diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/CREDITS linux-2.4.21/CREDITS
--- linux-2.4.20/CREDITS	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/CREDITS	2002-12-18 18:58:04.000000000 +0000
@@ -733,7 +733,7 @@
 D: Dell PowerEdge server, SCSI layer, misc drivers, and other patches
 S: Dell Computer Corporation
 S: One Dell Way
-S: Round Rock, TX  78681
+S: Round Rock, TX  78682
 S: USA
 
 N: Eddie C. Dost
@@ -1008,7 +1008,7 @@
 S: USA
 
 N: Jeff Garzik
-E: jgarzik@mandrakesoft.com
+E: jgarzik@pobox.com
 
 N: Jacques Gelinas
 E: jacques@solucorp.qc.ca
@@ -1065,6 +1065,11 @@
 D: Transformed old user space bdflush into 1st kernel thread - kflushd.
 D: Many other patches, documentation files, mini kernels, utilities, ...
 
+N: Masanori GOTO
+E: gotom@debian.or.jp
+D: Workbit NinjaSCSI-32Bi/UDE driver
+S: Japan
+
 N: John E. Gotts
 E: jgotts@linuxsavvy.com
 D: kernel hacker
@@ -1231,16 +1236,18 @@
 
 N: Christoph Hellwig
 E: hch@infradead.org
-D: misc driver & makefile hacking
+E: hch@sgi.com
+D: all kinds of driver, filesystem & core kernel hacking
 D: freevxfs driver
 D: sysvfs maintainer
-S: Triftstraße 26
-S: 38644 Goslar
+D: chief codingstyle nitpicker
+S: Auweg 38
+S: 85748 Garching
 S: Germany
 
 N: Richard Henderson
 E: rth@twiddle.net
-E: rth@cygnus.com
+E: rth@redhat.com
 D: Alpha hacker, kernel and userland
 S: 1668 California St.
 S: Mountain View, California 94041
@@ -3282,6 +3289,12 @@
 S: Socorro NM, 87801
 S: USA
 
+N: Hiroshi YOKOTA
+E: yokota@netlab.is.tsukuba.ac.jp
+D: Workbit NinjaSCSI-3/32Bi PCMCIA driver
+D: Workbit NinjaSCSI-32Bi/UDE driver
+S: Japan
+
 N: Eric Youngdale
 E: eric@andante.org
 W: http://www.andante.org
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/BK-usage/00-INDEX linux-2.4.21/Documentation/BK-usage/00-INDEX
--- linux-2.4.20/Documentation/BK-usage/00-INDEX	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/Documentation/BK-usage/00-INDEX	2002-12-18 18:58:07.000000000 +0000
@@ -0,0 +1,38 @@
+bk-kernel-howto.txt: Description of kernel workflow under BitKeeper
+
+bk-make-sum: Create summary of changesets in one repository and not
+another, typically in preparation to be sent to an upstream maintainer.
+Typical usage:
+	cd my-updated-repo
+	bk-make-sum ~/repo/original-repo
+	mv /tmp/linus.txt ../original-repo.txt
+
+bksend: Create readable text output containing summary of changes, GNU
+patch of the changes, and BK metadata of changes (as needed for proper
+importing into BitKeeper by an upstream maintainer).  This output is
+suitable for emailing BitKeeper changes.  The recipient of this output
+may pipe it directly to 'bk receive'.
+
+bz64wrap: helper script. Uncompressed input is piped to this script,
+which compresses its input, and then outputs the uu-/base64-encoded
+version of the compressed input.
+
+csets-to-patches: Produces a delta of two BK repositories, in the form
+of individual files, each containing a single cset as a GNU patch.
+Output is several files, each with the filename "/tmp/rev-$REV.patch"
+Typical usage:
+	cd my-updated-repo
+	bk changes -L ~/repo/original-repo 2>&1 | \
+		perl csets-to-patches
+
+cset-to-linus: Produces a delta of two BK repositories, in the form of
+changeset descriptions, with 'diffstat' output created for each
+individual changset.
+Typical usage:
+	cd my-updated-repo
+	bk changes -L ~/repo/original-repo 2>&1 | \
+		perl cset-to-linus > summary.txt
+
+unbz64wrap: Reverse an encoded, compressed data stream created by
+bz64wrap into an uncompressed, typically text/plain output.
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/BK-usage/bk-kernel-howto.txt linux-2.4.21/Documentation/BK-usage/bk-kernel-howto.txt
--- linux-2.4.20/Documentation/BK-usage/bk-kernel-howto.txt	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/Documentation/BK-usage/bk-kernel-howto.txt	2002-12-18 18:58:08.000000000 +0000
@@ -32,7 +32,7 @@
 
 Let's start with this progression:
 Each BitKeeper source tree on disk is a repository unto itself.
-Each repository has a parent.
+Each repository has a parent (except the root/original, of course).
 Each repository contains a set of a changesets ("csets").
 Each cset is one or more changed files, bundled together.
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/Configure.help linux-2.4.21/Documentation/Configure.help
--- linux-2.4.20/Documentation/Configure.help	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/Documentation/Configure.help	2002-12-18 18:58:11.000000000 +0000
@@ -246,14 +246,22 @@
 
   If unsure, say N.
 
-Multiquad support for NUMA systems
-CONFIG_MULTIQUAD
+Multiquad support for NUMAQ systems
+CONFIG_X86_NUMAQ
   This option is used for getting Linux to run on a (IBM/Sequent) NUMA 
   multiquad box. This changes the way that processors are bootstrapped,
   and uses Clustered Logical APIC addressing mode instead of Flat Logical.
   You will need a new lynxer.elf file to flash your firmware with - send
   email to Martin.Bligh@us.ibm.com
 
+Support for IBM Summit (EXA) systems
+CONFIG_X86_SUMMIT
+  This option is needed for IBM systems that use the Summit/EXA chipset.
+  (EXA: Extendable Xseries Architecture)In particular, it is needed for 
+  the x440 (even for the 4-CPU model).
+
+  If you don't have this computer, you may safely say N.
+
 IO-APIC support on uniprocessors
 CONFIG_X86_UP_IOAPIC
   An IO-APIC (I/O Advanced Programmable Interrupt Controller) is an
@@ -1114,10 +1122,10 @@
   This effect can be also invoked by calling "idex=ata66"
   If unsure, say N.
 
-CMD64X and CMD680 chipset support
+CMD64X/CMD680 chipset support
 CONFIG_BLK_DEV_CMD64X
   Say Y here if you have an IDE controller which uses any of these
-  chipsets: CMD643, CMD646, CMD648, CMD649 or CMD680.
+  chipsets: CMD643, CMD646 and CMD648.
 
 CY82C693 chipset support
 CONFIG_BLK_DEV_CY82C693
@@ -1276,6 +1284,11 @@
 
   Please read the comments at the top of <file:drivers/ide/sis5513.c>.
 
+Silicon Image chipset support
+CONFIG_BLK_DEV_SIIMAGE
+  This driver provides (U)DMA support for the SII3112 SATA controllers and
+  for the CMD/SI680 UDMA/DMA ATA controller.
+
 SLC90E66 chipset support
 CONFIG_BLK_DEV_SLC90E66
   This driver ensures (U)DMA support for Victroy66 SouthBridges for
@@ -3543,6 +3556,13 @@
   You should say Y here if you use XFree86 3.3.6 or 4.x and want to
   use GLX or DRI.  If unsure, say N.
 
+CONFIG_AGP_AMD_8151
+  This option gives you AGP support for the GLX component of
+  XFree86 on AMD K8 with an AGP 8151 chipset.
+
+  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
+  use GLX or DRI.  If unsure, say N.
+
 Generic SiS support
 CONFIG_AGP_SIS
   This option gives you AGP support for the GLX component of the "soon
@@ -4416,7 +4436,7 @@
 
   The driver is also available as a module ( = code which can be
   inserted and removed from the running kernel whenever you want). The
-  module will be called rivafb.o. If you want to compile it as a
+  module will be called tridentfb.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
 ATI Mach64 display support
@@ -7907,6 +7927,17 @@
 
   The common answer here is N, but answering Y is safe.
 
+Workbit NinjaSCSI-32Bi/UDE support
+CONFIG_SCSI_NSP32
+  This is support for the Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus
+  SCSI host adapter. Please read the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called nsp32.o.
+
 IBMMCA SCSI support
 CONFIG_SCSI_IBMMCA
   This is support for the IBM SCSI adapter found in many of the PS/2
@@ -10816,6 +10847,15 @@
   say M here and read <file:Documentation/modules.txt>.  This is
   recommended.  The module will be called yellowfin.o.
 
+Realtek 8169 Gigabit Ethernet support
+CONFIG_R8169
+  Say Y here if you have a Realtek 8169 PCI Gigabit Ethernet adapter.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  This is
+  recommended.  The module will be called r8169.o.
+
 General Instruments Surfboard 1000
 CONFIG_NET_SB1000
   This is a driver for the General Instrument (also known as
@@ -13764,6 +13804,21 @@
   The module will be called wacom.o.  If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
+Griffin Technology PowerMate support
+CONFIG_USB_POWERMATE
+  Say Y here if you want to use the Griffin Technology, Inc. USB
+  PowerMate device. This device is a stainless steel dial which 
+  can measure clockwise and anticlockwise rotation. The dial also
+  acts as a pushbutton. The base contains an LED which can be
+  instructed to pulse or to switch to a particular intensity.
+
+  You can download userspace tools from http://sowerbutts.com/powermate/
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called powermate.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
 Aiptek 6000U/8000U tablet support
 CONFIG_USB_AIPTEK
   Say Y here if you want to use the USB version of the Aiptek 6000U/8000U
@@ -14145,6 +14200,17 @@
   The module will be called pl2303.o.  If you want to compile it as
   a module, say M here and read <file:Documentation/modules.txt>.
 
+USB KOBIL chipcard reader
+CONFIG_USB_SERIAL_KOBIL_SCT
+  Say Y here if you want to use one of the following KOBIL USB chipcard 
+  readers: TWIN, KAAN Standard Plus, SecOVID Reader Plus, B1 PRO, KAAN PRO
+
+  Note that you need a current CT-API.
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called kobil_sct.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
 USB REINER SCT cyberJack pinpad/e-com chipcard reader
 CONFIG_USB_SERIAL_CYBERJACK
   Say Y here if you want to use a cyberJack pinpad/e-com USB chipcard
@@ -14649,6 +14715,28 @@
 
   If unsure, say N.
 
+Texas Instruments parallel link cable support
+CONFIG_TIPAR
+  If you own a Texas Instruments graphing calculator and use a
+  parallel link cable, then you might be interested in this driver.
+
+  If you enable this driver, you will be able to communicate with
+  your calculator through a set of device nodes under /dev. The
+  main advantage of this driver is that you don't have to be root
+  to use this precise link cable (depending on the permissions on
+  the device nodes, though).
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called tipar.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>
+
+  If you don't know what a parallel link cable is or what a Texas
+  Instruments graphing calculator is, then you probably don't need this
+  driver.
+
+  If unsure, say N.
+
 Tieman Voyager USB Braille display support
 CONFIG_USB_BRLVOYAGER
   Say Y here if you want to use the Voyager USB Braille display from
@@ -15188,6 +15276,35 @@
   debugging output from the driver. This is unlike previous versions
   of the driver, where enabling this option would turn on debugging
   output automatically.
+  
+  Example:
+  mount -t befs /dev/hda2 /mnt -o debug
+
+BeOS filesystem support (BeFS) (read only)
+CONFIG_BEFS_FS
+  The BeOS File System (BeFS) is the native file system of Be, Inc's
+  BeOS. Notable features include support for arbitrary attributes
+  on files and directories, and database-like indices on selected
+  attributes. (Also note that this driver doesn't make those features
+  available at this time). It is a 64 bit filesystem, so it supports
+  extremely large volumes and files.
+
+  If you use this filesystem, you should also say Y to at least one
+  of the NLS (native language support) options below.
+
+  If you don't know what this is about, say N.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called befs.o.
+
+Debug BeFS
+CONFIG_BEFS_DEBUG
+  If you say Y here, you can use the 'debug' mount option to enable
+  debugging output from the driver. This is unlike previous versions
+  of the driver, where enabling this option would turn on debugging
+  output automatically.
 
   Example:
   mount -t befs /dev/hda2 /mnt -o debug
@@ -19052,10 +19169,11 @@
   The module will be called cs461x.o.  If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-Aureal Vortex and Trident 4DWave gameports
+Aureal Vortex, Trident 4DWave, and ALi 5451 gameports
 CONFIG_INPUT_PCIGAME
   Say Y here if you have a Trident 4DWave DX/NX or Aureal Vortex 1/2
-  card. For more information on how to use the driver please read
+  card or an ALi 5451 chip on your motherboard. For more information
+  on how to use the driver please read
   <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
@@ -21278,6 +21396,8 @@
                HCI Device drivers (interface to the hardware)
                L2CAP Module (L2CAP protocol)
                SCO Module (SCO links)
+               RFCOMM Module (RFCOMM protocol)
+               BNEP Module (BNEP protocol)
 
   Say Y here to enable Linux Bluetooth support and to build BlueZ Core
   layer.
@@ -21306,6 +21426,19 @@
   Say Y here to compile SCO support into the kernel or say M to
   compile it as module (sco.o).
 
+RFCOMM protocol support
+CONFIG_BLUEZ_RFCOMM
+  RFCOMM provides connection oriented stream transport. RFCOMM
+  support is required for Dialup Networking, OBEX and other Bluetooth
+  applications.
+
+  Say Y here to compile RFCOMM support into the kernel or say M to
+  compile it as module (rfcomm.o).
+
+RFCOMM TTY emulation support
+CONFIG_BLUEZ_RFCOMM_TTY
+  This option enables TTY emulation support for RFCOMM channels.
+
 BNEP protocol support
 CONFIG_BLUEZ_BNEP
   BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet
@@ -21319,6 +21452,14 @@
   Say Y here to compile BNEP support into the kernel or say M to
   compile it as module (bnep.o).
 
+BNEP multicast filter support
+CONFIG_BLUEZ_BNEP_MC_FILTER
+  This option enables the multicast filter support for BNEP.
+
+BNEP protocol filter support
+CONFIG_BLUEZ_BNEP_PROTO_FILTER
+  This option enables the protocol filter support for BNEP.
+
 HCI UART driver
 CONFIG_BLUEZ_HCIUART
   Bluetooth HCI UART driver.
@@ -21333,11 +21474,26 @@
 HCI UART (H4) protocol support 
 CONFIG_BLUEZ_HCIUART_H4
   UART (H4) is serial protocol for communication between Bluetooth 
-  device and host. This protocol is required for most UART based 
-  Bluetooth device (including PCMCIA and CF). 
+  device and host. This protocol is required for most Bluetooth devices 
+  with UART interface, including PCMCIA and CF cards. 
 
   Say Y here to compile support for HCI UART (H4) protocol.
 
+HCI BCSP protocol support 
+CONFIG_BLUEZ_HCIUART_BCSP
+  BCSP (BlueCore Serial Protocol) is serial protocol for communication 
+  between Bluetooth device and host. This protocol is required for non
+  USB Bluetooth devices based on CSR BlueCore chip, including PCMCIA and 
+  CF cards.
+
+  Say Y here to compile support for HCI BCSP protocol.
+
+HCI BCSP transmit CRC with every BCSP packet
+CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+  If you say Y here, a 16-bit CRC checksum will be transmitted along with
+  every BCSP (BlueCore Serial Protocol) packet sent to the Bluetooth chip.
+  This increases reliability, but slightly reduces efficiency.
+
 HCI USB driver
 CONFIG_BLUEZ_HCIUSB
   Bluetooth HCI USB driver.
@@ -21399,6 +21555,20 @@
   Say Y here to compile support for HCI BlueCard devices into the
   kernel or say M to compile it as module (bluecard_cs.o).
 
+HCI UART (PC Card) device driver
+CONFIG_BLUEZ_HCIBTUART
+  Bluetooth HCI UART (PC Card) driver.
+  This driver provides support for Bluetooth PCMCIA devices with
+  an UART interface:
+     Xircom CreditCard Bluetooth Adapter
+     Xircom RealPort2 Bluetooth Adapter
+     Sphinx PICO Card
+     H-Soft blue+Card
+     Cyber-blue Compact Flash Card
+
+  Say Y here to compile support for HCI UART devices into the
+  kernel or say M to compile it as module (btuart_cs.o).
+
 # The following options are for Linux when running on the Hitachi
 # SuperH family of RISC microprocessors.
 
@@ -26181,7 +26351,7 @@
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
   say M here and read Documentation/modules.txt.  The module
-  will be called amdtp.o.
+  will be called cmp.o.
 
 OHCI-DV I/O support
 CONFIG_IEEE1394_DV1394
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/journal-api.tmpl linux-2.4.21/Documentation/DocBook/journal-api.tmpl
--- linux-2.4.20/Documentation/DocBook/journal-api.tmpl	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/Documentation/DocBook/journal-api.tmpl	2002-12-18 18:58:03.000000000 +0000
@@ -196,6 +196,8 @@
 Lock is also providing through journal_{un,}lock_updates(),
 ext3 uses this when it wants a window with a clean and stable fs for a moment.
 eg. 
+</para>
+
 <programlisting>
 
 	journal_lock_updates() //stop new stuff happening..
@@ -204,11 +206,12 @@
 	journal_unlock_updates() // carry on with filesystem use.
 </programlisting>
 
+<para>
 The opportunities for abuse and DOS attacks with this should be obvious,
 if you allow unprivileged userspace to trigger codepaths containing these
 calls.
 
-<para>
+</para>
 </sect1>
 <sect1>
 <title>Summary</title>
@@ -216,9 +219,13 @@
 Using the journal is a matter of wrapping the different context changes,
 being each mount, each modification (transaction) and each changed buffer
 to tell the journalling layer about them.
+</para>
 
+<para>
 Here is a some pseudo code to give you an idea of how it works, as
 an example.
+</para>
+
 <programlisting>
   journal_t* my_jnrl = journal_create();
   journal_init_{dev,inode}(jnrl,...)
@@ -244,6 +251,7 @@
    }
    journal_destroy(my_jrnl);
 </programlisting>
+</sect1>
 
 </chapter>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/kernel-hacking.tmpl linux-2.4.21/Documentation/DocBook/kernel-hacking.tmpl
--- linux-2.4.20/Documentation/DocBook/kernel-hacking.tmpl	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/Documentation/DocBook/kernel-hacking.tmpl	2002-12-18 18:58:09.000000000 +0000
@@ -1139,11 +1139,6 @@
     </listitem>
     <listitem>
      <para>
-      Labeled elements
-     </para>
-    </listitem>
-    <listitem>
-     <para>
       typeof
      </para>
     </listitem>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/kernel-locking.tmpl linux-2.4.21/Documentation/DocBook/kernel-locking.tmpl
--- linux-2.4.20/Documentation/DocBook/kernel-locking.tmpl	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/Documentation/DocBook/kernel-locking.tmpl	2002-12-18 18:58:06.000000000 +0000
@@ -1055,10 +1055,8 @@
       Another common problem is deleting timers which restart
       themselves (by calling <function>add_timer()</function> at the end 
       of their timer function).  Because this is a fairly common case 
-      which is prone to races, you can put a call to
-      <function>timer_exit()</function> at the very end of your timer function,
-      and user <function>del_timer_sync()</function> 
-      (<filename class=headerfile>include/linux/timer.h</filename>)
+      which is prone to races, you should use <function>del_timer_sync()</function> 
+      (<filename class=headerfile>include/linux/timer.h</filename>) 
       to handle this case.  It returns the number of times the timer 
       had to be deleted before we finally stopped it from adding itself back 
       in.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/mousedrivers.tmpl linux-2.4.21/Documentation/DocBook/mousedrivers.tmpl
--- linux-2.4.20/Documentation/DocBook/mousedrivers.tmpl	2001-09-30 19:26:05.000000000 +0000
+++ linux-2.4.21/Documentation/DocBook/mousedrivers.tmpl	2002-12-18 18:58:04.000000000 +0000
@@ -153,11 +153,17 @@
 __init ourmouse_init(void)
 {
 
-        if(check_region(OURMOUSE_BASE, 3))
+        if (request_region(OURMOUSE_BASE, 3, "ourmouse") < 0) {
+		printk(KERN_ERR "ourmouse: request_region failed.\n");
                 return -ENODEV;
-        request_region(OURMOUSE_BASE, 3, "ourmouse");
+	}
+
+        if (misc_register(&amp;our_mouse) < 0) {
+		printk(KERN_ERR "ourmouse: cannot register misc device.\n");
+		release_region(OURMOUSE_BASE, 3);
+		return -EBUSY;
+	}
 
-        misc_register(&amp;our_mouse);
         return 0;
 }
   </programlisting>
@@ -177,18 +183,20 @@
     so it is a good idea to obtain a current copy of this file first.
   </para>
   <para>
-    Our code then is fairly simple. We check nobody else has taken our 
-    address space. Having done so we reserve it to ensure nobody stamps 
-    on our device while probing for other ISA bus devices. Such a probe 
-    might confuse our device.
+    Our code then is fairly simple. We reserve our I/O address space with
+    request_region, checking to make sure that it succeeded (i.e. the
+    space wasn't reserved by anyone else). 
   </para>
   <para>
-    Then we tell the misc driver that we wish to own a minor number. We also
+    Then we ask the misc driver to allocate our minor device number. We also
     hand it our name (which is used in 
     <filename class="directory">/proc/misc</filename>) and a set of file 
     operations that are to be used. The file operations work exactly like the 
     file operations you would register for a normal character device. The misc 
     device itself is simply acting as a redirector for requests.
+    Since misc_register can fail, it is important to check for failure
+    and act accordingly (which in the case of a mouse driver is to abort,
+    since you can't use the mouse without a working device node).
   </para>
   <para>
     Next, in order to be able to use and test our code we need to add some 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/procfs-guide.tmpl linux-2.4.21/Documentation/DocBook/procfs-guide.tmpl
--- linux-2.4.20/Documentation/DocBook/procfs-guide.tmpl	2001-09-08 19:20:25.000000000 +0000
+++ linux-2.4.21/Documentation/DocBook/procfs-guide.tmpl	2002-12-18 18:58:10.000000000 +0000
@@ -99,7 +99,7 @@
 
     <para>
       I'd like to thank Jeff Garzik
-      <email>jgarzik@mandrakesoft.com</email> and Alexander Viro
+      <email>jgarzik@pobox.com</email> and Alexander Viro
       <email>viro@math.psu.edu</email> for their input, Tim Waugh
       <email>twaugh@redhat.com</email> for his <ulink
       url="http://people.redhat.com/twaugh/docbook/selfdocbook/">Selfdocbook</ulink>,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/tulip-user.tmpl linux-2.4.21/Documentation/DocBook/tulip-user.tmpl
--- linux-2.4.20/Documentation/DocBook/tulip-user.tmpl	2001-10-05 19:06:51.000000000 +0000
+++ linux-2.4.21/Documentation/DocBook/tulip-user.tmpl	2002-12-18 18:58:05.000000000 +0000
@@ -10,7 +10,7 @@
     <surname>Garzik</surname>
     <affiliation>
      <address>
-      <email>jgarzik@mandrakesoft.com</email>
+      <email>jgarzik@pobox.com</email>
      </address>
     </affiliation>
    </author>
@@ -57,7 +57,7 @@
     <title>Introduction</title>
 <para>
 The Tulip Ethernet Card Driver
-is maintained by Jeff Garzik (<email>jgarzik@mandrakesoft.com</email>).
+is maintained by Jeff Garzik (<email>jgarzik@pobox.com</email>).
 </para>
 
 <para>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/cciss.txt linux-2.4.21/Documentation/cciss.txt
--- linux-2.4.20/Documentation/cciss.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/Documentation/cciss.txt	2002-12-18 18:58:03.000000000 +0000
@@ -9,6 +9,9 @@
 	* SA 5i 
 	* SA 532
 	* SA 5312
+	* SA 641
+	* SA 642
+	* SA 6400
 
 If nodes are not already created in the /dev/cciss directory
 
@@ -86,7 +89,7 @@
 
 Hot plugging of SCSI tape drives is supported, with some caveats.
 The cciss driver must be informed that changes to the SCSI bus
-have been made, in addition to and prior to informing the the SCSI 
+have been made, in addition to and prior to informing the SCSI 
 mid layer.  This may be done via the /proc filesystem.  For example:
 
 	echo "rescan" > /proc/scsi/cciss0/1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/fb/clgenfb.txt linux-2.4.21/Documentation/fb/clgenfb.txt
--- linux-2.4.20/Documentation/fb/clgenfb.txt	2001-11-19 23:19:42.000000000 +0000
+++ linux-2.4.21/Documentation/fb/clgenfb.txt	2002-12-18 18:58:02.000000000 +0000
@@ -1,6 +1,6 @@
 
 		Framebuffer driver for Cirrus Logic chipsets
-		Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
+		Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
 
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/filesystems/Locking linux-2.4.21/Documentation/filesystems/Locking
--- linux-2.4.20/Documentation/filesystems/Locking	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/Documentation/filesystems/Locking	2002-12-18 18:58:06.000000000 +0000
@@ -93,6 +93,7 @@
 	void (*delete_inode) (struct inode *);
 	void (*put_super) (struct super_block *);
 	void (*write_super) (struct super_block *);
+	int (*sync_fs) (struct super_block *);
 	int (*statfs) (struct super_block *, struct statfs *);
 	int (*remount_fs) (struct super_block *, int *, char *);
 	void (*clear_inode) (struct inode *);
@@ -108,6 +109,7 @@
 clear_inode:	no	
 put_super:	yes	yes	maybe		(see below)
 write_super:	yes	yes	maybe		(see below)
+write_super:	yes	no	maybe		(see below)
 statfs:		yes	no	no
 remount_fs:	yes	yes	maybe		(see below)
 umount_begin:	yes	no	maybe		(see below)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/i810_rng.txt linux-2.4.21/Documentation/i810_rng.txt
--- linux-2.4.20/Documentation/i810_rng.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/Documentation/i810_rng.txt	2002-12-18 18:58:10.000000000 +0000
@@ -1,5 +1,5 @@
 	Hardware driver for Intel i810 Random Number Generator (RNG)
-	Copyright 2000,2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+	Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
 
 Introduction:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/8139too.txt linux-2.4.21/Documentation/networking/8139too.txt
--- linux-2.4.20/Documentation/networking/8139too.txt	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/Documentation/networking/8139too.txt	2002-12-18 18:58:02.000000000 +0000
@@ -2,7 +2,7 @@
 		"8139too" Fast Ethernet driver for Linux
 	 RTL-8139, -8129, and -8130 10/100 Fast Ethernet adapters
 
-	Copyright 2000,2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+	Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
 
                 http://sourceforge.net/projects/gkernel/
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/bonding.txt linux-2.4.21/Documentation/networking/bonding.txt
--- linux-2.4.20/Documentation/networking/bonding.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/Documentation/networking/bonding.txt	2002-12-18 18:58:05.000000000 +0000
@@ -266,7 +266,7 @@
 	If not explicitly configured with ifconfig, the MAC address of the
 	bonding device is taken from its first slave device. This MAC address
 	is then passed to all following slaves and remains persistent (even if
-	the the first slave is removed) until the bonding device is brought
+	the first slave is removed) until the bonding device is brought
 	down or reconfigured.
 	
 	If you wish to change the MAC address, you can set it with ifconfig:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/netdevices.txt linux-2.4.21/Documentation/networking/netdevices.txt
--- linux-2.4.20/Documentation/networking/netdevices.txt	2000-11-09 03:09:49.000000000 +0000
+++ linux-2.4.21/Documentation/networking/netdevices.txt	2002-12-18 18:58:04.000000000 +0000
@@ -12,31 +12,36 @@
 struct net_device synchronization rules
 =======================================
 dev->open:
-	Locking: Inside rtnl_lock() semaphore.
-	Sleeping: OK
+	Synchronization: rtnl_lock() semaphore.
+	Context: process
 
 dev->stop:
-	Locking: Inside rtnl_lock() semaphore.
-	Sleeping: OK
+	Synchronization: rtnl_lock() semaphore.
+	Context: process
+	Notes: netif_running() is guaranteed false when this is called
 
 dev->do_ioctl:
-	Locking: Inside rtnl_lock() semaphore.
-	Sleeping: OK
+	Synchronization: rtnl_lock() semaphore.
+	Context: process
 
 dev->get_stats:
-	Locking: Inside dev_base_lock spinlock.
-	Sleeping: NO
+	Synchronization: dev_base_lock rwlock.
+	Context: nominally process, but don't sleep inside an rwlock
 
 dev->hard_start_xmit:
-	Locking: Inside dev->xmit_lock spinlock.
-	Sleeping: NO
+	Synchronization: dev->xmit_lock spinlock.
+	Context: BHs disabled
 
 dev->tx_timeout:
-	Locking: Inside dev->xmit_lock spinlock.
-	Sleeping: NO
+	Synchronization: dev->xmit_lock spinlock.
+	Context: BHs disabled
 
 dev->set_multicast_list:
-	Locking: Inside dev->xmit_lock spinlock.
-	Sleeping: NO
+	Synchronization: dev->xmit_lock spinlock.
+	Context: BHs disabled
 
+dev->poll:
+	Synchronization: __LINK_STATE_RX_SCHED bit in dev->state.  See
+		dev_close code and comments in net/core/dev.c for more info.
+	Context: softirq
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/pktgen.txt linux-2.4.21/Documentation/networking/pktgen.txt
--- linux-2.4.20/Documentation/networking/pktgen.txt	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/Documentation/networking/pktgen.txt	2002-12-18 18:58:11.000000000 +0000
@@ -6,7 +6,7 @@
 3. Edit script to set preferred device and destination IP address.
 3a.  Create more scripts for different interfaces.  Up to thirty-two
      pktgen processes can be configured and run at once by using the
-     32 /proc/net/pg* files.
+     32 /proc/net/pktgen/pg* files.
 4. Run in shell: ". ipg"
 5. After this two commands are defined:
    A. "pg" to start generator and to get results.
@@ -52,7 +52,7 @@
 
 modprobe pktgen
 
-PGDEV=/proc/net/pg/pg0
+PGDEV=/proc/net/pktgen/pg0
 
 function pgset() {
     local result
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/sonypi.txt linux-2.4.21/Documentation/sonypi.txt
--- linux-2.4.20/Documentation/sonypi.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/Documentation/sonypi.txt	2002-12-18 18:58:01.000000000 +0000
@@ -1,6 +1,7 @@
 Sony Programmable I/O Control Device Driver Readme
 --------------------------------------------------
-	Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+	Copyright (C) 2001-2002 Stelian Pop <stelian@popies.net>
+	Copyright (C) 2001-2002 Alcôve <www.alcove.com>
 	Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
 	Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
 	Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
@@ -15,14 +16,14 @@
 	- capture button events (only on Vaio Picturebook series)
 	- Fn keys
 	- bluetooth button (only on C1VR model)
-	- back button (PCG-GR7/K model)
-	- lid open/close events (Z600NE model)
+	- programmable keys, back, help, zoom, thumbphrase buttons, etc.
+	  (when available)
 
 Those events (see linux/sonypi.h) can be polled using the character device node
 /dev/sonypi (major 10, minor auto allocated or specified as a option).
 
 A simple daemon which translates the jogdial movements into mouse wheel events
-can be downloaded at: <http://www.alcove-labs.org/en/software/sonypi/>
+can be downloaded at: <http://popies.net/sonypi/>
 
 This driver supports also some ioctl commands for setting the LCD screen
 brightness and querying the batteries charge information (some more 
@@ -43,7 +44,7 @@
 to /etc/modules.conf file, when the driver is compiled as a module or by
 adding the following to the kernel command line (in your bootloader):
 
-	sonypi=minor[,verbose[,fnkeyinit[,camera[,compat[,nojogdial]]]]]
+	sonypi=minor[,verbose[,fnkeyinit[,camera[,compat[,mask]]]]]
 
 where:
 
@@ -64,15 +65,37 @@
 			with it and it shouldn't be required anyway if 
 			ACPI is already enabled).
 
-	verbose:	print unknown events from the sonypi device
+	verbose:	set to 1 to print unknown events received from the 
+			sonypi device.
+			set to 2 to print all events received from the 
+			sonypi device.
 
 	compat:		uses some compatibility code for enabling the sonypi
 			events. If the driver worked for you in the past
 			(prior to version 1.5) and does not work anymore,
 			add this option and report to the author.
 
-	nojogdial:	gives more accurate PKEY events on those Vaio models
-			which don't have a jogdial (like the FX series).
+	mask:		event mask telling the driver what events will be
+			reported to the user. This parameter is required for some 
+			Vaio models where the hardware reuses values used in 
+			other Vaio models (like the FX series who does not
+			have a jogdial but reuses the jogdial events for
+			programmable keys events). The default event mask is
+			set to 0xffffffff, meaning that all possible events will be
+			tried. You can use the following bits to construct
+			your own event mask (from drivers/char/sonypi.h):
+				SONYPI_JOGGER_MASK 		0x0001
+				SONYPI_CAPTURE_MASK 		0x0002
+				SONYPI_FNKEY_MASK 		0x0004
+				SONYPI_BLUETOOTH_MASK 		0x0008
+				SONYPI_PKEY_MASK 		0x0010
+				SONYPI_BACK_MASK 		0x0020
+				SONYPI_HELP_MASK 		0x0040
+				SONYPI_LID_MASK 		0x0080
+				SONYPI_ZOOM_MASK 		0x0100
+				SONYPI_THUMBPHRASE_MASK 	0x0200
+				SONYPI_MEYE_MASK		0x0400
+				SONYPI_MEMORYSTICK_MASK		0x0800
 
 Module use:
 -----------
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/tipar.txt linux-2.4.21/Documentation/tipar.txt
--- linux-2.4.20/Documentation/tipar.txt	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/Documentation/tipar.txt	2002-12-18 18:58:05.000000000 +0000
@@ -0,0 +1,93 @@
+
+		Parallel link cable for Texas Instruments handhelds
+		===================================================
+
+
+Author: Romain Lievin
+Homepage: http://lpg.ticalc.org/prj_tidev
+
+
+INTRODUCTION:
+
+This is a driver for the very common home-made parallel link cable, a cable 
+designed for connecting TI8x/9x graphing calculators (handhelds) to a computer
+or workstation (Alpha, Sparc). Given that driver is built on parport, the 
+parallel port abstraction layer, this driver is independant of the platform.
+
+It can also be used with another device plugged on the same port (such as a
+ZIP drive). I have a 100MB ZIP and both of them work fine !
+
+If you need more information, please visit the 'TI drivers' homepage at the URL
+above.
+
+WHAT YOU NEED:
+
+A TI calculator of course and a program capable to communicate with your 
+calculator.
+TiLP will work for sure (since I am his developer !). yal92 may be able to use
+it by changing tidev for tipar (may require some hacking...).
+
+HOW TO USE IT:
+
+You must have first compiled parport support (CONFIG_PARPORT_DEV): either 
+compiled in your kernel, either as a module. 
+This driver supports the new device hierarchy (devfs).
+
+Next, (as root) from your appropriate modules directory (lib/modules/2.5.XX):
+
+       modprobe parport
+       insmod tipar.o
+
+If it is not already there (it usually is), create the device:
+
+       mknod /dev/tipar0 c 115 0
+       mknod /dev/tipar1 c 115 1
+       mknod /dev/tipar2 c 115 2
+
+You will have to set permissions on this device to allow you to read/write
+from it:
+
+       chmod 666 /dev/tipar?
+       
+Now you are ready to run a linking program such as TiLP. Be sure to configure 
+it properly (RTFM).
+       
+MODULE PARAMETERS:
+
+  You can set these with:  insmod tipar NAME=VALUE
+  There is currently no way to set these on a per-cable basis.
+
+  NAME: timeout
+  TYPE: integer
+  DEFAULT: 15
+  DESC: Timeout value in tenth of seconds. If no data is available once this 
+	time has expired then the driver will return with a timeout error.
+
+  NAME: delay
+  TYPE: integer
+  DEFAULT: 10
+  DESC: Inter-bit delay in micro-seconds. An lower value gives an higher data 
+	rate but makes transmission less reliable.
+
+These parameters can be changed at run time by any program via ioctl(2) calls 
+as listed in ./include/linux/ticable.h
+Rather than write 50 pages describing the ioctl() and so on, it is
+perhaps more useful you look at ticables library (dev_link.c) that demonstrates
+how to use them, and demonstrates the features of the driver. This is
+probably a lot more useful to people interested in writing applications
+that will be using this driver.
+
+QUIRKS/BUGS:
+
+None.
+
+HOW TO CONTACT US:
+
+You can email me at roms@lpg.ticalc.org. Please prefix the subject line
+with "TIPAR: " so that I am certain to notice your message.
+You can also mail JB at jb@jblache.org. He packaged these drivers for Debian.
+
+CREDITS:
+
+The code is based on tidev.c & parport.c.
+The driver has been developed independantly of Texas Instruments.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/usb/usb-serial.txt linux-2.4.21/Documentation/usb/usb-serial.txt
--- linux-2.4.20/Documentation/usb/usb-serial.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/Documentation/usb/usb-serial.txt	2002-12-18 18:58:02.000000000 +0000
@@ -98,10 +98,11 @@
 Compaq iPAQ, HP Jornada and Casio EM500 driver
 
   This driver can be used to connect to Compaq iPAQ, HP Jornada and Casio EM500
-  PDAs running Windows CE 3.0 or PocketPC 2002 using a USB cable/cradle. It
-  has been tested only on the Compaq H3135, but is rumoured to work on
-  with the H3600 and later models as well as the Jornada 548 and 568.
-  With minor modifications, it may work for other CE based handhelds too.
+  PDAs running Windows CE 3.0 or PocketPC 2002 using a USB cable/cradle.
+  It's very likely that every device supported by ActiveSync USB works with this
+  driver. The driver supports the Compaq iPAQ, Jornada 548/568 and the Casio
+  EM500 out of the box. For others, please use module parameters to specify
+  the product and vendor id. e.g. modprobe ipaq vendor=0x3f0 product=0x1125
 
   The driver presents a serial interface (usually on /dev/ttyUSB0) over
   which one may run ppp and establish a TCP/IP link to the iPAQ. Once this
@@ -109,36 +110,12 @@
   significant advantage of using USB is speed - you can get 73 to 113
   kbytes/sec for download/upload to the iPAQ.
 
-  The driver works intermittently with the usb-uhci driver but quite
-  reliably with the uhci driver. However, performance is much better
-  with usb-uhci. It does not seem to work with ohci at all.
-
-  You must setup hotplug to invoke pppd as soon as the iPAQ is connected.
-  A ppp script like the one below should be kept in the file
-  /etc/hotplug/usb/ipaq Remember to chmod +x. Make sure there are no
-  options in /etc/ppp/options or ~/.ppprc which conflict with the ones
-  given below.
-
-	#!/bin/bash
-
-	MYIP=linux.box.ip
-	REMOTEIP=ipaq.ip
-	MYDNS=my.dns.server
-	killall -9 pppd
-	/usr/sbin/pppd /dev/ttyUSB0 \
-	connect "/usr/sbin/chat -v TIMEOUT 60 CLIENT 'CLIENTSERVER\c'" \
-	nocrtscts local debug passive $MYIP:$REMOTEIP ms-dns $MYDNS noauth \
-	proxyarp
-
-  You must also download and install asyncd from http://synce.sourceforge.net
-  This is required to emulate keep-alive packets which are exchanged by
-  ActiveSync and the iPAQ.
-
-  On connecting the cable, you should see the usual "Device Connected",
-  "User Authenticated" messages flash by on your iPAQ. Once connected,
-  you can use Win CE programs like ftpView, Pocket Outlook from the iPAQ
-  and xcerdisp, synce utilities from the Linux side. Remember to enable IP
-  forwarding. 
+  This driver is only one of a set of components required to utilize
+  the USB connection. Please visit http://synce.sourceforge.net which
+  contains the necessary packages and a simple step-by-step howto.
+
+  Once connected, you can use Win CE programs like ftpView, Pocket Outlook
+  from the iPAQ and xcerdisp, synce utilities from the Linux side.
 
   To use Pocket IE, follow the instructions given at
   http://www.tekguru.co.uk/EM500/usbtonet.htm to achieve the same thing
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/video4linux/meye.txt linux-2.4.21/Documentation/video4linux/meye.txt
--- linux-2.4.20/Documentation/video4linux/meye.txt	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/Documentation/video4linux/meye.txt	2002-12-18 18:58:04.000000000 +0000
@@ -1,6 +1,7 @@
 Vaio Picturebook Motion Eye Camera Driver Readme
 ------------------------------------------------
-	Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+	Copyright (C) 2001-2002 Stelian Pop <stelian@popies.net>
+	Copyright (C) 2001-2002 Alcôve <www.alcove.com>
 	Copyright (C) 2000 Andrew Tridgell <tridge@samba.org>
 
 This driver enable the use of video4linux compatible applications with the
@@ -52,7 +53,7 @@
 				or
 			xawtv -c /dev/video0 -geometry 320x240
 
-	motioneye (<http://www.alcove-labs.org/en/software/meye/>)
+	motioneye (<http://popies.net/meye/>)
 		for getting ppm or jpg snapshots, mjpeg video
 
 Private API:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/watchdog-api.txt linux-2.4.21/Documentation/watchdog-api.txt
--- linux-2.4.20/Documentation/watchdog-api.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/Documentation/watchdog-api.txt	2002-12-18 18:58:09.000000000 +0000
@@ -278,7 +278,7 @@
 	when the timeout runs out which can be 0 = RESET (default), 
 	1 = SMI, 2 = NMI, 3 = SCI.
 
-	Supports CONFIG_WATCHDOG_NOWAYOUT and the the magic character
+	Supports CONFIG_WATCHDOG_NOWAYOUT and the magic character
 	'V' close handling.
 
 	GETSUPPORT returns WDIOF_KEEPALIVEPING, and the GETSTATUS call
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/MAINTAINERS linux-2.4.21/MAINTAINERS
--- linux-2.4.20/MAINTAINERS	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/MAINTAINERS	2002-12-18 18:58:10.000000000 +0000
@@ -104,12 +104,12 @@
 
 8139CP 10/100 FAST ETHERNET DRIVER
 P:	Jeff Garzik
-M:	jgarzik@mandrakesoft.com
+M:	jgarzik@pobox.com
 S:	Maintained
 
 8139TOO 10/100 FAST ETHERNET DRIVER
 P:	Jeff Garzik
-M:	jgarzik@mandrakesoft.com
+M:	jgarzik@pobox.com
 W:	http://sourceforge.net/projects/gkernel/
 S:	Maintained
 
@@ -154,6 +154,14 @@
 W:	http://www.ibm.com/linux/ltc/
 S:	Supported
 
+AACRAID SCSI RAID DRIVER
+P:	Adaptec OEM Raid Solutions
+M:	linux-aacraid-devel@dell.com
+L:	linux-aacraid-devel@dell.com
+L:	linux-aacraid-announce@dell.com
+W:	http://domsch.com/linux
+S:	Supported
+
 ACPI
 P:	Andy Grover
 M:	andrew.grover@intel.com
@@ -245,7 +253,7 @@
 BEFS FILE SYSTEM
 P:	Will Dyson
 M:	will@cs.earlham.edu
-W:	http://cs.earlham.edu/~will/software/linux/kernel/BeFS.html
+W:	http://befs-driver.sourceforge.net/
 S:	Maintained
 
 BERKSHIRE PRODUCTS PC WATCHDOG DRIVER
@@ -286,16 +294,9 @@
 W:	http://bytesex.org/bttv/
 S:	Maintained
 
-BUSLOGIC SCSI DRIVER
-P:	Leonard N. Zubkoff
-M:	Leonard N. Zubkoff <lnz@dandelion.com>
-L:	linux-scsi@vger.kernel.org
-W:	http://www.dandelion.com/Linux/
-S:	Maintained
-
 CIRRUS LOGIC GENERIC FBDEV DRIVER
 P:	Jeff Garzik
-M:	jgarzik@mandrakesoft.com
+M:	jgarzik@pobox.com
 L:	linux-fbdev-devel@lists.sourceforge.net
 S:	Odd Fixes
 
@@ -792,7 +793,7 @@
 
 INTEL I8XX RANDOM NUMBER GENERATOR SUPPORT
 P:	Jeff Garzik
-M:	jgarzik@mandrakesoft.com
+M:	jgarzik@pobox.com
 W:	http://sourceforge.net/projects/gkernel/
 S:	Maintained
 
@@ -1041,6 +1042,12 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+MOTION EYE VAIO PICTUREBOOK CAMERA DRIVER
+P:	Stelian Pop
+M:	stelian@popies.net
+W:	http://popies.net/meye/
+S:	Maintained
+
 MOUSE AND MISC DEVICES [GENERAL]
 P:	Alessandro Rubini
 M:	rubini@ipvvis.unipv.it
@@ -1106,7 +1113,7 @@
 P:	Andrew Morton
 M:	akpm@zip.com.au
 P:	Jeff Garzik
-M:	jgarzik@mandrakesoft.com
+M:	jgarzik@pobox.com
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
@@ -1145,6 +1152,14 @@
 W:	http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
 S:	Maintained
 
+NINJA SCSI-32Bi/UDE PCI/CARDBUS SCSI HOST ADAPTER DRIVER
+P:	GOTO Masanori
+M:	gotom@debian.or.jp
+P:	YOKOTA Hiroshi
+M:	yokota@netlab.is.tsukuba.ac.jp
+W:	http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
+S:	Maintained
+
 NON-IDE/NON-SCSI CDROM DRIVERS [GENERAL] (come on, crew - mark your responsibility)
 P:	Eberhard Moenkeberg
 M:	emoenke@gwdg.de
@@ -1277,6 +1292,13 @@
 W:	http://www.realitydiluted.com/projects/nino
 S:	Maintained
 
+PHILIPS NINO PALM PC
+P:	Steven Hill
+M:	sjhill@realitydiluted.com
+L:	linux-mips@oss.sgi.com
+W:	http://www.realitydiluted.com/projects/nino
+S:	Maintained
+
 PNP SUPPORT
 P:	Tom Lees
 M:	tom@lpsg.demon.co.uk
@@ -1316,17 +1338,6 @@
 W:	http://www.pnd-pc.demon.co.uk/promise/
 S:	Maintained
 
-PROMISE PDC202XX IDE CONTROLLER DRIVER
-P:	Hank Yang
-M:	support@promise.com.tw [TAIWAN]
-P:	Jordan Rhody
-M:	support@promise.com [U.S.A]
-P:	Jack Hu
-M:	support-china@promise.com [CHINA]
-W:	http://www.promise.com/support/linux_eng.asp
-W:	http://www.promise.com.tw/support/linux_eng.asp
-S:	Maintained
-
 QNX4 FILESYSTEM
 P:	Anders Larsen
 M:	al@alarsen.net
@@ -1439,6 +1450,12 @@
 L:	linux-scsi@vger.kernel.org
 S:	Maintained
 
+SCx200 CPU SUPPORT
+P:	Christer Weinigel
+M:	christer@weinigel.se
+W:	http://www.weinigel.se
+S:	Supported
+
 SGI VISUAL WORKSTATION 320 AND 540
 P:	Bent Hagemark
 M:	bh@sgi.com
@@ -1487,12 +1504,18 @@
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
+SONY VAIO CONTROL DEVICE DRIVER
+P:	Stelian Pop
+M:	stelian@popies.net
+W:	http://popies.net/sonypi/
+S:	Maintained
+
 SOUND
 P:	Alan Cox
 M:	alan@redhat.com
 S:	Maintained for 2.2 only
 
-SPARC:
+UltraSPARC (sparc64):
 P:	David S. Miller
 M:	davem@redhat.com
 P:	Eddie C. Dost
@@ -1505,6 +1528,10 @@
 L:	ultralinux@vger.kernel.org
 S:	Maintained
 
+SPARC (sparc32):
+L:	sparclinux@vger.kernel.org
+S:	Unmaintained - please send patches to mailing list
+
 SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER
 P:	Roger Wolff
 M:	R.E.Wolff@BitWizard.nl
@@ -1580,6 +1607,11 @@
 M:      jb@technologeek.org
 S:      Maintained
 
+TI PARALLEL LINK CABLE DRIVER
+P:     Romain Lievin
+M:     roms@lpg.ticalc.org
+S:     Maintained
+
 TIEMAN VOYAGER USB BRAILLE DISPLAY DRIVER
 P:	Stephane Dalton
 M:	sdalton@videotron.ca
@@ -1631,7 +1663,7 @@
 
 TULIP NETWORK DRIVER
 P:	Jeff Garzik
-M:	jgarzik@mandrakesoft.com
+M:	jgarzik@pobox.com
 L:	tulip-users@lists.sourceforge.net
 W:	http://sourceforge.net/projects/tulip/
 S:	Maintained
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Makefile linux-2.4.21/Makefile
--- linux-2.4.20/Makefile	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/Makefile	2002-12-18 18:58:03.000000000 +0000
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
-SUBLEVEL = 20
-EXTRAVERSION =
+SUBLEVEL = 21
+EXTRAVERSION = -pre2
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/core_cia.c linux-2.4.21/arch/alpha/kernel/core_cia.c
--- linux-2.4.20/arch/alpha/kernel/core_cia.c	2001-10-21 17:30:58.000000000 +0000
+++ linux-2.4.21/arch/alpha/kernel/core_cia.c	2002-12-18 18:58:02.000000000 +0000
@@ -370,7 +370,7 @@
 }
 
 static inline void
-cia_prepare_tbia_workaround(void)
+cia_prepare_tbia_workaround(int window)
 {
 	unsigned long *ppte, pte;
 	long i;
@@ -382,10 +382,10 @@
 	for (i = 0; i < CIA_BROKEN_TBIA_SIZE / sizeof(unsigned long); ++i)
 		ppte[i] = pte;
 
-	*(vip)CIA_IOC_PCI_W1_BASE = CIA_BROKEN_TBIA_BASE | 3;
-	*(vip)CIA_IOC_PCI_W1_MASK = (CIA_BROKEN_TBIA_SIZE*1024 - 1)
-				    & 0xfff00000;
-	*(vip)CIA_IOC_PCI_T1_BASE = virt_to_phys(ppte) >> 2;
+	*(vip)CIA_IOC_PCI_Wn_BASE(window) = CIA_BROKEN_TBIA_BASE | 3;
+	*(vip)CIA_IOC_PCI_Wn_MASK(window)
+	  = (CIA_BROKEN_TBIA_SIZE*1024 - 1) & 0xfff00000;
+	*(vip)CIA_IOC_PCI_Tn_BASE(window) = virt_to_phys(ppte) >> 2;
 }
 
 static void __init
@@ -605,8 +605,7 @@
 do_init_arch(int is_pyxis)
 {
 	struct pci_controller *hose;
-	int temp;
-	int cia_rev;
+	int temp, cia_rev, tbia_window;
 
 	cia_rev = *(vip)CIA_IOC_CIA_REV & CIA_REV_MASK;
 	printk("pci: cia revision %d%s\n",
@@ -715,8 +714,20 @@
 	   are compared against W_DAC.  We can, however, directly map 4GB,
 	   which is better than before.  However, due to assumptions made
 	   elsewhere, we should not claim that we support DAC unless that
-	   4GB covers all of physical memory.  */
-	if (is_pyxis || max_low_pfn > (0x100000000 >> PAGE_SHIFT)) {
+	   4GB covers all of physical memory.
+
+	   On CIA rev 1, apparently W1 and W2 can't be used for SG.
+	   At least, there are reports that it doesn't work for Alcor.
+	   In that case, we have no choice but to use W3 for the TBIA
+	   workaround, which means we can't use DAC at all.  */
+
+	tbia_window = 1;
+	if (is_pyxis) {
+		*(vip)CIA_IOC_PCI_W3_BASE = 0;
+	} else if (cia_rev == 1) {
+		*(vip)CIA_IOC_PCI_W1_BASE = 0;
+		tbia_window = 3;
+	} else if (max_low_pfn > (0x100000000 >> PAGE_SHIFT)) {
 		*(vip)CIA_IOC_PCI_W3_BASE = 0;
 	} else {
 		*(vip)CIA_IOC_PCI_W3_BASE = 0x00000000 | 1 | 8;
@@ -728,7 +739,7 @@
 	}
 
 	/* Prepare workaround for apparently broken tbia. */
-	cia_prepare_tbia_workaround();
+	cia_prepare_tbia_workaround(tbia_window);
 }
 
 void __init
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/core_t2.c linux-2.4.21/arch/alpha/kernel/core_t2.c
--- linux-2.4.20/arch/alpha/kernel/core_t2.c	2001-03-02 19:12:07.000000000 +0000
+++ linux-2.4.21/arch/alpha/kernel/core_t2.c	2002-12-18 18:58:02.000000000 +0000
@@ -26,6 +26,18 @@
 #include "proto.h"
 #include "pci_impl.h"
 
+/*
+ * By default, we direct-map starting at 2GB, in order to allow the
+ * maximum size direct-map window (2GB) to match the maximum amount of
+ * memory (2GB) that can be present on SABLEs. But that limits the
+ * floppy to DMA only via the scatter/gather window set up for 8MB
+ * ISA DMA, since the maximum ISA DMA address is 2GB-1.
+ *
+ * For now, this seems a reasonable trade-off: even though most SABLEs
+ * have far less than even 1GB of memory, floppy usage/performance will
+ * not really be affected by forcing it to go via scatter/gather...
+ */
+#define T2_DIRECTMAP_2G 1
 
 /*
  * NOTE: Herein lie back-to-back mb instructions.  They are magic. 
@@ -325,6 +337,7 @@
 t2_init_arch(void)
 {
 	struct pci_controller *hose;
+	unsigned long t2_iocsr;
 	unsigned int i;
 
 	for (i = 0; i < NR_CPUS; i++) {
@@ -333,43 +346,80 @@
 	}
 
 #if 0
-	{
-	  /* Set up error reporting.  */
-	  unsigned long t2_err;
+	/* Set up error reporting.  */
+	t2_iocsr = *(vulp)T2_IOCSR;
+	*(vulp)T2_IOCSR = t2_iocsr | (0x1UL << 7); /* TLB error check */
+	mb();
+	*(vulp)T2_IOCSR; /* read it back to make sure */
+#endif
 
-	  t2_err = *(vulp)T2_IOCSR;
-	  t2_err |= (0x1 << 7);   /* master abort */
-	  *(vulp)T2_IOCSR = t2_err;
-	  mb();
+	/* Enable scatter/gather TLB use.  */
+	t2_iocsr = *(vulp)T2_IOCSR;
+	if (!(t2_iocsr & (0x1UL << 26))) {
+		printk("t2_init_arch: enabling SG TLB, IOCSR was 0x%lx\n",
+		       t2_iocsr);
+		*(vulp)T2_IOCSR = t2_iocsr | (0x1UL << 26);
+		mb();	
+		*(vulp)T2_IOCSR; /* read it back to make sure */
 	}
-#endif
 
-	printk("t2_init: HBASE was 0x%lx\n", *(vulp)T2_HBASE);
 #if 0
-	printk("t2_init: WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n",
-	       *(vulp)T2_WBASE1,
-	       *(vulp)T2_WMASK1,
-	       *(vulp)T2_TBASE1);
-	printk("t2_init: WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n",
-	       *(vulp)T2_WBASE2,
-	       *(vulp)T2_WMASK2,
-	       *(vulp)T2_TBASE2);
+	printk("t2_init_arch: HBASE was 0x%lx\n", *(vulp)T2_HBASE);
+	printk("t2_init_arch: WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n",
+	       *(vulp)T2_WBASE1, *(vulp)T2_WMASK1, *(vulp)T2_TBASE1);
+	printk("t2_init_arch: WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n",
+	       *(vulp)T2_WBASE2, *(vulp)T2_WMASK2, *(vulp)T2_TBASE2);
 #endif
 
 	/*
+	 * Create our single hose.
+	 */
+
+	pci_isa_hose = hose = alloc_pci_controller();
+	hose->io_space = &ioport_resource;
+	hose->mem_space = &iomem_resource;
+	hose->index = 0;
+
+	hose->sparse_mem_base = T2_SPARSE_MEM - IDENT_ADDR;
+	hose->dense_mem_base = T2_DENSE_MEM - IDENT_ADDR;
+	hose->sparse_io_base = T2_IO - IDENT_ADDR;
+	hose->dense_io_base = 0;
+
+	/* Note we can only do 1 SG window, as the other is for direct, so
+	   do an ISA SG area, especially for the floppy. */
+	hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0);
+	hose->sg_pci = NULL;
+
+	/*
 	 * Set up the PCI->physical memory translation windows.
-	 * For now, window 2 is  disabled.  In the future, we may
-	 * want to use it to do scatter/gather DMA. 
 	 *
-	 * Window 1 goes at 1 GB and is 1 GB large.
+	 * Window 1 goes at ? GB and is ?GB large, direct mapped.
+	 * Window 2 goes at 8 MB and is 8MB large, scatter/gather (for ISA).
 	 */
 
-	/* WARNING!! must correspond to the DMA_WIN params!!! */
+#if T2_DIRECTMAP_2G
+	__direct_map_base = 0x80000000UL;
+	__direct_map_size = 0x80000000UL;
+
+	/* WARNING!! must correspond to the direct map window params!!! */
+	*(vulp)T2_WBASE1 = 0x80080fffU;
+	*(vulp)T2_WMASK1 = 0x7ff00000U;
+	*(vulp)T2_TBASE1 = 0;
+#else /* T2_DIRECTMAP_2G */
+	__direct_map_base = 0x40000000UL;
+	__direct_map_size = 0x40000000UL;
+
+	/* WARNING!! must correspond to the direct map window params!!! */
 	*(vulp)T2_WBASE1 = 0x400807ffU;
 	*(vulp)T2_WMASK1 = 0x3ff00000U;
 	*(vulp)T2_TBASE1 = 0;
+#endif /* T2_DIRECTMAP_2G */
+
+	/* WARNING!! must correspond to the SG arena/window params!!! */
+	*(vulp)T2_WBASE2 = 0x008c000fU;
+	*(vulp)T2_WMASK2 = 0x00700000U;
+	*(vulp)T2_TBASE2 = virt_to_phys(hose->sg_isa->ptes) >> 1;
 
-	*(vulp)T2_WBASE2 = 0x0;
 	*(vulp)T2_HBASE = 0x0;
 
 	/* Zero HAE.  */
@@ -377,26 +427,28 @@
 	*(vulp)T2_HAE_2 = 0; mb();
 	*(vulp)T2_HAE_3 = 0; mb();
 #if 0
-	*(vulp)T2_HAE_4 = 0; mb(); /* do not touch this */
+	*(vulp)T2_HAE_4 = 0; mb(); /* DO NOT TOUCH THIS!!! */
 #endif
 
-	/*
-	 * Create our single hose.
-	 */
+	t2_pci_tbi(hose, 0, -1); /* flush TLB all */
+}
 
-	pci_isa_hose = hose = alloc_pci_controller();
-	hose->io_space = &ioport_resource;
-	hose->mem_space = &iomem_resource;
-	hose->index = 0;
+void
+t2_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
+{
+	unsigned long t2_iocsr;
 
-	hose->sparse_mem_base = T2_SPARSE_MEM - IDENT_ADDR;
-	hose->dense_mem_base = T2_DENSE_MEM - IDENT_ADDR;
-	hose->sparse_io_base = T2_IO - IDENT_ADDR;
-	hose->dense_io_base = 0;
+	t2_iocsr = *(vulp)T2_IOCSR;
 
-	hose->sg_isa = hose->sg_pci = NULL;
-	__direct_map_base = 0x40000000;
-	__direct_map_size = 0x40000000;
+	/* set the TLB Clear bit */
+	*(vulp)T2_IOCSR = t2_iocsr | (0x1UL << 28);
+	mb();
+	*(vulp)T2_IOCSR; /* read it back to make sure */
+
+	/* clear the TLB Clear bit */
+	*(vulp)T2_IOCSR = t2_iocsr & ~(0x1UL << 28);
+	mb();
+	*(vulp)T2_IOCSR; /* read it back to make sure */
 }
 
 #define SIC_SEIC (1UL << 33)    /* System Event Clear */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/core_tsunami.c linux-2.4.21/arch/alpha/kernel/core_tsunami.c
--- linux-2.4.20/arch/alpha/kernel/core_tsunami.c	2001-10-21 17:30:58.000000000 +0000
+++ linux-2.4.21/arch/alpha/kernel/core_tsunami.c	2002-12-18 18:58:07.000000000 +0000
@@ -350,10 +350,17 @@
 	 * Window 0 is scatter-gather 8MB at 8MB (for isa)
 	 * Window 1 is scatter-gather (up to) 1GB at 1GB
 	 * Window 2 is direct access 2GB at 2GB
+	 *
+	 * NOTE: we need the align_entry settings for Acer devices on ES40,
+	 * specifically floppy and IDE when memory is larger than 2GB.
 	 */
 	hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0);
+	/* Initially set for 4 PTEs, but will be overridden to 64K for ISA. */
+	hose->sg_isa->align_entry = 4;
+
 	hose->sg_pci = iommu_arena_new(hose, 0x40000000,
 				       size_for_memory(0x40000000), 0);
+	hose->sg_pci->align_entry = 4; /* Tsunami caches 4 PTEs at a time */
 
 	__direct_map_base = 0x80000000;
 	__direct_map_size = 0x80000000;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/pci_impl.h linux-2.4.21/arch/alpha/kernel/pci_impl.h
--- linux-2.4.20/arch/alpha/kernel/pci_impl.h	2001-10-12 22:35:53.000000000 +0000
+++ linux-2.4.21/arch/alpha/kernel/pci_impl.h	2002-12-18 18:58:11.000000000 +0000
@@ -52,15 +52,16 @@
 #define APECS_AND_LCA_DEFAULT_MEM_BASE ((16+2)*1024*1024)
 
 /*
- * Because the MCPCIA core logic supports more bits for physical addresses,
- * it should allow an expanded range of SPARSE memory addresses.
- * However, we do not use them all, in order to avoid the HAE manipulation
- * that would be needed.
+ * Because MCPCIA and T2 core logic support more bits for
+ * physical addresses, they should allow an expanded range of SPARSE
+ * memory addresses.  However, we do not use them all, in order to
+ * avoid the HAE manipulation that would be needed.
  */
 #define MCPCIA_DEFAULT_MEM_BASE ((32+2)*1024*1024)
+#define T2_DEFAULT_MEM_BASE ((16+1)*1024*1024)
 
 /*
- * Because CIA and PYXIS and T2 have more bits for physical addresses,
+ * Because CIA and PYXIS have more bits for physical addresses,
  * they support an expanded range of SPARSE memory addresses.
  */
 #define DEFAULT_MEM_BASE ((128+16)*1024*1024)
@@ -157,8 +158,6 @@
 extern struct pci_iommu_arena *iommu_arena_new(struct pci_controller *,
 					       dma_addr_t, unsigned long,
 					       unsigned long);
-extern long iommu_arena_alloc(struct pci_iommu_arena *arena, long n);
-
 extern const char *const pci_io_names[];
 extern const char *const pci_mem_names[];
 extern const char pci_hae0_name[];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/pci_iommu.c linux-2.4.21/arch/alpha/kernel/pci_iommu.c
--- linux-2.4.20/arch/alpha/kernel/pci_iommu.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/arch/alpha/kernel/pci_iommu.c	2002-12-18 18:58:11.000000000 +0000
@@ -30,10 +30,9 @@
 #define DEBUG_NODIRECT 0
 #define DEBUG_FORCEDAC 0
 
-/* Most Alphas support 32-bit ISA DMA. Exceptions are XL, Ruffian and
-   Nautilus (see asm/dma.h for details). */
-#define ISA_DMA_MASK	(MAX_DMA_ADDRESS - IDENT_ADDR - 1 < 0xffffffff ? \
-			 MAX_DMA_ADDRESS - IDENT_ADDR - 1 : 0xffffffff)
+/* Most Alphas support 32-bit ISA DMA. Exceptions are XL, Ruffian,
+   Sable, and Alcor (see asm-alpha/dma.h for details). */
+#define ISA_DMA_MASK	(MAX_DMA_ADDRESS - IDENT_ADDR - 1)
 
 static inline unsigned long
 mk_iommu_pte(unsigned long paddr)
@@ -133,8 +132,8 @@
 	return p;
 }
 
-long
-iommu_arena_alloc(struct pci_iommu_arena *arena, long n)
+static long
+iommu_arena_alloc(struct pci_iommu_arena *arena, long n, unsigned int align)
 {
 	unsigned long flags;
 	unsigned long *ptes;
@@ -144,7 +143,7 @@
 
 	/* Search for N empty ptes */
 	ptes = arena->ptes;
-	mask = arena->align_entry - 1;
+	mask = max(align, arena->align_entry) - 1;
 	p = iommu_arena_find_pages(arena, n, mask);
 	if (p < 0) {
 		spin_unlock_irqrestore(&arena->lock, flags);
@@ -233,7 +232,8 @@
 		arena = hose->sg_isa;
 
 	npages = calc_npages((paddr & ~PAGE_MASK) + size);
-	dma_ofs = iommu_arena_alloc(arena, npages);
+	/* Force allocation to 64KB boundary for all ISA devices. */
+	dma_ofs = iommu_arena_alloc(arena, npages, pdev ? 0 : 8);
 	if (dma_ofs < 0) {
 		printk(KERN_WARNING "pci_map_single failed: "
 		       "could not allocate dma page tables\n");
@@ -505,7 +505,7 @@
 
 	paddr &= ~PAGE_MASK;
 	npages = calc_npages(paddr + size);
-	dma_ofs = iommu_arena_alloc(arena, npages);
+	dma_ofs = iommu_arena_alloc(arena, npages, 0);
 	if (dma_ofs < 0) {
 		/* If we attempted a direct map above but failed, die.  */
 		if (leader->dma_address == 0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/proto.h linux-2.4.21/arch/alpha/kernel/proto.h
--- linux-2.4.20/arch/alpha/kernel/proto.h	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.21/arch/alpha/kernel/proto.h	2002-12-18 18:58:04.000000000 +0000
@@ -59,7 +59,7 @@
 extern struct pci_ops t2_pci_ops;
 extern void t2_init_arch(void);
 extern void t2_machine_check(u64, u64, struct pt_regs *);
-#define t2_pci_tbi ((void *)0)
+extern void t2_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_titan.c */
 extern struct pci_ops titan_pci_ops;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/setup.c linux-2.4.21/arch/alpha/kernel/setup.c
--- linux-2.4.20/arch/alpha/kernel/setup.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/arch/alpha/kernel/setup.c	2002-12-18 18:58:04.000000000 +0000
@@ -243,6 +243,27 @@
         return end >> PAGE_SHIFT; /* Return the PFN of the limit. */
 }
 
+#ifdef CONFIG_BLK_DEV_INITRD
+void * __init
+move_initrd(unsigned long mem_limit)
+{
+	void *start;
+	unsigned long size;
+
+	size = initrd_end - initrd_start;
+	start = __alloc_bootmem(size, PAGE_SIZE, 0);
+	if (!start || __pa(start) + size > mem_limit) {
+		initrd_start = initrd_end = 0;
+		return NULL;
+	}
+	memmove(start, (void *)initrd_start, size);
+	initrd_start = (unsigned long)start;
+	initrd_end = initrd_start + size;
+	printk(KERN_INFO "initrd moved to %p\n", start);
+	return start;
+}
+#endif
+
 #ifndef CONFIG_DISCONTIGMEM
 static void __init
 setup_memory(void *kernel_end)
@@ -371,11 +392,11 @@
 		       (void *) initrd_start, INITRD_SIZE);
 
 		if ((void *)initrd_end > phys_to_virt(PFN_PHYS(max_low_pfn))) {
-			printk("initrd extends beyond end of memory "
-			       "(0x%08lx > 0x%p)\ndisabling initrd\n",
-			       initrd_end,
-			       phys_to_virt(PFN_PHYS(max_low_pfn)));
-			initrd_start = initrd_end = 0;
+			if (!move_initrd(PFN_PHYS(max_low_pfn)))
+				printk("initrd extends beyond end of memory "
+				       "(0x%08lx > 0x%p)\ndisabling initrd\n",
+				       initrd_end,
+				       phys_to_virt(PFN_PHYS(max_low_pfn)));
 		} else {
 			reserve_bootmem(virt_to_phys((void *)initrd_start),
 					INITRD_SIZE);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/smp.c linux-2.4.21/arch/alpha/kernel/smp.c
--- linux-2.4.20/arch/alpha/kernel/smp.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/arch/alpha/kernel/smp.c	2002-12-18 18:58:05.000000000 +0000
@@ -81,7 +81,6 @@
 int smp_num_probed;		/* Internal processor count */
 int smp_num_cpus = 1;		/* Number that came online.  */
 int smp_threads_ready;		/* True once the per process idle is forked. */
-cycles_t cacheflush_time;
 
 int __cpu_number_map[NR_CPUS];
 int __cpu_logical_map[NR_CPUS];
@@ -184,20 +183,20 @@
 	 */
 	wait_boot_cpu_to_stop(cpuid);
 	mb();
- try_again:
+
 	calibrate_delay();
 
 	smp_store_cpu_info(cpuid);
 
 	{
 #define LPJ(c) ((long)cpu_data[c].loops_per_jiffy)
-	  static int tries = 3;
 	  long diff = LPJ(boot_cpuid) - LPJ(cpuid);
 	  if (diff < 0) diff = -diff;
 				
-	  if (diff > LPJ(boot_cpuid)/10 && --tries) {
-	    printk("Bogus BogoMIPS for cpu %d - retrying...\n", cpuid);
-	    goto try_again;
+	  if (diff > LPJ(boot_cpuid)/10) {
+	  	printk("Bogus BogoMIPS for cpu %d - trusting boot CPU\n",
+		       cpuid);
+		loops_per_jiffy = LPJ(cpuid) = LPJ(boot_cpuid);
 	  }
 	}
 
@@ -225,64 +224,6 @@
 	cpu_idle();
 }
 
-
-/*
- * Rough estimation for SMP scheduling, this is the number of cycles it
- * takes for a fully memory-limited process to flush the SMP-local cache.
- *
- * We are not told how much cache there is, so we have to guess.
- */
-static void __init
-smp_tune_scheduling (int cpuid)
-{
-	struct percpu_struct *cpu;
-	unsigned long on_chip_cache;
-	unsigned long freq;
-
-	cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset
-				      + cpuid * hwrpb->processor_size);
-	switch (cpu->type)
-	{
-	case EV45_CPU:
-		on_chip_cache = 16 + 16;
-		break;
-
-	case EV5_CPU:
-	case EV56_CPU:
-		on_chip_cache = 8 + 8 + 96;
-		break;
-
-	case PCA56_CPU:
-		on_chip_cache = 16 + 8;
-		break;
-
-	case EV6_CPU:
-	case EV67_CPU:
-		on_chip_cache = 64 + 64;
-		break;
-
-	default:
-		on_chip_cache = 8 + 8;
-		break;
-	}
-
-	freq = hwrpb->cycle_freq ? : est_cycle_freq;
-
-#if 0
-	/* Magic estimation stolen from x86 port.  */
-	cacheflush_time = freq / 1024L * on_chip_cache / 5000L;
-
-        printk("Using heuristic of %d cycles.\n",
-               cacheflush_time);
-#else
-	/* Magic value to force potential preemption of other CPUs.  */
-	cacheflush_time = INT_MAX;
-
-        printk("Using heuristic of %d cycles.\n",
-               cacheflush_time);
-#endif
-}
-
 /*
  * Send a message to a secondary's console.  "START" is one such
  * interesting message.  ;-)
@@ -622,7 +563,6 @@
 	current->processor = boot_cpuid;
 
 	smp_store_cpu_info(boot_cpuid);
-	smp_tune_scheduling(boot_cpuid);
 	smp_setup_percpu_timer(boot_cpuid);
 
 	init_idle();
@@ -666,8 +606,8 @@
 	}
 	printk(KERN_INFO "SMP: Total of %d processors activated "
 	       "(%lu.%02lu BogoMIPS).\n",
-	       cpu_count, (bogosum + 2500) / (500000/HZ),
-	       ((bogosum + 2500) / (5000/HZ)) % 100);
+	       cpu_count, bogosum / (500000/HZ),
+	       (bogosum / (5000/HZ)) % 100);
 
 	smp_num_cpus = cpu_count;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_alcor.c linux-2.4.21/arch/alpha/kernel/sys_alcor.c
--- linux-2.4.20/arch/alpha/kernel/sys_alcor.c	2001-06-27 23:18:13.000000000 +0000
+++ linux-2.4.21/arch/alpha/kernel/sys_alcor.c	2002-12-18 18:58:07.000000000 +0000
@@ -250,7 +250,7 @@
 	DO_CIA_IO,
 	DO_CIA_BUS,
 	machine_check:		cia_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
+	max_dma_address:	ALPHA_ALCOR_MAX_DMA_ADDRESS,
 	min_io_address:		EISA_DEFAULT_IO_BASE,
 	min_mem_address:	CIA_DEFAULT_MEM_BASE,
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_sable.c linux-2.4.21/arch/alpha/kernel/sys_sable.c
--- linux-2.4.20/arch/alpha/kernel/sys_sable.c	2001-06-12 18:44:59.000000000 +0000
+++ linux-2.4.21/arch/alpha/kernel/sys_sable.c	2002-12-18 18:58:03.000000000 +0000
@@ -289,9 +289,9 @@
 	DO_T2_IO,
 	DO_T2_BUS,
 	machine_check:		t2_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
+	max_dma_address:	ALPHA_SABLE_MAX_DMA_ADDRESS,
 	min_io_address:		EISA_DEFAULT_IO_BASE,
-	min_mem_address:	DEFAULT_MEM_BASE,
+	min_mem_address:	T2_DEFAULT_MEM_BASE,
 
 	nr_irqs:		40,
 	device_interrupt:	sable_srm_device_interrupt,
@@ -321,9 +321,9 @@
 	DO_T2_IO,
 	DO_T2_BUS,
 	machine_check:		t2_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
+	max_dma_address:	ALPHA_SABLE_MAX_DMA_ADDRESS,
 	min_io_address:		EISA_DEFAULT_IO_BASE,
-	min_mem_address:	DEFAULT_MEM_BASE,
+	min_mem_address:	T2_DEFAULT_MEM_BASE,
 
 	nr_irqs:		40,
 	device_interrupt:	sable_srm_device_interrupt,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/time.c linux-2.4.21/arch/alpha/kernel/time.c
--- linux-2.4.20/arch/alpha/kernel/time.c	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.21/arch/alpha/kernel/time.c	2002-12-18 18:58:09.000000000 +0000
@@ -143,7 +143,9 @@
 
 	/* Reset periodic interrupt frequency.  */
 	x = CMOS_READ(RTC_FREQ_SELECT) & 0x3f;
-	if (x != 0x26 && x != 0x19 && x != 0x06) {
+	/* Test includes known working values on various platforms
+	   where 0x26 is wrong; we refuse to change those. */
+	if (x != 0x26 && x != 0x25 && x != 0x19 && x != 0x06) {
 		printk("Setting RTC_FREQ to 1024 Hz (%x)\n", x);
 		CMOS_WRITE(0x26, RTC_FREQ_SELECT);
 	}
@@ -183,8 +185,8 @@
 		unsigned int min, max;
 	} cpu_hz[] __initdata = {
 		[EV3_CPU]    = {   50000000,  200000000 },	/* guess */
-		[EV4_CPU]    = {  150000000,  300000000 },
-		[LCA4_CPU]   = {  150000000,  300000000 },	/* guess */
+		[EV4_CPU]    = {  100000000,  300000000 },
+		[LCA4_CPU]   = {  100000000,  300000000 },	/* guess */
 		[EV45_CPU]   = {  200000000,  300000000 },
 		[EV5_CPU]    = {  250000000,  433000000 },
 		[EV56_CPU]   = {  333000000,  667000000 },
@@ -255,12 +257,12 @@
 
 	cc = rpcc();
 	do {
-		count++;
+	  count += 100; /* by 1 takes too long to timeout from 0 */
 	} while ((inb(0x61) & 0x20) == 0 && count > 0);
 	cc = rpcc() - cc;
 
 	/* Error: ECTCNEVERSET or ECPUTOOFAST.  */
-	if (count <= 1)
+	if (count <= 100)
 		return 0;
 
 	/* Error: ECPUTOOSLOW.  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/traps.c linux-2.4.21/arch/alpha/kernel/traps.c
--- linux-2.4.20/arch/alpha/kernel/traps.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/alpha/kernel/traps.c	2002-12-18 18:58:05.000000000 +0000
@@ -29,6 +29,7 @@
 */
 static int opDEC_testing = 0;
 static int opDEC_fix = 0;
+static int opDEC_checked = 0;
 static unsigned long opDEC_test_pc = 0;
 
 static void
@@ -36,6 +37,8 @@
 {
 	unsigned long test_pc;
 
+	if (opDEC_checked) return;
+
 	lock_kernel();
 	opDEC_testing = 1;
 
@@ -48,6 +51,7 @@
 		: );
 
 	opDEC_testing = 0;
+	opDEC_checked = 1;
 	unlock_kernel();
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/ev6-strncpy_from_user.S linux-2.4.21/arch/alpha/lib/ev6-strncpy_from_user.S
--- linux-2.4.20/arch/alpha/lib/ev6-strncpy_from_user.S	2000-12-04 01:45:20.000000000 +0000
+++ linux-2.4.21/arch/alpha/lib/ev6-strncpy_from_user.S	2002-12-18 18:58:08.000000000 +0000
@@ -27,7 +27,7 @@
 
 
 #include <asm/errno.h>
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 
 /* Allow an exception for an insn; exit if we get one.  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/ev6-stxcpy.S linux-2.4.21/arch/alpha/lib/ev6-stxcpy.S
--- linux-2.4.20/arch/alpha/lib/ev6-stxcpy.S	2000-12-11 21:46:26.000000000 +0000
+++ linux-2.4.21/arch/alpha/lib/ev6-stxcpy.S	2002-12-18 18:58:01.000000000 +0000
@@ -30,7 +30,7 @@
  * Try not to change the actual algorithm if possible for consistency.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noat
 	.set noreorder
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/ev6-stxncpy.S linux-2.4.21/arch/alpha/lib/ev6-stxncpy.S
--- linux-2.4.20/arch/alpha/lib/ev6-stxncpy.S	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/alpha/lib/ev6-stxncpy.S	2002-12-18 18:58:11.000000000 +0000
@@ -25,7 +25,7 @@
  *	a0  = unaligned address of the last *word* written
  *	a2  = the number of full words left in COUNT
  *
- * Furthermore, v0, a3-a5, t11, t12, and $at are untouched.
+ * Furthermore, v0, a3-a5, t11, and $at are untouched.
  *
  * Much of the information about 21264 scheduling/coding comes from:
  *	Compiler Writer's Guide for the Alpha 21264
@@ -38,7 +38,7 @@
  * Try not to change the actual algorithm if possible for consistency.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noat
 	.set noreorder
@@ -324,7 +324,7 @@
 	extqh	t2, a1, t0	# U : extract low bits for last word (stall)
 	or	t1, t0, t1	# E : (stall)
 
-	cmpbge	zero, t1, t8	# E :
+1:	cmpbge	zero, t1, t8	# E :
 	mov	t1, t0		# E :
 
 $u_eocfin:			# end-of-count, final word
@@ -350,17 +350,17 @@
 	mskql	t6, a0, t6	# U :
 	nop
 	nop
-1:	subq	a1, t4, a1	# E : sub dest misalignment from src addr
+	subq	a1, t4, a1	# E : sub dest misalignment from src addr
 
 	/* If source misalignment is larger than dest misalignment, we need
 	   extra startup checks to avoid SEGV.  */
 
-	cmplt	t4, t5, t12	# E :
+1:	cmplt	t4, t5, t12	# E :
 	extql	t1, a1, t1	# U : shift src into place
 	lda	t2, -1		# E : for creating masks later
 	beq	t12, $u_head	# U : (stall)
 
-	mskqh	t2, t5, t2	# U : begin src byte validity mask
+	nop
 	cmpbge	zero, t1, t8	# E : is there a zero?
 	extql	t2, a1, t2	# U :
 	or	t8, t10, t5	# E : test for end-of-count too
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/ev67-strchr.S linux-2.4.21/arch/alpha/lib/ev67-strchr.S
--- linux-2.4.20/arch/alpha/lib/ev67-strchr.S	2000-12-11 21:46:26.000000000 +0000
+++ linux-2.4.21/arch/alpha/lib/ev67-strchr.S	2002-12-18 18:58:01.000000000 +0000
@@ -16,7 +16,7 @@
  * Try not to change the actual algorithm if possible for consistency.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noreorder
 	.set noat
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/ev67-strlen_user.S linux-2.4.21/arch/alpha/lib/ev67-strlen_user.S
--- linux-2.4.20/arch/alpha/lib/ev67-strlen_user.S	2000-12-04 01:45:20.000000000 +0000
+++ linux-2.4.21/arch/alpha/lib/ev67-strlen_user.S	2002-12-18 18:58:08.000000000 +0000
@@ -23,7 +23,7 @@
  * Try not to change the actual algorithm if possible for consistency.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 
 /* Allow an exception for an insn; exit if we get one.  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/ev67-strrchr.S linux-2.4.21/arch/alpha/lib/ev67-strrchr.S
--- linux-2.4.20/arch/alpha/lib/ev67-strrchr.S	2000-12-30 19:13:36.000000000 +0000
+++ linux-2.4.21/arch/alpha/lib/ev67-strrchr.S	2002-12-18 18:58:01.000000000 +0000
@@ -19,7 +19,7 @@
  */
 
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noreorder
 	.set noat
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/strchr.S linux-2.4.21/arch/alpha/lib/strchr.S
--- linux-2.4.20/arch/alpha/lib/strchr.S	1996-10-18 08:53:20.000000000 +0000
+++ linux-2.4.21/arch/alpha/lib/strchr.S	2002-12-18 18:58:08.000000000 +0000
@@ -6,7 +6,7 @@
  * string, or null if it is not found.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noreorder
 	.set noat
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/strlen_user.S linux-2.4.21/arch/alpha/lib/strlen_user.S
--- linux-2.4.20/arch/alpha/lib/strlen_user.S	1999-10-11 17:06:34.000000000 +0000
+++ linux-2.4.21/arch/alpha/lib/strlen_user.S	2002-12-18 18:58:09.000000000 +0000
@@ -12,7 +12,7 @@
  * boundary when doing so.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 
 /* Allow an exception for an insn; exit if we get one.  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/strncpy_from_user.S linux-2.4.21/arch/alpha/lib/strncpy_from_user.S
--- linux-2.4.20/arch/alpha/lib/strncpy_from_user.S	1999-04-25 00:54:08.000000000 +0000
+++ linux-2.4.21/arch/alpha/lib/strncpy_from_user.S	2002-12-18 18:58:02.000000000 +0000
@@ -12,7 +12,7 @@
 
 
 #include <asm/errno.h>
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 
 /* Allow an exception for an insn; exit if we get one.  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/strrchr.S linux-2.4.21/arch/alpha/lib/strrchr.S
--- linux-2.4.20/arch/alpha/lib/strrchr.S	1997-11-19 22:07:33.000000000 +0000
+++ linux-2.4.21/arch/alpha/lib/strrchr.S	2002-12-18 18:58:06.000000000 +0000
@@ -6,7 +6,7 @@
  * within a null-terminated string, or null if it is not found.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noreorder
 	.set noat
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/stxcpy.S linux-2.4.21/arch/alpha/lib/stxcpy.S
--- linux-2.4.20/arch/alpha/lib/stxcpy.S	2000-12-11 21:46:26.000000000 +0000
+++ linux-2.4.21/arch/alpha/lib/stxcpy.S	2002-12-18 18:58:04.000000000 +0000
@@ -20,7 +20,7 @@
  * Furthermore, v0, a3-a5, t11, and t12 are untouched.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noat
 	.set noreorder
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/stxncpy.S linux-2.4.21/arch/alpha/lib/stxncpy.S
--- linux-2.4.20/arch/alpha/lib/stxncpy.S	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/alpha/lib/stxncpy.S	2002-12-18 18:58:12.000000000 +0000
@@ -25,10 +25,10 @@
  *	a0  = unaligned address of the last *word* written
  *	a2  = the number of full words left in COUNT
  *
- * Furthermore, v0, a3-a5, t11, t12, and $at are untouched.
+ * Furthermore, v0, a3-a5, t11, and $at are untouched.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noat
 	.set noreorder
@@ -269,7 +269,7 @@
 	   t1 == the shifted high-order bits from the previous source word  */
 $u_eoc:
 	and	a1, 7, t6	# e1    :
-	sll	t12, t6, t6	# e0    :
+	sll	t10, t6, t6	# e0    :
 	and	t6, 0xff, t6	# e0    :
 	bne	t6, 1f		# .. e1 :
 
@@ -303,18 +303,17 @@
 	ldq_u	t0, 0(a0)	# e0    :
 	lda	t6, -1		# .. e1 :
 	mskql	t6, a0, t6	# e0    :
-1:
 	subq	a1, t4, a1	# .. e1 : sub dest misalignment from src addr
 
 	/* If source misalignment is larger than dest misalignment, we need
 	   extra startup checks to avoid SEGV.  */
 
-	cmplt	t4, t5, t12	# e1    :
+1:	cmplt	t4, t5, t12	# e1    :
 	extql	t1, a1, t1	# .. e0 : shift src into place
 	lda	t2, -1		# e0    : for creating masks later
-	beq	t12, $u_head	# e1    :
+	beq	t12, $u_head	# .. e1 :
 
-	mskqh	t2, t5, t2	# e0    : begin src byte validity mask
+	nop			# e0    :
 	cmpbge	zero, t1, t8	# .. e1 : is there a zero?
 	extql	t2, a1, t2	# e0    :
 	or	t8, t10, t5	# .. e1 : test for end-of-count too
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/mm/init.c linux-2.4.21/arch/alpha/mm/init.c
--- linux-2.4.20/arch/alpha/mm/init.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/arch/alpha/mm/init.c	2002-12-18 18:58:06.000000000 +0000
@@ -368,18 +368,23 @@
 #endif /* CONFIG_DISCONTIGMEM */
 
 void
-free_initmem (void)
+free_reserved_mem(void *start, void *end)
 {
-	extern char __init_begin, __init_end;
-	unsigned long addr;
-
-	addr = (unsigned long)(&__init_begin);
-	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
-		ClearPageReserved(virt_to_page(addr));
-		set_page_count(virt_to_page(addr), 1);
-		free_page(addr);
+	void *__start = start;
+	for (; __start < end; __start += PAGE_SIZE) {
+		ClearPageReserved(virt_to_page(__start));
+		set_page_count(virt_to_page(__start), 1);
+		free_page((long)__start);
 		totalram_pages++;
 	}
+}
+
+void
+free_initmem(void)
+{
+	extern char __init_begin, __init_end;
+
+	free_reserved_mem(&__init_begin, &__init_end);
 	printk (KERN_INFO "Freeing unused kernel memory: %ldk freed\n",
 		(&__init_end - &__init_begin) >> 10);
 }
@@ -388,14 +393,9 @@
 void
 free_initrd_mem(unsigned long start, unsigned long end)
 {
-	unsigned long __start = start;
-	for (; start < end; start += PAGE_SIZE) {
-		ClearPageReserved(virt_to_page(start));
-		set_page_count(virt_to_page(start), 1);
-		free_page(start);
-		totalram_pages++;
-	}
-	printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - __start) >> 10);
+	free_reserved_mem((void *)start, (void *)end);
+	printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
+	       (end - start) >> 10);
 }
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/mm/numa.c linux-2.4.21/arch/alpha/mm/numa.c
--- linux-2.4.20/arch/alpha/mm/numa.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/arch/alpha/mm/numa.c	2002-12-18 18:58:02.000000000 +0000
@@ -249,16 +249,18 @@
 #ifdef CONFIG_BLK_DEV_INITRD
 	initrd_start = INITRD_START;
 	if (initrd_start) {
+		extern void *move_initrd(unsigned long);
+
 		initrd_end = initrd_start+INITRD_SIZE;
 		printk("Initial ramdisk at: 0x%p (%lu bytes)\n",
 		       (void *) initrd_start, INITRD_SIZE);
 
 		if ((void *)initrd_end > phys_to_virt(PFN_PHYS(max_low_pfn))) {
-			printk("initrd extends beyond end of memory "
-			       "(0x%08lx > 0x%p)\ndisabling initrd\n",
-			       initrd_end,
-			       phys_to_virt(PFN_PHYS(max_low_pfn)));
-			initrd_start = initrd_end = 0;
+			if (!move_initrd(PFN_PHYS(max_low_pfn)))
+				printk("initrd extends beyond end of memory "
+				       "(0x%08lx > 0x%p)\ndisabling initrd\n",
+				       initrd_end,
+				       phys_to_virt(PFN_PHYS(max_low_pfn)));
 		} else {
 			reserve_bootmem_node(NODE_DATA(KVADDR_TO_NID(initrd_start)),
 					     virt_to_phys((void *)initrd_start),
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/config.in linux-2.4.21/arch/arm/config.in
--- linux-2.4.20/arch/arm/config.in	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/arm/config.in	2002-12-18 18:58:04.000000000 +0000
@@ -83,7 +83,7 @@
    choice 'Cerf Flash available'  \
         "8MB    CONFIG_SA1100_CERF_FLASH_8MB \
          16MB   CONFIG_SA1100_CERF_FLASH_16MB \
-         32MB   CONFIG_SA1100_CERF_FLASH_32MB" CerfFlash
+         32MB   CONFIG_SA1100_CERF_FLASH_32MB" 8MB
    bool 'Cerf w/CPLD support (CerfPDA)' CONFIG_SA1100_CERF_CPLD
 fi
 dep_bool '  Compaq iPAQ H3100' CONFIG_SA1100_H3100 $CONFIG_ARCH_SA1100
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/boot/compressed/decompress.ld linux-2.4.21/arch/cris/boot/compressed/decompress.ld
--- linux-2.4.20/arch/cris/boot/compressed/decompress.ld	2001-07-26 22:10:06.000000000 +0000
+++ linux-2.4.21/arch/cris/boot/compressed/decompress.ld	2002-12-18 18:58:03.000000000 +0000
@@ -13,6 +13,7 @@
 		_stext = . ;
 		*(.text)
 		*(.rodata)
+		*(.rodata.*)
 		_etext = . ;
 	} > dram
 	.data :
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/boot/rescue/Makefile linux-2.4.21/arch/cris/boot/rescue/Makefile
--- linux-2.4.20/arch/cris/boot/rescue/Makefile	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.21/arch/cris/boot/rescue/Makefile	2002-12-18 18:58:07.000000000 +0000
@@ -53,7 +53,7 @@
 
 modules:
 
-modules-install:
+modules_install:
 
 depend:
 	$(CC) -M *.S > .depend
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/config.in linux-2.4.21/arch/cris/config.in
--- linux-2.4.20/arch/cris/config.in	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/cris/config.in	2002-12-18 18:58:01.000000000 +0000
@@ -154,6 +154,11 @@
 
 source drivers/md/Config.in
 
+source drivers/pcmcia/Config.in
+if [ "$CONFIG_PCMCIA" != "n" ]; then
+   define_bool CONFIG_VIRTUAL_BUS y
+fi
+
 if [ "$CONFIG_NET" = "y" ]; then
   source net/Config.in
 fi
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/Config.in linux-2.4.21/arch/cris/drivers/Config.in
--- linux-2.4.20/arch/cris/drivers/Config.in	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/cris/drivers/Config.in	2002-12-18 18:58:04.000000000 +0000
@@ -26,46 +26,150 @@
   bool '  Use fast timers for serial DMA flush (experimental)' CONFIG_ETRAX_SERIAL_FAST_TIMER
   if [ "$CONFIG_ETRAX_SERIAL_FAST_TIMER" = "n" ]; then
     bool '  Fast serial port DMA flush' CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
-    if [ "$CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST" = "n" ]; then
+    if [ "$CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST" = "n" ]; then
       int '  Receive flush timeout (ticks) ' CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5
     fi
   fi
   bool '  Serial port 0 enabled' CONFIG_ETRAX_SERIAL_PORT0
   if [ "$CONFIG_ETRAX_SERIAL_PORT0" = "y" ]; then
-    bool '  Ser0 DTR, RI, DSR, CD on PB' CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB
-    if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB" = "y" ]; then
-      int '    Ser0 DTR on PB bit' CONFIG_ETRAX_SER0_DTR_ON_PB_BIT 4
-      int '    Ser0 RI  on PB bit' CONFIG_ETRAX_SER0_RI_ON_PB_BIT 5
-      int '    Ser0 DSR on PB bit' CONFIG_ETRAX_SER0_DSR_ON_PB_BIT 6
-      int '    Ser0 CD  on PB bit' CONFIG_ETRAX_SER0_CD_ON_PB_BIT 7
+  choice 'Ser0 DTR, RI, DSR and CD assignment' \
+  "No_DTR_RI_DSR_CD      CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_NONE \
+   DTR_RI_DSR_CD_on_PA   CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PA \
+   DTR_RI_DSR_CD_on_PB   CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB \
+   DTR_RI_DSR_CD_mixed_on_PA_and_PB  CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED" \
+     No_DTR_RI_DSR_CD
+
+    if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PA" = "y" -o \
+         "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser0 DTR on PA bit (-1 = not used)' CONFIG_ETRAX_SER0_DTR_ON_PA_BIT 4
+      int '    Ser0 RI  on PA bit (-1 = not used)' CONFIG_ETRAX_SER0_RI_ON_PA_BIT 5
+      int '    Ser0 DSR on PA bit (-1 = not used)' CONFIG_ETRAX_SER0_DSR_ON_PA_BIT 6
+      int '    Ser0 CD  on PA bit (-1 = not used)' CONFIG_ETRAX_SER0_CD_ON_PA_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER0_DTR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER0_RI_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER0_DSR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER0_CD_ON_PA_BIT -1
+    fi
+    if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB" = "y" -o \
+         "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser0 DTR on PB bit (-1 = not used)' CONFIG_ETRAX_SER0_DTR_ON_PB_BIT 4
+      int '    Ser0 RI  on PB bit (-1 = not used)' CONFIG_ETRAX_SER0_RI_ON_PB_BIT 5
+      int '    Ser0 DSR on PB bit (-1 = not used)' CONFIG_ETRAX_SER0_DSR_ON_PB_BIT 6
+      int '    Ser0 CD  on PB bit (-1 = not used)' CONFIG_ETRAX_SER0_CD_ON_PB_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER0_DTR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER0_RI_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER0_DSR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER0_CD_ON_PB_BIT -1
     fi
   fi
 
   bool '  Serial port 1 enabled' CONFIG_ETRAX_SERIAL_PORT1
   if [ "$CONFIG_ETRAX_SERIAL_PORT1" = "y" ]; then
-    bool '  Ser1 DTR, RI, DSR, CD on PB' CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB
-    if [ "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB" = "y" ]; then
-      int '    Ser1 DTR on PB bit' CONFIG_ETRAX_SER1_DTR_ON_PB_BIT 4
-      int '    Ser1 RI  on PB bit' CONFIG_ETRAX_SER1_RI_ON_PB_BIT 5
-      int '    Ser1 DSR on PB bit' CONFIG_ETRAX_SER1_DSR_ON_PB_BIT 6
-      int '    Ser1 CD  on PB bit' CONFIG_ETRAX_SER1_CD_ON_PB_BIT 7
+  choice 'Ser1 DTR, RI, DSR and CD assignment' \
+  "No_DTR_RI_DSR_CD      CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_NONE \
+   DTR_RI_DSR_CD_on_PA   CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PA \
+   DTR_RI_DSR_CD_on_PB   CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB \
+   DTR_RI_DSR_CD_mixed_on_PA_and_PB  CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED" \
+     No_DTR_RI_DSR_CD
+
+    if [ "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PA" = "y" -o \
+         "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser1 DTR on PA bit (-1 = not used)' CONFIG_ETRAX_SER1_DTR_ON_PA_BIT 4
+      int '    Ser1 RI  on PA bit (-1 = not used)' CONFIG_ETRAX_SER1_RI_ON_PA_BIT 5
+      int '    Ser1 DSR on PA bit (-1 = not used)' CONFIG_ETRAX_SER1_DSR_ON_PA_BIT 6
+      int '    Ser1 CD  on PA bit (-1 = not used)' CONFIG_ETRAX_SER1_CD_ON_PA_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER1_DTR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER1_RI_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER1_DSR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER1_CD_ON_PA_BIT -1
+    fi
+    if [ "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB" = "y" -o \
+         "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser1 DTR on PB bit (-1 = not used)' CONFIG_ETRAX_SER1_DTR_ON_PB_BIT 4
+      int '    Ser1 RI  on PB bit (-1 = not used)' CONFIG_ETRAX_SER1_RI_ON_PB_BIT 5
+      int '    Ser1 DSR on PB bit (-1 = not used)' CONFIG_ETRAX_SER1_DSR_ON_PB_BIT 6
+      int '    Ser1 CD  on PB bit (-1 = not used)' CONFIG_ETRAX_SER1_CD_ON_PB_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER1_DTR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER1_RI_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER1_DSR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER1_CD_ON_PB_BIT -1
     fi
   fi
+
   if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB" = "y" -a \
        "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB" = "y" ]; then
     comment 'Make sure you dont have the same PB bits more than once!'
   fi
   bool '  Serial port 2 enabled' CONFIG_ETRAX_SERIAL_PORT2
   if [ "$CONFIG_ETRAX_SERIAL_PORT2" = "y" ]; then
-    bool '    Ser2 DTR, RI, DSR, CD on PA' CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA
-    if [ "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA" = "y" ]; then
-      int '      Ser2 DTR on PA bit' CONFIG_ETRAX_SER2_DTR_ON_PA_BIT 4
-      int '      Ser2 RI  on PA bit' CONFIG_ETRAX_SER2_RI_ON_PA_BIT 5
-      int '      Ser2 DSR on PA bit' CONFIG_ETRAX_SER2_DSR_ON_PA_BIT 6
-      int '      Ser2 CD  on PA bit' CONFIG_ETRAX_SER2_CD_ON_PA_BIT 7
-    fi 
+  choice 'Ser2 DTR, RI, DSR and CD assignment' \
+  "No_DTR_RI_DSR_CD      CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_NONE \
+   DTR_RI_DSR_CD_on_PA   CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA \
+   DTR_RI_DSR_CD_on_PB   CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PB \
+   DTR_RI_DSR_CD_mixed_on_PA_and_PB  CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED" \
+     No_DTR_RI_DSR_CD
+    if [ "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA" = "y" -o \
+         "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser2 DTR on PA bit (-1 = not used)' CONFIG_ETRAX_SER2_DTR_ON_PA_BIT 4
+      int '    Ser2 RI  on PA bit (-1 = not used)' CONFIG_ETRAX_SER2_RI_ON_PA_BIT 5
+      int '    Ser2 DSR on PA bit (-1 = not used)' CONFIG_ETRAX_SER2_DSR_ON_PA_BIT 6
+      int '    Ser2 CD  on PA bit (-1 = not used)' CONFIG_ETRAX_SER2_CD_ON_PA_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER2_DTR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER2_RI_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER2_DSR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER2_CD_ON_PA_BIT -1
+    fi
+    if [ "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PB" = "y" -o \
+         "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser2 DTR on PB bit (-1 = not used)' CONFIG_ETRAX_SER2_DTR_ON_PB_BIT 4
+      int '    Ser2 RI  on PB bit (-1 = not used)' CONFIG_ETRAX_SER2_RI_ON_PB_BIT 5
+      int '    Ser2 DSR on PB bit (-1 = not used)' CONFIG_ETRAX_SER2_DSR_ON_PB_BIT 6
+      int '    Ser2 CD  on PB bit (-1 = not used)' CONFIG_ETRAX_SER2_CD_ON_PB_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER2_DTR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER2_RI_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER2_DSR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER2_CD_ON_PB_BIT -1
+    fi
   fi
   bool '  Serial port 3 enabled' CONFIG_ETRAX_SERIAL_PORT3
+  if [ "$CONFIG_ETRAX_SERIAL_PORT3" = "y" ]; then
+  choice 'Ser3 DTR, RI, DSR and CD assignment' \
+  "No_DTR_RI_DSR_CD      CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_ON_NONE \
+   DTR_RI_DSR_CD_on_PA   CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_ON_PA \
+   DTR_RI_DSR_CD_on_PB   CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_ON_PB \
+   DTR_RI_DSR_CD_mixed_on_PA_and_PB  CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED" \
+     No_DTR_RI_DSR_CD
+    if [ "$CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_ON_PA" = "y" -o \
+         "$CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser3 DTR on PA bit (-1 = not used)' CONFIG_ETRAX_SER3_DTR_ON_PA_BIT -1
+      int '    Ser3 RI  on PA bit (-1 = not used)' CONFIG_ETRAX_SER3_RI_ON_PA_BIT -1
+      int '    Ser3 DSR on PA bit (-1 = not used)' CONFIG_ETRAX_SER3_DSR_ON_PA_BIT -1
+      int '    Ser3 CD  on PA bit (-1 = not used)' CONFIG_ETRAX_SER3_CD_ON_PA_BIT -1
+    else
+      define_int CONFIG_ETRAX_SER3_DTR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER3_RI_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER3_DSR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER3_CD_ON_PA_BIT -1
+    fi
+    if [ "$CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_ON_PB" = "y" -o \
+         "$CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser3 DTR on PB bit (-1 = not used)' CONFIG_ETRAX_SER3_DTR_ON_PB_BIT -1
+      int '    Ser3 RI  on PB bit (-1 = not used)' CONFIG_ETRAX_SER3_RI_ON_PB_BIT -1
+      int '    Ser3 DSR on PB bit (-1 = not used)' CONFIG_ETRAX_SER3_DSR_ON_PB_BIT -1
+      int '    Ser3 CD  on PB bit (-1 = not used)' CONFIG_ETRAX_SER3_CD_ON_PB_BIT -1
+    else
+      define_int CONFIG_ETRAX_SER3_DTR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER3_RI_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER3_DSR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER3_CD_ON_PB_BIT -1
+    fi
+  fi
   bool '  RS-485 support' CONFIG_ETRAX_RS485
   if [ "$CONFIG_ETRAX_RS485" = "y" ]; then
     bool '    RS-485 mode on PA' CONFIG_ETRAX_RS485_ON_PA
@@ -139,7 +243,6 @@
 	define_bool CONFIG_MTD y
 
 	define_bool CONFIG_MTD_CFI y
-	define_bool CONFIG_MTD_CFI_INTELEXT n
 	define_bool CONFIG_MTD_CFI_AMDSTD y
 
 	define_bool CONFIG_MTD_OBSOLETE_CHIPS y
@@ -148,6 +251,7 @@
 	define_bool CONFIG_MTD_CHAR y
 	define_bool CONFIG_MTD_BLOCK y
 	define_bool CONFIG_MTD_PARTITIONS y
+	define_bool CONFIG_MTD_CONCAT y
 fi
 
 bool 'I2C support' CONFIG_ETRAX_I2C
@@ -209,6 +313,7 @@
   int '  DS1302 RST bit number' CONFIG_ETRAX_DS1302_RSTBIT 2
   int '  DS1302 SCL bit number' CONFIG_ETRAX_DS1302_SCLBIT 1
   int '  DS1302 SDA bit number' CONFIG_ETRAX_DS1302_SDABIT 0
+  int '  DS1302 Trickle charger value' CONFIG_ETRAX_DS1302_TRICKLE_CHARGE 0
 fi
 
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/Makefile linux-2.4.21/arch/cris/drivers/Makefile
--- linux-2.4.20/arch/cris/drivers/Makefile	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/cris/drivers/Makefile	2002-12-18 18:58:01.000000000 +0000
@@ -18,6 +18,7 @@
 obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL)  += sync_serial.o
 obj-$(CONFIG_ETRAX_PARPORT)             += parport.o
 obj-$(CONFIG_ETRAX_DS1302)              += ds1302.o
+obj-$(CONFIG_ETRAX_PCF8563)		+= pcf8563.o
 
 
 obj-$(CONFIG_ETRAX_ETHERNET_LPSLAVE)    += lpslave/lpslavedrivers.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/axisflashmap.c linux-2.4.21/arch/cris/drivers/axisflashmap.c
--- linux-2.4.20/arch/cris/drivers/axisflashmap.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/arch/cris/drivers/axisflashmap.c	2002-12-18 18:58:11.000000000 +0000
@@ -11,6 +11,26 @@
  * partition split defined below.
  *
  * $Log: axisflashmap.c,v $
+ * Revision 1.28  2002/10/01 08:08:43  jonashg
+ * The first partition ends at the start of the partition table.
+ *
+ * Revision 1.27  2002/08/21 09:23:13  jonashg
+ * Speling.
+ *
+ * Revision 1.26  2002/08/21 08:35:20  jonashg
+ * Cosmetic change to printouts.
+ *
+ * Revision 1.25  2002/08/21 08:15:42  jonashg
+ * Made it compile even without CONFIG_MTD_CONCAT defined.
+ *
+ * Revision 1.24  2002/08/20 13:12:35  jonashg
+ * * New approach to probing. Probe cse0 and cse1 separately and (mtd)concat
+ *   the results.
+ * * Removed compile time tests concerning how the mtdram driver has been
+ *   configured. The user will know about the misconfiguration at runtime
+ *   instead. (The old approach made it impossible to use mtdram for anything
+ *   else than RAM boot).
+ *
  * Revision 1.23  2002/05/13 12:12:28  johana
  * Allow compile without CONFIG_MTD_MTDRAM but warn at compiletime and
  * be informative at runtime.
@@ -98,13 +118,15 @@
 #include <linux/kernel.h>
 #include <linux/config.h>
 
-#include <linux/mtd/mtd.h>
+#include <linux/mtd/concat.h>
 #include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
+#include <linux/mtd/mtd.h>
 #include <linux/mtd/mtdram.h>
+#include <linux/mtd/partitions.h>
 
 #include <asm/axisflashmap.h>
 #include <asm/mmu.h>
+#include <asm/sv_addr_ag.h>
 
 #ifdef CONFIG_CRIS_LOW_MAP
 #define FLASH_UNCACHED_ADDR  KSEG_8
@@ -114,63 +136,65 @@
 #define FLASH_CACHED_ADDR    KSEG_F
 #endif
 
-/*
- * WINDOW_SIZE is the total size where the flash chips may be mapped.
- * MTD probes should find all devices there and it does not matter
- * if there are unmapped gaps or aliases (mirrors of flash devices).
- * The MTD probes will ignore them.
- */
-
-#define WINDOW_SIZE  (128 * 1024 * 1024)
-
-extern unsigned long romfs_start, romfs_length, romfs_in_flash; /* From head.S */
+/* From head.S */
+extern unsigned long romfs_start, romfs_length, romfs_in_flash;
 
-/* 
- * Map driver
- *
- * We run into tricky coherence situations if we mix cached with uncached
- * accesses to we use the uncached version here.
- */
+/* Map driver functions. */
 
 static __u8 flash_read8(struct map_info *map, unsigned long ofs)
 {
-	return *(__u8 *)(FLASH_UNCACHED_ADDR + ofs);
+	return *(__u8 *)(map->map_priv_1 + ofs);
 }
 
 static __u16 flash_read16(struct map_info *map, unsigned long ofs)
 {
-	return *(__u16 *)(FLASH_UNCACHED_ADDR + ofs);
+	return *(__u16 *)(map->map_priv_1 + ofs);
 }
 
 static __u32 flash_read32(struct map_info *map, unsigned long ofs)
 {
-	return *(volatile unsigned int *)(FLASH_UNCACHED_ADDR + ofs);
+	return *(volatile unsigned int *)(map->map_priv_1 + ofs);
 }
 
 static void flash_copy_from(struct map_info *map, void *to,
 			    unsigned long from, ssize_t len)
 {
-	memcpy(to, (void *)(FLASH_UNCACHED_ADDR + from), len);
+	memcpy(to, (void *)(map->map_priv_1 + from), len);
 }
 
 static void flash_write8(struct map_info *map, __u8 d, unsigned long adr)
 {
-	*(__u8 *)(FLASH_UNCACHED_ADDR + adr) = d;
+	*(__u8 *)(map->map_priv_1 + adr) = d;
 }
 
 static void flash_write16(struct map_info *map, __u16 d, unsigned long adr)
 {
-	*(__u16 *)(FLASH_UNCACHED_ADDR + adr) = d;
+	*(__u16 *)(map->map_priv_1 + adr) = d;
 }
 
 static void flash_write32(struct map_info *map, __u32 d, unsigned long adr)
 {
-	*(__u32 *)(FLASH_UNCACHED_ADDR + adr) = d;
+	*(__u32 *)(map->map_priv_1 + adr) = d;
 }
 
-static struct map_info axis_map = {
-	name: "Axis flash",
-	size: WINDOW_SIZE,
+/*
+ * The map for chip select e0.
+ *
+ * We run into tricky coherence situations if we mix cached with uncached
+ * accesses to we only use the uncached version here.
+ *
+ * The size field is the total size where the flash chips may be mapped on the
+ * chip select. MTD probes should find all devices there and it does not matter
+ * if there are unmapped gaps or aliases (mirrors of flash devices). The MTD
+ * probes will ignore them.
+ *
+ * The start address in map_priv_1 is in virtual memory so we cannot use
+ * MEM_CSE0_START but must rely on that FLASH_UNCACHED_ADDR is the start
+ * address of cse0.
+ */
+static struct map_info map_cse0 = {
+	name: "cse0",
+	size: MEM_CSE0_SIZE,
 	buswidth: CONFIG_ETRAX_FLASH_BUSWIDTH,
 	read8: flash_read8,
 	read16: flash_read16,
@@ -179,15 +203,35 @@
 	write8: flash_write8,
 	write16: flash_write16,
 	write32: flash_write32,
+	map_priv_1: FLASH_UNCACHED_ADDR
 };
 
-/* If no partition-table was found, we use this default-set.
+/*
+ * The map for chip select e1.
+ *
+ * If there was a gap between cse0 and cse1, map_priv_1 would get the wrong
+ * address, but there isn't.
  */
+static struct map_info map_cse1 = {
+	name: "cse1",
+	size: MEM_CSE1_SIZE,
+	buswidth: CONFIG_ETRAX_FLASH_BUSWIDTH,
+	read8: flash_read8,
+	read16: flash_read16,
+	read32: flash_read32,
+	copy_from: flash_copy_from,
+	write8: flash_write8,
+	write16: flash_write16,
+	write32: flash_write32,
+	map_priv_1: FLASH_UNCACHED_ADDR + MEM_CSE0_SIZE
+};
 
+/* If no partition-table was found, we use this default-set. */
 #define MAX_PARTITIONS         7  
 #define NUM_DEFAULT_PARTITIONS 3
 
-/* Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the
+/*
+ * Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the
  * size of one flash block and "filesystem"-partition needs 5 blocks to be able
  * to use JFFS.
  */
@@ -209,10 +253,11 @@
 	}
 };
 
+/* Initialize the ones normally used. */
 static struct mtd_partition axis_partitions[MAX_PARTITIONS] = {
 	{
 		name: "part0",
-		size: 0,
+		size: CONFIG_ETRAX_PTABLE_SECTOR,
 		offset: 0
 	},
 	{
@@ -247,48 +292,118 @@
 	},
 };
 
+/*
+ * Probe a chip select for AMD-compatible (JEDEC) or CFI-compatible flash
+ * chips in that order (because the amd_flash-driver is faster).
+ */
+static struct mtd_info *probe_cs(struct map_info *map_cs)
+{
+	struct mtd_info *mtd_cs = NULL;
+
+	printk("%s: Probing a 0x%08lx bytes large window at 0x%08lx.\n",
+	       map_cs->name, map_cs->size, map_cs->map_priv_1);
+
+#ifdef CONFIG_MTD_AMDSTD
+	mtd_cs = do_map_probe("amd_flash", map_cs);
+#endif
+#ifdef CONFIG_MTD_CFI
+	if (!mtd_cs) {
+		mtd_cs = do_map_probe("cfi_probe", map_cs);
+	}
+#endif
+
+	return mtd_cs;
+}
+
 /* 
- * This is the master MTD device for which all the others are just
- * auto-relocating aliases.
+ * Probe each chip select individually for flash chips. If there are chips on
+ * both cse0 and cse1, the mtd_info structs will be concatenated to one struct
+ * so that MTD partitions can cross chip boundries.
+ *
+ * The only known restriction to how you can mount your chips is that each
+ * chip select must hold similar flash chips. But you need external hardware
+ * to do that anyway and you can put totally different chips on cse0 and cse1
+ * so it isn't really much of a restriction.
  */
-static struct mtd_info *mymtd;
+static struct mtd_info *flash_probe(void)
+{
+	struct mtd_info *mtd_cse0;
+	struct mtd_info *mtd_cse1;
+	struct mtd_info *mtd_cse;
+
+	mtd_cse0 = probe_cs(&map_cse0);
+	mtd_cse1 = probe_cs(&map_cse1);
+
+	if (!mtd_cse0 && !mtd_cse1) {
+		/* No chip found. */
+		return NULL;
+	}
+
+	if (mtd_cse0 && mtd_cse1) {
+#ifdef CONFIG_MTD_CONCAT
+		struct mtd_info *mtds[] = { mtd_cse0, mtd_cse1 };
+		
+		/* Since the concatenation layer adds a small overhead we
+		 * could try to figure out if the chips in cse0 and cse1 are
+		 * identical and reprobe the whole cse0+cse1 window. But since
+		 * flash chips are slow, the overhead is relatively small.
+		 * So we use the MTD concatenation layer instead of further
+		 * complicating the probing procedure.
+		 */
+		mtd_cse = mtd_concat_create(mtds,
+					    sizeof(mtds) / sizeof(mtds[0]),
+					    "cse0+cse1");
+#else
+		printk(KERN_ERR "%s and %s: Cannot concatenate due to kernel "
+		       "(mis)configuration!\n", map_cse0.name, map_cse1.name);
+		mtd_cse = NULL;
+#endif
+		if (!mtd_cse) {
+			printk(KERN_ERR "%s and %s: Concatenation failed!\n",
+			       map_cse0.name, map_cse1.name);
+
+			/* The best we can do now is to only use what we found
+			 * at cse0.
+			 */ 
+			mtd_cse = mtd_cse0;
+			map_destroy(mtd_cse1);
+		}
+	} else {
+		mtd_cse = mtd_cse0? mtd_cse0 : mtd_cse1;
+	}
+
+	return mtd_cse;
+}
 
-/* CFI-scan the flash, and if there was a chip, read the partition-table
+/*
+ * Probe the flash chip(s) and, if it succeeds, read the partition-table
  * and register the partitions with MTD.
  */
-
-static int __init
-init_axis_flash(void)
+static int __init init_axis_flash(void)
 {
+	struct mtd_info *mymtd;
 	int err = 0;
 	int pidx = 0;
 	struct partitiontable_head *ptable_head;
 	struct partitiontable_entry *ptable;
-	int use_default_ptable = 1; /* Until proven otherwise */
-	const char *pmsg = "  /dev/flash%d at 0x%x, size 0x%x\n";
-
-	printk(KERN_NOTICE "Axis flash mapping: %x at %lx\n",
-	       WINDOW_SIZE, FLASH_CACHED_ADDR);
-#ifdef CONFIG_MTD_AMDSTD
-	mymtd = (struct mtd_info *)do_map_probe("amd_flash", &axis_map);
-#endif
+	int use_default_ptable = 1; /* Until proven otherwise. */
+	const char *pmsg = "  /dev/flash%d at 0x%08x, size 0x%08x\n";
 
-#ifdef CONFIG_MTD_CFI
-	if (!mymtd) {
-		mymtd = (struct mtd_info *)do_map_probe("cfi_probe", &axis_map);
+	if (!(mymtd = flash_probe())) {
+		/* There's no reason to use this module if no flash chip can
+		 * be identified. Make sure that's understood.
+		 */
+		panic("axisflashmap found no flash chip!\n");
 	}
-#endif
 
-	if(!mymtd) {
-		printk("%s: No flash chip found!\n", axis_map.name);
-		return -ENXIO;
-	}
+	printk("%s: 0x%08x bytes of flash memory.\n",
+	       mymtd->name, mymtd->size);
 
 	mymtd->module = THIS_MODULE;
 
 	ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR +
-		CONFIG_ETRAX_PTABLE_SECTOR + PARTITION_TABLE_OFFSET);
-	pidx++;  /* first partition is always set to the default */
+		      CONFIG_ETRAX_PTABLE_SECTOR + PARTITION_TABLE_OFFSET);
+	pidx++;  /* First partition is always set to the default. */
 
 	if ((ptable_head->magic == PARTITION_TABLE_MAGIC)
 	    && (ptable_head->size <
@@ -322,20 +437,17 @@
 			csum += *p++;
 			csum += *p++;
 		}
-		/* printk("  total csum: 0x%08X 0x%08X\n",
-		   csum, ptable_head->checksum); */
 		ptable_ok = (csum == ptable_head->checksum);
 
 		/* Read the entries and use/show the info.  */
-		printk(" Found %s partition table at 0x%08lX-0x%08lX.\n",
-		       (ptable_ok ? "valid" : "invalid"),
-		       (unsigned long)ptable_head,
-		       (unsigned long)max_addr);
+		printk(" Found a%s partition table at 0x%p-0x%p.\n",
+		       (ptable_ok ? " valid" : "n invalid"), ptable_head,
+		       max_addr);
 
 		/* We have found a working bootblock.  Now read the
-		   partition table.  Scan the table.  It ends when
-		   there is 0xffffffff, that is, empty flash.  */
-		
+		 * partition table.  Scan the table.  It ends when
+		 * there is 0xffffffff, that is, empty flash.
+		 */
 		while (ptable_ok
 		       && ptable->offset != 0xffffffff
 		       && ptable < max_addr
@@ -352,59 +464,64 @@
 		use_default_ptable = !ptable_ok;
 	}
 
+	if (romfs_in_flash) {
+		/* Add an overlapping device for the root partition (romfs). */
+
+		axis_partitions[pidx].name = "romfs";
+		axis_partitions[pidx].size = romfs_length;
+		axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR;
+		axis_partitions[pidx].mask_flags |= MTD_WRITEABLE;
+
+		printk(" Adding readonly flash partition for romfs image:\n");
+		printk(pmsg, pidx, axis_partitions[pidx].offset,
+		       axis_partitions[pidx].size);
+		pidx++;
+	}
+
 	if (use_default_ptable) {
-		printk(" Using default partition table\n");
+		printk(" Using default partition table.\n");
 		err = add_mtd_partitions(mymtd, axis_default_partitions,
 		                         NUM_DEFAULT_PARTITIONS);
 	} else {
-		if (romfs_in_flash) {
-			axis_partitions[pidx].name = "romfs";
-			axis_partitions[pidx].size = romfs_length;
-			axis_partitions[pidx].offset = romfs_start -
-						       FLASH_CACHED_ADDR;
-			axis_partitions[pidx].mask_flags |= MTD_WRITEABLE;
-
-			printk(" Adding readonly partition for romfs image:\n");
-			printk(pmsg, pidx, axis_partitions[pidx].offset,
-			       axis_partitions[pidx].size);
-			pidx++;
-		}
-
 		err = add_mtd_partitions(mymtd, axis_partitions, pidx);
 	}
-	if (!err && !romfs_in_flash) {
-#ifdef CONFIG_MTD_MTDRAM
-		/* Allocate, initialise and forget the mtd ram struct
-		 * when booting from RAM
-		 */
-		struct mtd_info *romfs_mtd = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
-		printk("MTD RAM device romfs_start: 0x%08lX len %lu\n",
-		       romfs_start, romfs_length);
 
-#if (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0)
-#error "You must set CONFIG_MTDRAM_TOTAL_SIZE and CONFIG_MTDRAM_ABS_POS to 0"
-#endif
-		err = mtdram_init_device(romfs_mtd, (void*)romfs_start, 
-		                         romfs_length, "romfs in RAM");
+	if (err) {
+		panic("axisflashmap could not add MTD partitions!\n");
+	}
+
+	if (!romfs_in_flash) {
+		/* Create an RAM device for the root partition (romfs). */
+
+#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0)
+		/* No use trying to boot this kernel from RAM. Panic! */
+		printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM "
+		       "device due to kernel (mis)configuration!\n");
+		panic("This kernel cannot boot from RAM!\n");
 #else
-#warning ######################################
-#warning # You must enable CONFIG_MTD_MTDRAM  #
-#warning # with TOTAL_SIZE 0 and ABS_POS 0 to # 
-#warning # be able to boot with cramfs in RAM #
-#warning ######################################
-/* Maybe overkill to save these bytes in non debug builds, but let's do it..
- * (No point in printing if we don't have a debug port anyway...)
- */
-#ifndef CONFIG_ETRAX_DEBUG_PORT_NULL
-		printk("## Can't mount romfs in RAM using MTDRAM.\n");
-		printk("## You must enable MTD_MTDRAM with TOTAL_SIZE 0 and ABS_POS 0\n");
+		struct mtd_info *mtd_ram;
+
+		mtd_ram = (struct mtd_info *)kmalloc(sizeof(struct mtd_info),
+						     GFP_KERNEL);
+		if (!mtd_ram) {
+			panic("axisflashmap couldn't allocate memory for "
+			      "mtd_info!\n");
+		}
+
+		printk(" Adding RAM partition for romfs image:\n");
+		printk(pmsg, pidx, romfs_start, romfs_length);
+
+		err = mtdram_init_device(mtd_ram, (void*)romfs_start, 
+		                         romfs_length, "romfs");
+		if (err) {
+			panic("axisflashmap could not initialize MTD RAM "
+			      "device!\n");
+		}
 #endif
-#endif /* CONFIG_MTD_MTDRAM */
 	}
+
 	return err;
 }
 
-/* This adds the above to the kernels init-call chain */
-
+/* This adds the above to the kernels init-call chain. */
 module_init(init_axis_flash);
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/bluetooth/Makefile linux-2.4.21/arch/cris/drivers/bluetooth/Makefile
--- linux-2.4.20/arch/cris/drivers/bluetooth/Makefile	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/arch/cris/drivers/bluetooth/Makefile	2002-12-18 18:58:10.000000000 +0000
@@ -1,19 +1,10 @@
-include $(APPS)/Rules.elinux
+include $(AXIS_TOP_DIR)/tools/build/Rules.axis
 
 all:
 
 install:	src/bluetooth.c include/btcommon.h
 	ln -sfn ../../arch/cris/drivers/bluetooth/include ../../../../include/linux/bluetooth
-	if ! grep arch/cris/drivers/bluetooth/src/Config.in ../Config.in; then \
-	  echo '' >> ../Config.in; \
-	  echo '# The following if statement was added by arch/cris/drivers/bluetooth/Makefile' >> ../Config.in; \
-	  echo 'if [ "$$CONFIG_ETRAX_SERIAL" = "y" ]; then' >> ../Config.in; \
-	  echo '  source arch/cris/drivers/bluetooth/src/Config.in' >> ../Config.in; \
-	  echo 'fi' >> ../Config.in; \
-	fi
-	if ! grep bluetooth/src/bt.o ../Makefile; then \
-	  perl -pi -e "s:include:\# The following two lines were added by arch/cris/drivers/bluetooth/Makefile\nobj-\\\$$(CONFIG_BLUETOOTH)                 += bluetooth/src/bt.o\nsubdir-\\\$$(CONFIG_BLUETOOTH)              += bluetooth/src\n\ninclude:" ../Makefile; \
-	fi
+	(cd .. && patch -N -r /tmp/bt.rej < bluetooth/bt.patch >/dev/null || true)
 
 clean:
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/bluetooth/bt.patch linux-2.4.21/arch/cris/drivers/bluetooth/bt.patch
--- linux-2.4.20/arch/cris/drivers/bluetooth/bt.patch	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/arch/cris/drivers/bluetooth/bt.patch	2002-12-18 18:58:03.000000000 +0000
@@ -0,0 +1,33 @@
+Index: Config.in
+===================================================================
+RCS file: /usr/local/cvs/linux/os/linux/arch/cris/drivers/Config.in,v
+retrieving revision 1.46
+diff -u -d -r1.46 Config.in
+--- Config.in	11 Oct 2002 16:14:33 -0000	1.46
++++ Config.in	31 Oct 2002 08:44:37 -0000
+@@ -317,3 +317,8 @@
+ fi
+ 
+ endmenu
++
++# The following if statement was added by arch/cris/drivers/bluetooth/Makefile
++if [ "$CONFIG_ETRAX_SERIAL" = "y" ]; then
++  source arch/cris/drivers/bluetooth/src/Config.in
++fi
+Index: Makefile
+===================================================================
+RCS file: /usr/local/cvs/linux/os/linux/arch/cris/drivers/Makefile,v
+retrieving revision 1.20
+diff -u -d -r1.20 Makefile
+--- Makefile	14 Aug 2002 18:32:33 -0000	1.20
++++ Makefile	31 Oct 2002 08:44:37 -0000
+@@ -24,5 +24,9 @@
+ obj-$(CONFIG_ETRAX_ETHERNET_LPSLAVE)    += lpslave/lpslavedrivers.o
+ subdir-$(CONFIG_ETRAX_ETHERNET_LPSLAVE) += lpslave
+ 
++# The following two lines were added by arch/cris/drivers/bluetooth/Makefile
++obj-$(CONFIG_BLUETOOTH)                 += bluetooth/src/bt.o
++subdir-$(CONFIG_BLUETOOTH)              += bluetooth/src
++
+ include $(TOPDIR)/Rules.make
+ 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/ds1302.c linux-2.4.21/arch/cris/drivers/ds1302.c
--- linux-2.4.20/arch/cris/drivers/ds1302.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/cris/drivers/ds1302.c	2002-12-18 18:58:11.000000000 +0000
@@ -7,6 +7,13 @@
 *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status
 *!
 *! $Log: ds1302.c,v $
+*! Revision 1.15  2002/10/11 16:14:33  johana
+*! Added CONFIG_ETRAX_DS1302_TRICKLE_CHARGE and initial setting of the
+*! trcklecharge register.
+*!
+*! Revision 1.14  2002/10/10 12:15:38  magnusmn
+*! Added support for having the RST signal on bit g0
+*!
 *! Revision 1.13  2002/05/29 15:16:08  johana
 *! Removed unused variables.
 *!
@@ -88,7 +95,7 @@
 *!
 *! (C) Copyright 1999, 2000, 2001  Axis Communications AB, LUND, SWEDEN
 *!
-*! $Id: ds1302.c,v 1.13 2002/05/29 15:16:08 johana Exp $
+*! $Id: ds1302.c,v 1.15 2002/10/11 16:14:33 johana Exp $
 *!
 *!***************************************************************************/
 
@@ -493,17 +500,25 @@
 { 
 	if (!ds1302_probe()) {
 #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
+#if CONFIG_ETRAX_DS1302_RSTBIT == 27
 		/*
 		 * The only way to set g27 to output is to enable ATA.
 		 *
 		 * Make sure that R_GEN_CONFIG is setup correct.
 		 */
     		genconfig_shadow = ((genconfig_shadow &
-				     ~IO_MASK(R_GEN_CONFIG, ata))
-				   | 
+				     ~IO_MASK(R_GEN_CONFIG, ata)) | 
 				   (IO_STATE(R_GEN_CONFIG, ata, select)));    
     		*R_GEN_CONFIG = genconfig_shadow;
-    		if (!ds1302_probe())
+#elif CONFIG_ETRAX_DS1302_RSTBIT == 0
+		
+		/* Set the direction of this bit to out. */		
+    		genconfig_shadow = ((genconfig_shadow &
+				     ~IO_MASK(R_GEN_CONFIG, g0dir)) | 
+				   (IO_STATE(R_GEN_CONFIG, g0dir, out)));    
+    		*R_GEN_CONFIG = genconfig_shadow;
+#endif
+		if (!ds1302_probe())
       			return -1;
 #else
     		return -1;
@@ -515,5 +530,8 @@
 		       ds1302_name, RTC_MAJOR_NR);
 		return -1;
 	}
+	/* Initialise trickle charger */
+	ds1302_writereg(RTC_TRICKLECHARGER,
+			RTC_TCR_PATTERN |(CONFIG_ETRAX_DS1302_TRICKLE_CHARGE & 0x0F));
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/ethernet.c linux-2.4.21/arch/cris/drivers/ethernet.c
--- linux-2.4.20/arch/cris/drivers/ethernet.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/arch/cris/drivers/ethernet.c	2002-12-18 18:58:08.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: ethernet.c,v 1.30 2002/05/07 18:50:08 johana Exp $
+/* $Id: ethernet.c,v 1.34 2002/12/13 07:17:44 starvik Exp $
  *
  * e100net.c: A network driver for the ETRAX 100LX network controller.
  *
@@ -7,6 +7,22 @@
  * The outline of this driver comes from skeleton.c.
  *
  * $Log: ethernet.c,v $
+ * Revision 1.34  2002/12/13 07:17:44  starvik
+ * Basic ethtool and MII ioctls
+ * Handle out of memory when allocating new buffers
+ *
+ * Revision 1.33  2002/10/02 20:16:17  hp
+ * SETF, SETS: Use underscored IO_x_ macros rather than incorrect token concatenation
+ *
+ * Revision 1.32  2002/09/16 06:05:58  starvik
+ * Align memory returned by dev_alloc_skb
+ * Moved handling of sent packets to interrupt to avoid reference counting problem
+ *
+ * Revision 1.31  2002/09/10 13:28:23  larsv
+ * Return -EINVAL for unknown ioctls to avoid confusing tools that tests
+ * for supported functionality by issuing special ioctls, i.e. wireless
+ * extensions.
+ *
  * Revision 1.30  2002/05/07 18:50:08  johana
  * Correct spelling in comments.
  *
@@ -152,9 +168,12 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 
+#include <linux/if.h>
+#include <linux/mii.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/ethtool.h>
 
 #include <asm/svinto.h>     /* DMA and register descriptions */
 #include <asm/io.h>         /* LED_* I/O functions */
@@ -163,6 +182,8 @@
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/ethernet.h>
+#include <asm/cache.h>
+#include <asm/uaccess.h>
 
 //#define ETHDEBUG
 #define D(x)
@@ -264,10 +285,10 @@
 #define GET_BIT(bit,val)   (((val) >> (bit)) & 0x01)
 
 /* Define some macros to access ETRAX 100 registers */
-#define SETF(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
-					  IO_FIELD(##reg##, field, val)
-#define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
-					  IO_STATE(##reg##, field, val)
+#define SETF(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_FIELD_(reg##_, field##_, val)
+#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_STATE_(reg##_, field##_, _##val)
 
 static etrax_eth_descr *myNextRxDesc;  /* Points to the next descriptor to
                                           to be processed */
@@ -304,12 +325,12 @@
 static int e100_open(struct net_device *dev);
 static int e100_set_mac_address(struct net_device *dev, void *addr);
 static int e100_send_packet(struct sk_buff *skb, struct net_device *dev);
-static void e100rx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void e100tx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void e100nw_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void e100_rx(struct net_device *dev);
 static int e100_close(struct net_device *dev);
 static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static int e100_ethtool_ioctl(struct net_device* dev, struct ifreq *ifr);
 static void e100_tx_timeout(struct net_device *dev);
 static struct net_device_stats *e100_get_stats(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
@@ -324,6 +345,7 @@
 static void e100_negotiate(void);
 
 static unsigned short e100_get_mdio_reg(unsigned char reg_num);
+static void e100_set_mdio_reg(unsigned char reg, unsigned short data);
 static void e100_send_mdio_cmd(unsigned short cmd, int write_cmd);
 static void e100_send_mdio_bit(unsigned char bit);
 static unsigned char e100_receive_mdio_bit(void);
@@ -399,11 +421,14 @@
 	/* Initialise receive descriptors */
 
 	for (i = 0; i < NBR_OF_RX_DESC; i++) {
-		RxDescList[i].skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE);
+		/* Allocate two extra cachelines to make sure that buffer used by DMA
+		 * does not share cacheline with any other data (to avoid cache bug)
+		 */
+		RxDescList[i].skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES);
 		RxDescList[i].descr.ctrl   = 0;
 		RxDescList[i].descr.sw_len = MAX_MEDIA_DATA_SIZE;
 		RxDescList[i].descr.next   = virt_to_phys(&RxDescList[i + 1]);
-		RxDescList[i].descr.buf    = virt_to_phys(RxDescList[i].skb->data);
+		RxDescList[i].descr.buf    = L1_CACHE_ALIGN(virt_to_phys(RxDescList[i].skb->data));
 		RxDescList[i].descr.status = 0;
 		RxDescList[i].descr.hw_len = 0;
              
@@ -540,14 +565,14 @@
 
 	/* allocate the irq corresponding to the receiving DMA */
 
-	if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rx_interrupt, 0,
+	if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt, 0,
 			cardname, (void *)dev)) {
 		goto grace_exit0;
 	}
 
 	/* allocate the irq corresponding to the transmitting DMA */
 
-	if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100tx_interrupt, 0,
+	if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100rxtx_interrupt, 0,
 			cardname, (void *)dev)) {
 		goto grace_exit1;
 	}
@@ -685,9 +710,7 @@
 static void
 e100_negotiate(void)
 {
-	unsigned short cmd;
 	unsigned short data = e100_get_mdio_reg(MDIO_ADVERTISMENT_REG);
-	int bitCounter;
 
 	/* Discard old speed and duplex settings */
 	data &= ~(MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | 
@@ -726,29 +749,13 @@
 			        MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD;
 	}
 
-	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) |
-	      (MDIO_ADVERTISMENT_REG<< 2);
-
-	e100_send_mdio_cmd(cmd, 1);
-
-	/* Data... */
-	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
-		e100_send_mdio_bit(GET_BIT(bitCounter, data));
-	}
+	e100_set_mdio_reg(MDIO_ADVERTISMENT_REG, data);
 
 	/* Renegotiate with link partner */
 	data = e100_get_mdio_reg(MDIO_BASE_CONTROL_REG);
 	data |= MDIO_BC_NEGOTIATE;
 
-	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) |
-	      (MDIO_BASE_CONTROL_REG<< 2);
-
-	e100_send_mdio_cmd(cmd, 1);
-
-	/* Data... */
-	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
-		e100_send_mdio_bit(GET_BIT(bitCounter, data));
-	}  
+	e100_set_mdio_reg(MDIO_BASE_CONTROL_REG, data);
 }
 
 static void
@@ -816,6 +823,24 @@
 }
 
 static void
+e100_set_mdio_reg(unsigned char reg, unsigned short data)
+{
+	int bitCounter;
+	unsigned short cmd;
+
+	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) |
+	      (reg << 2);
+
+	e100_send_mdio_cmd(cmd, 1);
+
+	/* Data... */
+	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
+		e100_send_mdio_bit(GET_BIT(bitCounter, data));
+	}
+
+}
+
+static void
 e100_send_mdio_cmd(unsigned short cmd, int write_cmd)
 {
 	int bitCounter;
@@ -958,21 +983,6 @@
 		*R_IRQ_MASK2_SET = IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set);
 		netif_stop_queue(dev);
 	}
-	else {
-	  /* Report any packets that have been sent */
-		while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&
-		       myFirstTxDesc != myNextTxDesc)
-		{
-			np->stats.tx_bytes += myFirstTxDesc->skb->len;
-			np->stats.tx_packets++;
-
-			/* dma is ready with the transmission of the data in tx_skb, so now
-			   we can release the skb memory */
-			dev_kfree_skb(myFirstTxDesc->skb);
-			myFirstTxDesc->skb = 0;
-			myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);				
-		}
-	}
 
 	spin_unlock_irq(&np->lock);
 
@@ -985,11 +995,13 @@
  */
 
 static void
-e100rx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct net_device *dev = (struct net_device *)dev_id;
+	struct net_local *np = (struct net_local *)dev->priv;
 	unsigned long irqbits = *R_IRQ_MASK2_RD;
  
+	/* Handle received packets */
 	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) {
 		/* acknowledge the eop interrupt */
 
@@ -1014,44 +1026,26 @@
 			   so we have to loop back and check if so */
 		}
 	}
-}
 
-/* the transmit dma channel interrupt
- *
- * this is supposed to free the skbuff which was pending during transmission,
- * and inform the kernel that we can send one more buffer
- */
+	/* Report any packets that have been sent */
+	while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&
+	       myFirstTxDesc != myNextTxDesc)
+	{
+		np->stats.tx_bytes += myFirstTxDesc->skb->len;
+		np->stats.tx_packets++;
 
-static void
-e100tx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
-	struct net_device *dev = (struct net_device *)dev_id;
-	unsigned long irqbits = *R_IRQ_MASK2_RD;
-	struct net_local *np = (struct net_local *)dev->priv;
+		/* dma is ready with the transmission of the data in tx_skb, so now
+		   we can release the skb memory */
+		dev_kfree_skb_irq(myFirstTxDesc->skb);
+		myFirstTxDesc->skb = 0;
+		myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
+	}
 
-	/* check for a dma0_eop interrupt */
 	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) {
-		/* Report all sent packets */
-		do {
-			/* acknowledge the eop interrupt */
-			*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
-
-			np->stats.tx_bytes += myFirstTxDesc->skb->len;
-			np->stats.tx_packets++;
-
-			/* dma is ready with the transmission of the data in tx_skb, so now
-			   we can release the skb memory */
-			dev_kfree_skb_irq(myFirstTxDesc->skb);
-			myFirstTxDesc->skb = 0;
-
-			if (netif_queue_stopped(dev)) {
-			  	/* Queue is running, disable tx IRQ */
-			  	*R_IRQ_MASK2_CLR = IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr);		
-				netif_wake_queue(dev);
-			}
-			myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
-		} while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&
-		         myFirstTxDesc != myNextTxDesc);
+		/* acknowledge the eop interrupt and wake up queue */
+		*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
+		*R_IRQ_MASK2_CLR = IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr);		
+		netif_wake_queue(dev);
 	}
 }
 
@@ -1140,11 +1134,24 @@
 		memcpy(skb_data_ptr, phys_to_virt(myNextRxDesc->descr.buf), length);
 	}
 	else {
-		/* Large packet, send directly to upper layers and allocate new memory */		 
+		/* Large packet, send directly to upper layers and allocate new 
+		 * memory (aligned to cache line boundary to avoid bug).
+		 * Before sending the skb to upper layers we must make sure that 
+		 * skb->data points to the aligned start of the packet. 
+		 */
+		int align;  
+		struct sk_buff *new_skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES);
+		if (!new_skb) {
+			np->stats.rx_errors++;
+			printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+			return;
+		}
 		skb = myNextRxDesc->skb;
-		skb_put(skb, length);
-		myNextRxDesc->skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE);
-		myNextRxDesc->descr.buf = virt_to_phys(myNextRxDesc->skb->data);
+		align = (int)phys_to_virt(myNextRxDesc->descr.buf) - (int)skb->data;	
+		skb_put(skb, length + align); 
+		skb_pull(skb, align); /* Remove alignment bytes */
+		myNextRxDesc->skb = new_skb;
+		myNextRxDesc->descr.buf = L1_CACHE_ALIGN(virt_to_phys(myNextRxDesc->skb->data));
 	}
 
 	skb->dev = dev;
@@ -1220,8 +1227,22 @@
 static int
 e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	/* Maybe default should return -EINVAL instead? */
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
+
 	switch (cmd) {
+		case SIOCETHTOOL:
+			return e100_ethtool_ioctl(dev,ifr);
+		case SIOCGMIIPHY: /* Get PHY address */
+			data->phy_id = MDIO_PHYS_ADDR;
+			break;
+		case SIOCGMIIREG: /* Read MII register */
+			data->val_out = e100_get_mdio_reg(data->reg_num);
+			break;
+		case SIOCSMIIREG: /* Write MII register */
+			e100_set_mdio_reg(data->reg_num, data->val_in);
+			break;
+		/* The ioctls below should be considered obsolete but are */
+		/* still present for compatability with old scripts/apps  */	
 		case SET_ETH_SPEED_10:                  /* 10 Mbps */
 			e100_set_speed(10);
 			break;
@@ -1240,10 +1261,90 @@
 		case SET_ETH_DUPLEX_AUTO:             /* Autonegotiate duplex*/
 			e100_set_duplex(autoneg);
 			break;
-		default: /* Auto neg */
-			e100_set_speed(0);
-			e100_set_duplex(autoneg);
-			break;
+		default:
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static int
+e100_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
+{
+	struct ethtool_cmd ecmd;
+
+	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd)))
+		return -EFAULT;
+
+	switch (ecmd.cmd) {
+		case ETHTOOL_GSET:
+		{
+			memset((void *) &ecmd, 0, sizeof (ecmd));
+			ecmd.supported = 
+			  SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |
+			  SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | 
+			  SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
+			ecmd.port = PORT_TP;
+			ecmd.transceiver = XCVR_EXTERNAL;
+			ecmd.phy_address = MDIO_PHYS_ADDR;
+			ecmd.speed = current_speed;
+			ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+			ecmd.advertising = ADVERTISED_TP;
+			if (current_duplex == autoneg && current_speed_selection == 0)
+				ecmd.advertising |= ADVERTISED_Autoneg;
+			else {
+				ecmd.advertising |= 
+				  ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+				  ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
+				if (current_speed_selection == 10)
+					ecmd.advertising &= ~(ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full);
+				else if (current_speed_selection == 100)
+					ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full);
+				if (current_duplex == half)
+					ecmd.advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Full);
+				else if (current_duplex == full)
+					ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half);
+			}
+			ecmd.autoneg = AUTONEG_ENABLE;
+			if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
+				return -EFAULT;
+		}
+		break;
+		case ETHTOOL_SSET:
+		{
+			if (!capable(CAP_NET_ADMIN)) {
+				return -EPERM;
+			}
+			if (ecmd.autoneg == AUTONEG_ENABLE) {
+				e100_set_duplex(autoneg);
+				e100_set_speed(0);
+			} else {
+				e100_set_duplex(ecmd.duplex == DUPLEX_HALF ? half : full);
+				e100_set_speed(ecmd.speed == SPEED_10 ? 10: 100);
+			}
+		}
+		break;
+		case ETHTOOL_GDRVINFO:
+		{
+			struct ethtool_drvinfo info;
+			memset((void *) &info, 0, sizeof (info));
+			strncpy(info.driver, "ETRAX 100LX", sizeof(info.driver) - 1);
+			strncpy(info.version, "$Rev$", sizeof(info.version) - 1);
+			strncpy(info.fw_version, "N/A", sizeof(info.fw_version) - 1);
+			strncpy(info.bus_info, "N/A", sizeof(info.bus_info) - 1);
+			info.regdump_len = 0;
+			info.eedump_len = 0;
+			info.testinfo_len = 0;
+			if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
+				return -EFAULT;
+		}
+		break;
+		case ETHTOOL_NWAY_RST:
+			if (current_duplex == autoneg && current_speed_selection == 0)
+				e100_negotiate();
+		break;
+		default:
+			return -EOPNOTSUPP;
+		break;
 	}
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/gpio.c linux-2.4.21/arch/cris/drivers/gpio.c
--- linux-2.4.20/arch/cris/drivers/gpio.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/cris/drivers/gpio.c	2002-12-18 18:58:01.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: gpio.c,v 1.17 2002/06/17 15:53:01 johana Exp $
+/* $Id: gpio.c,v 1.21 2002/12/02 08:11:41 starvik Exp $
  *
  * Etrax general port I/O device
  *
@@ -9,6 +9,29 @@
  *             Johan Adolfsson  (read/set directions, write, port G)
  *
  * $Log: gpio.c,v $
+ * Revision 1.21  2002/12/02 08:11:41  starvik
+ * Merge of Linux 2.4.20
+ *
+ * Revision 1.20  2002/10/16 21:16:24  johana
+ * Added support for PA high level interrupt.
+ * That gives 2ms response time with iodtest for high levels and 2-12 ms
+ * response time on low levels if the check is not made in
+ * process.c:cpu_idle() as well.
+ *
+ * Revision 1.19  2002/10/14 18:27:33  johana
+ * Implemented alarm handling so select() now works.
+ * Latency is around 6-9 ms with a etrax_gpio_wake_up_check() in
+ * cpu_idle().
+ * Otherwise I get 15-18 ms (same as doing the poll in userspace -
+ * but less overhead).
+ * TODO? Perhaps we should add the check in IMMEDIATE_BH (or whatever it
+ * is in 2.4) as well?
+ * TODO? Perhaps call request_irq()/free_irq() only when needed?
+ * Increased version to 2.5
+ *
+ * Revision 1.18  2002/10/11 15:02:00  johana
+ * Mask inverted 8 bit value in setget_input().
+ *
  * Revision 1.17  2002/06/17 15:53:01  johana
  * Added IO_READ_INBITS, IO_READ_OUTBITS, IO_SETGET_INPUT and IO_SETGET_OUTPUT
  * that take a pointer as argument and thus can handle 32 bit ports (G)
@@ -95,11 +118,19 @@
 #include <asm/svinto.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/irq.h>
 
 #define GPIO_MAJOR 120  /* experimental MAJOR number */
 
 #define D(x)
 
+#if 0
+static int dp_cnt;
+#define DP(x) do { dp_cnt++; if (dp_cnt % 1000 == 0) x; }while(0)
+#else
+#define DP(x)
+#endif
+	
 static char gpio_name[] = "etrax gpio";
 
 #if 0
@@ -137,6 +168,8 @@
 
 static struct gpio_private *alarmlist = 0;
 
+static int gpio_some_alarms = 0; /* Set if someone uses alarm */
+
 /* Port A and B use 8 bit access, but Port G is 32 bit */
 #define NUM_PORTS (GPIO_MINOR_B+1)
 
@@ -197,21 +230,81 @@
 
 
 static unsigned int 
-gpio_poll(struct file *filp,
-	  struct poll_table_struct *wait)
+gpio_poll(struct file *file,
+	  poll_table *wait)
 {
-	/* TODO poll on alarms! */
-#if 0
-	if (!ANYTHING_WANTED) {
-		D(printk("gpio_select sleeping task\n"));
-		select_wait(&gpio_wq, table);
+	unsigned int mask = 0;
+	struct gpio_private *priv = (struct gpio_private *)file->private_data;
+	unsigned long data;
+	poll_wait(file, &priv->alarm_wq, wait);
+	if (priv->minor == GPIO_MINOR_A) {
+		unsigned long tmp;
+		data = *R_PORT_PA_DATA;
+		/* PA has support for high level interrupt -
+		 * lets activate for those low and with highalarm set
+		 */
+		tmp = ~data & priv->highalarm & 0xFF;
+		*R_IRQ_MASK1_SET = (tmp << R_IRQ_MASK1_SET__pa0__BITNR);
+	} else if (priv->minor == GPIO_MINOR_B)
+		data = *R_PORT_PB_DATA;
+	else if (priv->minor == GPIO_MINOR_G)
+		data = *R_PORT_G_DATA;
+	else
 		return 0;
+	
+	if ((data & priv->highalarm) ||
+	    (~data & priv->lowalarm)) {
+		mask = POLLIN|POLLRDNORM;
+	}
+	
+	DP(printk("gpio_poll ready: mask 0x%08X\n", mask));
+	return mask;
+}
+
+void etrax_gpio_wake_up_check(void)
+{
+	struct gpio_private *priv = alarmlist;
+	unsigned long data = 0;
+	while (priv) {
+		if (USE_PORTS(priv)) {
+			data = *priv->port;
+		} else if (priv->minor == GPIO_MINOR_G) {
+			data = *R_PORT_G_DATA;
+		}
+		if ((data & priv->highalarm) ||
+		    (~data & priv->lowalarm)) {
+			DP(printk("etrax_gpio_wake_up_check %i\n",priv->minor));
+			wake_up_interruptible(&priv->alarm_wq);
+		}
+		priv = priv->next;
+	}
+}
+
+static void 
+gpio_poll_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	if (gpio_some_alarms) {
+		etrax_gpio_wake_up_check();
+	}
+}
+
+static void 
+gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long tmp;
+	/* Find what PA interrupts are active */
+	tmp = (*R_IRQ_READ1 >> R_IRQ_READ1__pa0__BITNR) & 0xFF;
+	/* Clear them.. */
+	/* NOTE: Maybe we need to be more careful here if some other
+	 * driver uses PA interrupt as well?
+	 */
+	*R_IRQ_MASK1_CLR = (tmp << R_IRQ_MASK1_CLR__pa0__BITNR);
+	if (gpio_some_alarms) {
+		etrax_gpio_wake_up_check();
 	}
-	D(printk("gpio_select ready\n"));
-#endif
-	return 1;
 }
 
+
 static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
                           loff_t *off)
 {
@@ -322,7 +415,7 @@
 {
 	struct gpio_private *p = alarmlist;
 	struct gpio_private *todel = (struct gpio_private *)filp->private_data;
-
+	
 	/* unlink from alarmlist and free the private structure */
 
 	if (p == todel) {
@@ -334,7 +427,17 @@
 	}
 
 	kfree(todel);
-
+	/* Check if there are still any alarms set */
+	p = alarmlist;
+	while (p) {
+		if (p->highalarm | p->lowalarm) {
+			gpio_some_alarms = 1;
+			return 0;
+		}
+		p = p->next;
+	}
+	gpio_some_alarms = 0;
+		
 	return 0;
 }
 
@@ -353,7 +456,7 @@
 		*priv->dir = *priv->dir_shadow &= 
 		~((unsigned char)arg & priv->changeable_dir);
 		restore_flags(flags);
-		return ~(*priv->dir_shadow);
+		return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */
 	} else if (priv->minor == GPIO_MINOR_G) {
 		/* We must fiddle with R_GEN_CONFIG to change dir */
 		if (((arg & dir_g_in_bits) != arg) && 
@@ -491,10 +594,12 @@
 	case IO_HIGHALARM:
 		// set alarm when bits with 1 in arg go high
 		priv->highalarm |= arg;
+		gpio_some_alarms = 1;
 		break;
 	case IO_LOWALARM:
 		// set alarm when bits with 1 in arg go low
 		priv->lowalarm |= arg;
+		gpio_some_alarms = 1;
 		break;
 	case IO_CLRALARM:
 		// clear alarm for bits with 1 in arg
@@ -760,8 +865,21 @@
 
 #endif
 	gpio_init_port_g();
-	printk("ETRAX 100LX GPIO driver v2.4, (c) 2001, 2002 Axis Communications AB\n");
-
+	printk("ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002 Axis Communications AB\n");
+	/* We call etrax_gpio_wake_up_check() from timer interrupt and
+	 * from cpu_idle() in kernel/process.c
+	 * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms
+	 * in some tests.
+	 */  
+	if (request_irq(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt,
+			SA_SHIRQ | SA_INTERRUPT,"gpio poll", NULL)) {
+		printk("err: timer0 irq for gpio\n");
+	}
+	if (request_irq(PA_IRQ_NBR, gpio_pa_interrupt,
+			SA_SHIRQ | SA_INTERRUPT,"gpio PA", NULL)) {
+		printk("err: PA irq for gpio\n");
+	}
+	
 	return res;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/i2c.c linux-2.4.21/arch/cris/drivers/i2c.c
--- linux-2.4.20/arch/cris/drivers/i2c.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/cris/drivers/i2c.c	2002-12-18 18:58:02.000000000 +0000
@@ -12,6 +12,12 @@
 *!                                 don't use PB_I2C if DS1302 uses same bits,
 *!                                 use PB.
 *! $Log: i2c.c,v $
+*! Revision 1.9  2002/10/31 15:32:26  starvik
+*! Update Port B register and shadow even when running with hardware support
+*!   to avoid glitches when reading bits
+*! Never set direction to out in i2c_inbyte
+*! Removed incorrect clock togling at end of i2c_inbyte
+*!
 *! Revision 1.8  2002/08/13 06:31:53  starvik
 *! Made SDA and SCL line configurable
 *! Modified i2c_inbyte to work with PCF8563
@@ -47,7 +53,7 @@
 *! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN
 *!
 *!***************************************************************************/
-/* $Id: i2c.c,v 1.8 2002/08/13 06:31:53 starvik Exp $ */
+/* $Id: i2c.c,v 1.9 2002/10/31 15:32:26 starvik Exp $ */
 /****************** INCLUDE FILES SECTION ***********************************/
 
 #include <linux/module.h>
@@ -135,16 +141,24 @@
 
 /* enable or disable output-enable, to select output or input on the i2c bus */
 
-#define i2c_dir_out() *R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_oe_))
-#define i2c_dir_in() *R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_oe_))
+#define i2c_dir_out() \
+	*R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_oe_)); \
+	REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, 0, 1); 
+#define i2c_dir_in() \
+	*R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_oe_)); \
+	REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, 0, 0);
 
 /* control the i2c clock and data signals */
 
-#define i2c_clk(x) *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
-       ~IO_MASK(R_PORT_PB_I2C, i2c_clk)) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, (x)))
+#define i2c_clk(x) \
+	*R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
+       ~IO_MASK(R_PORT_PB_I2C, i2c_clk)) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, (x))); \
+       REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 1, x);
 
-#define i2c_data(x) *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
-       ~IO_MASK(R_PORT_PB_I2C, i2c_d)) | IO_FIELD(R_PORT_PB_I2C, i2c_d, (x)))
+#define i2c_data(x) \
+	*R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
+	   ~IO_MASK(R_PORT_PB_I2C, i2c_d)) | IO_FIELD(R_PORT_PB_I2C, i2c_d, (x))); \
+	REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 0, x);
 
 /* read a bit from the i2c interface */
 
@@ -221,10 +235,11 @@
 	i2c_dir_out();
 
 	for (i = 0; i < 8; i++) {
-		if (x & 0x80)
+		if (x & 0x80) {
 			i2c_data(I2C_DATA_HIGH);
-		else
+		} else {
 			i2c_data(I2C_DATA_LOW);
+		}
 		
 		i2c_delay(CLOCK_LOW_TIME/2);
 		i2c_clk(I2C_CLOCK_HIGH);
@@ -260,7 +275,6 @@
 
 	/* Enable I2C */
 	i2c_enable();
-	i2c_dir_out();
 	i2c_delay(CLOCK_LOW_TIME/2);
 
 	for (i = 1; i < 8; i++) {
@@ -281,12 +295,10 @@
 
 		/* Enable I2C */
 		i2c_enable();
-		i2c_dir_out();
 		i2c_delay(CLOCK_LOW_TIME/2);
 	}
 	i2c_clk(I2C_CLOCK_HIGH);
 	i2c_delay(CLOCK_HIGH_TIME);
-	i2c_clk(I2C_CLOCK_LOW);
 	return aBitByte;
 }
 
@@ -416,7 +428,7 @@
 {
 	int error, cntr = 3;
 	unsigned long flags;
-		
+
 	do {
 		error = 0;
 		/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/ide.c linux-2.4.21/arch/cris/drivers/ide.c
--- linux-2.4.20/arch/cris/drivers/ide.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/arch/cris/drivers/ide.c	2002-12-18 18:58:04.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: ide.c,v 1.24 2002/04/22 11:47:21 johana Exp $
+/* $Id: ide.c,v 1.26 2002/09/17 12:16:59 bjornw Exp $
  *
  * Etrax specific IDE functions, like init and PIO-mode setting etc.
  * Almost the entire ide.c is used for the rest of the Etrax ATA driver.
@@ -8,6 +8,12 @@
  *             Mikael Starvik     (pio setup stuff)
  *
  * $Log: ide.c,v $
+ * Revision 1.26  2002/09/17 12:16:59  bjornw
+ * Removed unnecessary cli/sti pair
+ *
+ * Revision 1.25  2002/08/19 08:07:19  matsfg
+ * Added IN_WORD.
+ *
  * Revision 1.24  2002/04/22 11:47:21  johana
  * Fix according to 2.4.19-pre7. time_after/time_before and
  * missing end of comment.
@@ -180,9 +186,14 @@
 			    IO_MASK(R_ATA_STATUS_DATA, tr_rdy)))
 		timeleft--;
 }
-
 unsigned char 
 IN_BYTE(ide_ioreg_t reg) {
+        /* data was in the lower 16 bits in the status reg */
+        return (unsigned char)(IN_WORD(reg));
+}
+
+unsigned short 
+IN_WORD(ide_ioreg_t reg) {
 	int status;
 	int timeleft;
 
@@ -226,7 +237,7 @@
 
 	LOWDB(printk("inb: 0x%x from reg 0x%x\n", status & 0xff, reg));
 
-	return (unsigned char)status; /* data was in the lower 16 bits in the status reg */
+        return (unsigned short)status;
 }
 
 /* PIO timing (in R_ATA_CONFIG)
@@ -303,9 +314,6 @@
 	pio = 4;
 	/* pio = ide_get_best_pio_mode(drive, pio, 4, NULL); */
 	
-	save_flags(flags);
-	cli();
-
 	/* set pio mode! */
   	 
 	switch(pio) {
@@ -350,7 +358,6 @@
 					  IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO4_HOLD ) );
 			break;
 	}
-	restore_flags(flags);
 }
 
 void __init 
@@ -816,13 +823,13 @@
 			rq = HWGROUP(drive)->rq;
 			for (i = rq->nr_sectors; i > 0;) {
 				i -= rq->current_nr_sectors;
-				ide_end_request(1, HWGROUP(drive));
+				DRIVER(drive)->end_request(drive, 1);
 			}
 			return ide_stopped;
 		}
 		printk("%s: bad DMA status\n", drive->name);
 	}
-	return ide_error(drive, "dma_intr", stat);
+	return DRIVER(drive)->error(drive, "dma_intr", stat);
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/parport.c linux-2.4.21/arch/cris/drivers/parport.c
--- linux-2.4.20/arch/cris/drivers/parport.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/arch/cris/drivers/parport.c	2002-12-18 18:58:02.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: parport.c,v 1.9 2002/05/15 12:30:24 starvik Exp $
+/* $Id: parport.c,v 1.10 2002/10/03 05:54:24 starvik Exp $
  * 
  * Elinux parallel port driver
  * NOTE!
@@ -56,11 +56,11 @@
 //#define CONFIG_PAR0_INT 1
 //#define CONFIG_PAR1_INT 1
 
-#define SETF(var, reg, field, val) \
-	var = (var & ~IO_MASK(##reg##, field)) | IO_FIELD(##reg##, field, val)
-
-#define SETS(var, reg, field, val) \
-	var = (var & ~IO_MASK(##reg##, field)) | IO_STATE(##reg##, field, val)
+/* Define some macros to access ETRAX 100 registers */
+#define SETF(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_FIELD_(reg##_, field##_, val)
+#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_STATE_(reg##_, field##_, _##val)
 
 struct etrax100par_struct {
 	/* parallell port control */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/pcf8563.c linux-2.4.21/arch/cris/drivers/pcf8563.c
--- linux-2.4.20/arch/cris/drivers/pcf8563.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/cris/drivers/pcf8563.c	2002-12-18 18:58:09.000000000 +0000
@@ -15,7 +15,7 @@
  *
  * Author: Tobias Anderberg <tobiasa@axis.com>.
  *
- * $Id: pcf8563.c,v 1.1 2002/08/12 13:46:02 starvik Exp $
+ * $Id: pcf8563.c,v 1.4 2002/10/15 09:22:42 tobiasa Exp $
  */
 
 #include <linux/config.h>
@@ -39,7 +39,11 @@
 #define PCF8563_MAJOR 121		/* Local major number. */
 #define DEVICE_NAME "rtc"		/* Name which is registered in /proc/devices. */
 #define PCF8563_NAME "PCF8563"
-#define DRIVER_VERSION "$Rev$"
+#define DRIVER_VERSION "$Revision: 1.4 $"
+
+/* I2C bus slave registers. */
+#define RTC_I2C_READ		0xa3
+#define RTC_I2C_WRITE		0xa2
 
 /* Two simple wrapper macros, saves a few keystrokes. */
 #define rtc_read(x) i2c_readreg(RTC_I2C_READ, x)
@@ -59,11 +63,38 @@
 	release: pcf8563_release,
 };
 
+unsigned char
+pcf8563_readreg(int reg) 
+{
+	unsigned char res = i2c_readreg(RTC_I2C_READ, reg);
+
+	/* The PCF8563 does not return 0 for unimplemented bits */
+	switch(reg)
+	{
+		case RTC_SECONDS:
+		case RTC_MINUTES:
+		     res &= 0x7f;
+		     break;
+		case RTC_HOURS:
+		case RTC_DAY_OF_MONTH:
+		     res &= 0x3f;
+		     break;
+		case RTC_MONTH:
+		     res = (res & 0x1f) - 1;  /* PCF8563 returns month in range 1-12 */
+		     break;
+	}
+	return res;
+}
+
+void
+pcf8563_writereg(int reg, unsigned char val) 
+{
+	i2c_writereg(RTC_I2C_WRITE,reg,val);
+}
+
 void
 get_rtc_time(struct rtc_time *tm)
 {
-	unsigned long flags;
-	
 	tm->tm_sec = rtc_read(RTC_SECONDS);
 	tm->tm_min = rtc_read(RTC_MINUTES);
 	tm->tm_hour = rtc_read(RTC_HOURS);
@@ -74,7 +105,7 @@
 	if (tm->tm_sec & 0x80)
 		printk(KERN_WARNING "%s: RTC Low Voltage - date/time is not reliable!\n", PCF8563_NAME);
 
-        tm->tm_year = BCD_TO_BIN(tm->tm_year) + ((tm->tm_mon & 0x80) ? 100 : 0);
+	tm->tm_year = BCD_TO_BIN(tm->tm_year) + ((tm->tm_mon & 0x80) ? 100 : 0);
 	tm->tm_sec &= 0x7f;
 	tm->tm_min &= 0x7f;
 	tm->tm_hour &= 0x3f;
@@ -93,8 +124,6 @@
 pcf8563_init(void)
 {
 	unsigned char ret;
-        struct rtc_time tm;
-        
 	/*
 	 * First of all we need to reset the chip. This is done by
 	 * clearing control1, control2 and clk freq, clear the 
@@ -134,7 +163,7 @@
 		return -1;
 	}
 
-	printk(KERN_INFO "%s Real-Time Driver, %s\n", PCF8563_NAME, DRIVER_VERSION);
+	printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME, DRIVER_VERSION);
         
 	/* Check for low voltage, and warn about it.. */
 	if (rtc_read(RTC_SECONDS) & 0x80)
@@ -163,7 +192,7 @@
 pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
 {
 	/* Some sanity checks. */
-	if (_IOC_TYPE(cmd) != PCF8563_MAGIC)
+	if (_IOC_TYPE(cmd) != RTC_MAGIC)
 		return -ENOTTY;
 
 	if (_IOC_NR(cmd) > RTC_MAX_IOCTL)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/serial.c linux-2.4.21/arch/cris/drivers/serial.c
--- linux-2.4.20/arch/cris/drivers/serial.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/cris/drivers/serial.c	2002-12-18 18:58:03.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: serial.c,v 1.37 2002/08/13 13:02:37 bjornw Exp $
+/* $Id: serial.c,v 1.44 2002/11/21 04:28:06 hp Exp $
  *
  * Serial port driver for the ETRAX 100LX chip
  *
@@ -7,6 +7,42 @@
  *      Many, many authors. Based once upon a time on serial.c for 16x50.
  *
  * $Log: serial.c,v $
+ * Revision 1.44  2002/11/21 04:28:06  hp
+ * Change static inline to extern inline where otherwise outlined with gcc-3.2
+ *
+ * Revision 1.43  2002/11/15 12:02:25  pkj
+ * Make sure we have a tty in flush_to_flip_buffer() before we
+ * try to use it...
+ *
+ * Revision 1.42  2002/11/05 09:08:47  johana
+ * Better implementation of rs_stop() and rs_start() that uses the XOFF
+ * register to start/stop transmission.
+ * change_speed() also initilises XOFF register correctly so that
+ * auto_xoff is enabled when IXON flag is set by user.
+ * This gives fast XOFF response times.
+ *
+ * Revision 1.41  2002/11/04 18:40:57  johana
+ * Implemented rs_stop() and rs_start().
+ * Simple tests using hwtestserial indicates that this should be enough
+ * to make it work.
+ *
+ * Revision 1.40  2002/10/14 05:33:18  starvik
+ * RS-485 uses fast timers even if SERIAL_FAST_TIMER is disabled
+ *
+ * Revision 1.39  2002/09/30 21:00:57  johana
+ * Support for CONFIG_ETRAX_SERx_DTR_RI_DSR_CD_MIXED where the status and
+ * control pins can be mixed between PA and PB.
+ * If no serial port uses MIXED old solution is used
+ * (saves a few bytes and cycles).
+ * control_pins struct uses masks instead of bit numbers.
+ * Corrected dummy values and polarity in line_info() so
+ * /proc/tty/driver/serial is now correct.
+ * (the E100_xxx_GET() macros is really active low - perhaps not obvious)
+ *
+ * Revision 1.38  2002/08/23 11:01:36  starvik
+ * Check that serial port is enabled in all interrupt handlers to avoid
+ * restarts of DMA channels not assigned to serial ports
+ *
  * Revision 1.37  2002/08/13 13:02:37  bjornw
  * Removed some warnings because of unused code
  *
@@ -321,7 +357,7 @@
  *
  */
 
-static char *serial_version = "$Revision: 1.37 $";
+static char *serial_version = "$Revision: 1.44 $";
 
 #include <linux/config.h>
 #include <linux/version.h>
@@ -429,7 +465,7 @@
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
 static int rs_write(struct tty_struct * tty, int from_user,
                     const unsigned char *buf, int count);
-static inline int raw_write(struct tty_struct * tty, int from_user,
+extern inline int raw_write(struct tty_struct * tty, int from_user,
                             const unsigned char *buf, int count);
 #ifdef CONFIG_ETRAX_RS485
 static int e100_write_rs485(struct tty_struct * tty, int from_user,
@@ -585,87 +621,214 @@
 static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT;
 #endif
 #endif
-  
 
-/* For now we assume that all bits are on the same port for each serial port */
+/* Info and macros needed for each ports extra control/status signals. */
+#define E100_STRUCT_PORT(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+		(R_PORT_PA_DATA): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+		(R_PORT_PB_DATA):&dummy_ser[##line##]))
+
+#define E100_STRUCT_SHADOW(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+		(&port_pa_data_shadow): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+		(&port_pb_data_shadow):&dummy_ser[line]))
+#define E100_STRUCT_MASK(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+		(1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+		(1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT):DUMMY_##pinname##_MASK))
+
+#define DUMMY_DTR_MASK 1
+#define DUMMY_RI_MASK  2
+#define DUMMY_DSR_MASK 4
+#define DUMMY_CD_MASK  8
+static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF};
+
+#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED)
+#define CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
+#endif
+
+#ifdef CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
+/* The pins can be mixed on PA and PB */
+#define CONTROL_PINS_PORT_NOT_USED(line) \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
+    
 
-/* Dummy shadow variables */
-#if !defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB)
-static unsigned char dummy_ser0 = 0x00;
-static unsigned char dummy_dir_ser0 = 0x00;
-#endif
-#if !defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB)
-static unsigned char dummy_ser1 = 0x00;
-static unsigned char dummy_dir_ser1 = 0x00;
-#endif
-#if !defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA)
-static unsigned char dummy_ser2 = 0x00;
-static unsigned char dummy_dir_ser2 = 0x00;
-#endif
+struct control_pins
+{
+	volatile unsigned char *dtr_port;
+	unsigned char          *dtr_shadow;
+	volatile unsigned char *ri_port;
+	unsigned char          *ri_shadow;
+	volatile unsigned char *dsr_port;
+	unsigned char          *dsr_shadow;
+	volatile unsigned char *cd_port;
+	unsigned char          *cd_shadow;
+
+	unsigned char dtr_mask;
+	unsigned char ri_mask;
+	unsigned char dsr_mask;
+	unsigned char cd_mask;
+};
+
+static const struct control_pins e100_modem_pins[NR_PORTS] = 
+{
+	/* Ser 0 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+	E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
+	E100_STRUCT_PORT(0,RI),  E100_STRUCT_SHADOW(0,RI),
+	E100_STRUCT_PORT(0,DSR), E100_STRUCT_SHADOW(0,DSR),
+	E100_STRUCT_PORT(0,CD),  E100_STRUCT_SHADOW(0,CD),
+	E100_STRUCT_MASK(0,DTR),
+	E100_STRUCT_MASK(0,RI),
+	E100_STRUCT_MASK(0,DSR),
+	E100_STRUCT_MASK(0,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(0)
+#endif	
+	},
+
+	/* Ser 1 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT1	  
+	E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
+	E100_STRUCT_PORT(1,RI),  E100_STRUCT_SHADOW(1,RI),
+	E100_STRUCT_PORT(1,DSR), E100_STRUCT_SHADOW(1,DSR),
+	E100_STRUCT_PORT(1,CD),  E100_STRUCT_SHADOW(1,CD),
+	E100_STRUCT_MASK(1,DTR),
+	E100_STRUCT_MASK(1,RI),
+	E100_STRUCT_MASK(1,DSR),
+	E100_STRUCT_MASK(1,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(1)
+#endif		
+	},
 
-static unsigned char dummy_ser3 = 0x00;
-static unsigned char dummy_dir_ser3 = 0x00;
+	/* Ser 2 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT2	  
+	E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
+	E100_STRUCT_PORT(2,RI),  E100_STRUCT_SHADOW(2,RI),
+	E100_STRUCT_PORT(2,DSR), E100_STRUCT_SHADOW(2,DSR),
+	E100_STRUCT_PORT(2,CD),  E100_STRUCT_SHADOW(2,CD),
+	E100_STRUCT_MASK(2,DTR),
+	E100_STRUCT_MASK(2,RI),
+	E100_STRUCT_MASK(2,DSR),
+	E100_STRUCT_MASK(2,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(2)
+#endif		
+	},
+
+	/* Ser 3 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT3	  
+	E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
+	E100_STRUCT_PORT(3,RI),  E100_STRUCT_SHADOW(3,RI),
+	E100_STRUCT_PORT(3,DSR), E100_STRUCT_SHADOW(3,DSR),
+	E100_STRUCT_PORT(3,CD),  E100_STRUCT_SHADOW(3,CD),
+	E100_STRUCT_MASK(3,DTR),
+	E100_STRUCT_MASK(3,RI),
+	E100_STRUCT_MASK(3,DSR),
+	E100_STRUCT_MASK(3,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(3)
+#endif		
+	}
+};
+#else  /* CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
+
+/* All pins are on either PA or PB for each serial port */
+#define CONTROL_PINS_PORT_NOT_USED(line) \
+  &dummy_ser[line], &dummy_ser[line], \
+  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
+    
 
-/* Info needed for each ports extra control/status signals.
-   We only supports that all pins uses same register for each port */
 struct control_pins
 {
 	volatile unsigned char *port;
-	volatile unsigned char *shadow;
-	volatile unsigned char *dir_shadow;
+	unsigned char          *shadow;
 
-	unsigned char dtr_bit;
-	unsigned char ri_bit;
-	unsigned char dsr_bit;
-	unsigned char cd_bit;
+	unsigned char dtr_mask;
+	unsigned char ri_mask;
+	unsigned char dsr_mask;
+	unsigned char cd_mask;
 };
 
+#define dtr_port port
+#define dtr_shadow shadow
+#define ri_port port
+#define ri_shadow shadow
+#define dsr_port port
+#define dsr_shadow shadow
+#define cd_port port
+#define cd_shadow shadow
+
 static const struct control_pins e100_modem_pins[NR_PORTS] = 
 {
 	/* Ser 0 */
 	{
-#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB)
-		R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow,
-		CONFIG_ETRAX_SER0_DTR_ON_PB_BIT,
-		CONFIG_ETRAX_SER0_RI_ON_PB_BIT,
-		CONFIG_ETRAX_SER0_DSR_ON_PB_BIT,
-		CONFIG_ETRAX_SER0_CD_ON_PB_BIT
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+	E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
+	E100_STRUCT_MASK(0,DTR),
+	E100_STRUCT_MASK(0,RI),
+	E100_STRUCT_MASK(0,DSR),
+	E100_STRUCT_MASK(0,CD)
 #else
-		&dummy_ser0, &dummy_ser0, &dummy_dir_ser0, 0, 1, 2, 3
-#endif
+	CONTROL_PINS_PORT_NOT_USED(0)
+#endif	
 	},
 
 	/* Ser 1 */
 	{
-#if defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB)
-		R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow,
-		CONFIG_ETRAX_SER1_DTR_ON_PB_BIT,
-		CONFIG_ETRAX_SER1_RI_ON_PB_BIT,
-		CONFIG_ETRAX_SER1_DSR_ON_PB_BIT,
-		CONFIG_ETRAX_SER1_CD_ON_PB_BIT
+#ifdef CONFIG_ETRAX_SERIAL_PORT1	  
+	E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
+	E100_STRUCT_MASK(1,DTR),
+	E100_STRUCT_MASK(1,RI),
+	E100_STRUCT_MASK(1,DSR),
+	E100_STRUCT_MASK(1,CD)
 #else
-		&dummy_ser1, &dummy_ser1, &dummy_dir_ser1, 0, 1, 2, 3
-#endif
+	CONTROL_PINS_PORT_NOT_USED(1)
+#endif		
 	},
 
 	/* Ser 2 */
 	{
-#if defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA)
-		R_PORT_PA_DATA, &port_pa_data_shadow, &port_pa_dir_shadow,
-		CONFIG_ETRAX_SER2_DTR_ON_PA_BIT,
-		CONFIG_ETRAX_SER2_RI_ON_PA_BIT,
-		CONFIG_ETRAX_SER2_DSR_ON_PA_BIT,
-		CONFIG_ETRAX_SER2_CD_ON_PA_BIT
+#ifdef CONFIG_ETRAX_SERIAL_PORT2	  
+	E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
+	E100_STRUCT_MASK(2,DTR),
+	E100_STRUCT_MASK(2,RI),
+	E100_STRUCT_MASK(2,DSR),
+	E100_STRUCT_MASK(2,CD)
 #else
-		&dummy_ser2, &dummy_ser2, &dummy_dir_ser2, 0, 1, 2, 3
-#endif
+	CONTROL_PINS_PORT_NOT_USED(2)
+#endif		
 	},
 
 	/* Ser 3 */
 	{
-		&dummy_ser3, &dummy_ser3, &dummy_dir_ser3, 0, 1, 2, 3
+#ifdef CONFIG_ETRAX_SERIAL_PORT3	  
+	E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
+	E100_STRUCT_MASK(3,DTR),
+	E100_STRUCT_MASK(3,RI),
+	E100_STRUCT_MASK(3,DSR),
+	E100_STRUCT_MASK(3,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(3)
+#endif		
 	}
 };
+#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
 
 #if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_RS485_ON_PA)
 unsigned char rs485_pa_port = CONFIG_ETRAX_RS485_ON_PA_BIT;
@@ -690,20 +853,16 @@
 
 /* These are typically PA or PB and 0 means 0V, 1 means 3.3V */
 /* Is an output */
-#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].shadow) & (1 << e100_modem_pins[(info)->line].dtr_bit))
+#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].dtr_shadow) & e100_modem_pins[(info)->line].dtr_mask)
 
 /* Normally inputs */
-#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].ri_bit))
-#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].cd_bit))
+#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].ri_port) & e100_modem_pins[(info)->line].ri_mask)
+#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].cd_port) & e100_modem_pins[(info)->line].cd_mask)
 
 /* Input */
-#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].dsr_bit))
+#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask)
 
 
-#ifndef MIN
-#define MIN(a,b)	((a) < (b) ? (a) : (b))
-#endif
-
 /*
  * tmp_buf is used as a temporary buffer by serial_write.  We need to
  * lock it in case the memcpy_fromfs blocks while swapping in a page,
@@ -837,16 +996,17 @@
  * any general port.
  */
 
+
 static inline void 
 e100_dtr(struct e100_serial *info, int set)
 {
 #ifndef CONFIG_SVINTO_SIM
-	unsigned char mask = (1 << e100_modem_pins[info->line].dtr_bit);
+	unsigned char mask = e100_modem_pins[info->line].dtr_mask;
 
 #ifdef SERIAL_DEBUG_IO  
 	printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask);
 	printk("ser%i shadow before 0x%02X get: %i\n", 
-	       info->line, *e100_modem_pins[info->line].shadow,
+	       info->line, *e100_modem_pins[info->line].dtr_shadow,
 	       E100_DTR_GET(info));
 #endif
 	/* DTR is active low */
@@ -855,20 +1015,15 @@
 
 		save_flags(flags);
 		cli();
-		*e100_modem_pins[info->line].shadow &= ~mask;
-		*e100_modem_pins[info->line].shadow |= (set ? 0 : mask); 
-		*e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow;
+		*e100_modem_pins[info->line].dtr_shadow &= ~mask;
+		*e100_modem_pins[info->line].dtr_shadow |= (set ? 0 : mask); 
+		*e100_modem_pins[info->line].dtr_port = *e100_modem_pins[info->line].dtr_shadow;
 		restore_flags(flags);
 	}
 	
-#if 0
-	REG_SHADOW_SET(e100_modem_pins[info->line].port,
-		       *e100_modem_pins[info->line].shadow,
-		       e100_modem_pins[info->line].dtr_bit, !set);
-#endif
 #ifdef SERIAL_DEBUG_IO
 	printk("ser%i shadow after 0x%02X get: %i\n", 
-	       info->line, *e100_modem_pins[info->line].shadow, 
+	       info->line, *e100_modem_pins[info->line].dtr_shadow, 
 	       E100_DTR_GET(info));
 #endif
 #endif
@@ -890,6 +1045,7 @@
 #endif
 }
 
+
 /* If this behaves as a modem, RI and CD is an output */
 static inline void 
 e100_ri_out(struct e100_serial *info, int set)
@@ -897,14 +1053,14 @@
 #ifndef CONFIG_SVINTO_SIM
 	/* RI is active low */
 	{
-		unsigned char mask = (1 << e100_modem_pins[info->line].ri_bit);
+		unsigned char mask = e100_modem_pins[info->line].ri_mask;
 		unsigned long flags;
 
 		save_flags(flags);
 		cli();
-		*e100_modem_pins[info->line].shadow &= ~mask;
-		*e100_modem_pins[info->line].shadow |= (set ? 0 : mask); 
-		*e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow;
+		*e100_modem_pins[info->line].ri_shadow &= ~mask;
+		*e100_modem_pins[info->line].ri_shadow |= (set ? 0 : mask); 
+		*e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow;
 		restore_flags(flags);
 	}
 #endif
@@ -915,14 +1071,14 @@
 #ifndef CONFIG_SVINTO_SIM
 	/* CD is active low */
 	{
-		unsigned char mask = (1 << e100_modem_pins[info->line].cd_bit);
+		unsigned char mask = e100_modem_pins[info->line].cd_mask;
 		unsigned long flags;
 
 		save_flags(flags);
 		cli();
-		*e100_modem_pins[info->line].shadow &= ~mask;
-		*e100_modem_pins[info->line].shadow |= (set ? 0 : mask); 
-		*e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow;
+		*e100_modem_pins[info->line].cd_shadow &= ~mask;
+		*e100_modem_pins[info->line].cd_shadow |= (set ? 0 : mask); 
+		*e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow;
 		restore_flags(flags);
 	}
 #endif
@@ -1078,23 +1234,49 @@
  * rs_stop() and rs_start()
  *
  * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
+ * They enable or disable transmitter using the XOFF registers, as necessary.
  * ------------------------------------------------------------
  */
 
-/* FIXME - when are these used and what is the purpose ? 
- * In rs_stop we probably just can block the transmit DMA ready irq
- * and in rs_start we re-enable it (and then the old one will come).
- */
-
 static void 
 rs_stop(struct tty_struct *tty)
 {
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+	if (info) {
+		unsigned long flags;
+		unsigned long xoff;
+		
+		save_flags(flags); cli();
+		xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty));
+		xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
+		if (tty->termios->c_iflag & IXON ) {
+			xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+		}
+	
+		*((unsigned long *)&info->port[REG_XOFF]) = xoff;
+		restore_flags(flags);
+	}
 }
 
 static void 
 rs_start(struct tty_struct *tty)
 {
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+	if (info) {
+		unsigned long flags;
+		unsigned long xoff;
+
+		save_flags(flags); cli();
+		xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));
+		xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
+		if (tty->termios->c_iflag & IXON ) {
+			xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+		}
+	
+		*((unsigned long *)&info->port[REG_XOFF]) = xoff;
+		
+		restore_flags(flags);
+	}
 }
 
 /*
@@ -1341,7 +1523,7 @@
 	return 1;
 }
 
-static _INLINE_ unsigned int
+extern _INLINE_ unsigned int
 handle_descr_data(struct e100_serial *info, struct etrax_dma_descr *descr, unsigned int recvl)
 {
 	struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer;
@@ -1567,7 +1749,7 @@
 	
 	for (i = 0; i < NR_PORTS; i++) {
 		info = rs_table + i;
-		if (!info->uses_dma) 
+		if (!info->enabled || !info->uses_dma) 
 			continue; 
 		/* check for dma_descr (don't need to check for dma_eop in output dma for serial */
 		if (ireg & info->irq) {  
@@ -1613,7 +1795,7 @@
 	
 	for (i = 0; i < NR_PORTS; i++) {
 		info = rs_table + i;
-		if (!info->uses_dma) 
+		if (!info->enabled || !info->uses_dma) 
 			continue; 
 		/* check for both dma_eop and dma_descr for the input dma channel */
 		if (ireg & ((info->irq << 2) | (info->irq << 3))) {
@@ -1671,10 +1853,10 @@
 	return 1;
 }
 
-static _INLINE_ void
+extern _INLINE_ void
 flush_to_flip_buffer(struct e100_serial *info)
 {
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty;
 	struct etrax_recv_buffer *buffer;
 	unsigned int length;
 	unsigned long flags;
@@ -1685,6 +1867,11 @@
 	save_flags(flags);
 	cli();
 
+	if (!(tty = info->tty)) {
+		restore_flags(flags);
+		return;
+	}
+
 	length = tty->flip.count;
 
 	while ((buffer = info->first_recv_buffer) && length < TTY_FLIPBUF_SIZE) {
@@ -1773,7 +1960,7 @@
 	
 	for (i = 0; i < NR_PORTS; i++) {
 		info = rs_table + i;
-		if (info->uses_dma) 
+		if (info->enabled && info->uses_dma) 
 			check_flush_timeout(info);
 	}
 } /* timeout_interrupt */
@@ -1880,7 +2067,7 @@
 
 */
 
-static void _INLINE_ handle_ser_interrupt(struct e100_serial *info)
+extern void _INLINE_ handle_ser_interrupt(struct e100_serial *info)
 {
 	unsigned char rstat = info->port[REG_STATUS];
 
@@ -2247,6 +2434,7 @@
 change_speed(struct e100_serial *info)
 {
 	unsigned int cflag;
+	unsigned long xoff;
 
 	/* first some safety checks */
 	
@@ -2316,7 +2504,13 @@
 	
 	info->port[REG_TR_CTRL] = info->tx_ctrl;
 	info->port[REG_REC_CTRL] = info->rx_ctrl;
-	*((unsigned long *)&info->port[REG_XOFF]) = 0;
+	xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty));
+	xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
+	if (info->tty->termios->c_iflag & IXON ) {
+		xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+	}
+	
+	*((unsigned long *)&info->port[REG_XOFF]) = xoff;
 #endif /* !CONFIG_SVINTO_SIM */
 
 	update_char_time(info);
@@ -2349,7 +2543,7 @@
 	restore_flags(flags);
 }
 
-static inline int 
+extern inline int 
 raw_write(struct tty_struct * tty, int from_user,
 	  const unsigned char *buf, int count)
 {
@@ -2497,7 +2691,7 @@
 
 		/* Sleep until all sent */
 		tty_wait_until_sent(tty, 0);
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+#ifdef CONFIG_ETRAX_FAST_TIMER
 		/* Now sleep a little more so that shift register is empty */
 		schedule_usleep(info->char_time_usec * 2);
 #endif
@@ -2805,14 +2999,15 @@
 	       E100_DSR_GET(info),
 	       E100_CTS_GET(info));
 #endif
+
 	result =  
 		(!E100_RTS_GET(info) ? TIOCM_RTS : 0)
 		| (!E100_DTR_GET(info) ? TIOCM_DTR : 0)
-		| (!E100_CD_GET(info) ? TIOCM_CAR : 0)
 		| (!E100_RI_GET(info) ? TIOCM_RNG : 0)
 		| (!E100_DSR_GET(info) ? TIOCM_DSR : 0)
+		| (!E100_CD_GET(info) ? TIOCM_CAR : 0)
 		| (!E100_CTS_GET(info) ? TIOCM_CTS : 0);
-	
+
 #ifdef SERIAL_DEBUG_IO 
 	printk("e100ser: modem state: %i 0x%08X\n", result, result);
 	{
@@ -3488,7 +3683,7 @@
  * /proc fs routines....
  */
 
-static inline int line_info(char *buf, struct e100_serial *info)
+extern inline int line_info(char *buf, struct e100_serial *info)
 {
 	char	stat_buf[30];
 	int	ret;
@@ -3503,17 +3698,17 @@
 
 	stat_buf[0] = 0;
 	stat_buf[1] = 0;
-	if (E100_RTS_GET(info))
+	if (!E100_RTS_GET(info))
 		strcat(stat_buf, "|RTS");
-	if (E100_CTS_GET(info))
+	if (!E100_CTS_GET(info))
 		strcat(stat_buf, "|CTS");
-	if (E100_DTR_GET(info))
+	if (!E100_DTR_GET(info))
 		strcat(stat_buf, "|DTR");
-	if (E100_DSR_GET(info))
+	if (!E100_DSR_GET(info))
 		strcat(stat_buf, "|DSR");
-	if (E100_CD_GET(info))
+	if (!E100_CD_GET(info))
 		strcat(stat_buf, "|CD");
-	if (E100_RI_GET(info))
+	if (!E100_RI_GET(info))
 		strcat(stat_buf, "|RI");
 
 	ret += sprintf(buf+ret, " baud:%d", info->baud);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/sync_serial.c linux-2.4.21/arch/cris/drivers/sync_serial.c
--- linux-2.4.20/arch/cris/drivers/sync_serial.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/cris/drivers/sync_serial.c	2002-12-18 18:58:03.000000000 +0000
@@ -64,13 +64,13 @@
 #define DEFAULT_FRAME_RATE 0
 #define DEFAULT_WORD_RATE 7
 
-#define DEBUG(x) 
+#define DEBUG(x)
 
 /* Define some macros to access ETRAX 100 registers */
-#define SETF(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
-					  IO_FIELD(##reg##, field, val)
-#define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
-					  IO_STATE(##reg##, field, val)
+#define SETF(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_FIELD_(reg##_, field##_, val)
+#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_STATE_(reg##_, field##_, _##val)
 
 typedef struct sync_port
 {
@@ -107,8 +107,7 @@
 	char in_buffer[IN_BUFFER_SIZE];
 	volatile char* readp;  /* Next byte to be read by application */
 	volatile char* writep; /* Next byte to be written by etrax */
-	int odd_output; /* 1 if writing odd nible in 12 bit mode */
-	int odd_input;  /* 1 if reading odd nible in 12 bit mode */
+	int started; /* 1 if port has been started */
 } sync_port;
 
 
@@ -221,7 +220,6 @@
 	  IO_STATE(R_DMA_CH9_CLR_INTR, clr_descr, do); 
 	*R_IRQ_MASK2_SET =
 	  IO_STATE(R_IRQ_MASK2_SET, dma8_eop, set) |
-	  IO_STATE(R_IRQ_MASK2_SET, dma8_descr, set) |
           IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set);
 	start_dma_in(&ports[0]);
 #else
@@ -229,7 +227,6 @@
 	initialize_port(0);
 	if (request_irq(8, manual_interrupt, SA_SHIRQ | SA_INTERRUPT, "synchronous serial manual irq", &ports[0]))
 		panic("Can't allocate sync serial manual irq");
-	*R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser1_data, set);	 
 #endif
 #endif
 
@@ -252,7 +249,6 @@
 	  IO_STATE(R_DMA_CH5_CLR_INTR, clr_descr, do); 
 	*R_IRQ_MASK2_SET =
 	  IO_STATE(R_IRQ_MASK2_SET, dma4_eop, set) |
-	  IO_STATE(R_IRQ_MASK2_SET, dma4_descr, set) |
 	  IO_STATE(R_IRQ_MASK2_SET, dma5_descr, set);
 	start_dma_in(&ports[1]);
 #else
@@ -263,7 +259,6 @@
 		if (request_irq(8, manual_interrupt, SA_SHIRQ | SA_INTERRUPT, "synchronous serial manual irq", &ports[1]))
 			panic("Can't allocate sync serial manual irq");
 	}
-	*R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser3_data, set);	 
 #endif
 #endif
 
@@ -292,12 +287,12 @@
 	struct sync_port* port = &ports[portnbr];
 
 	DEBUG(printk("Init sync serial port %d\n", portnbr));
-    
+
+	port->started = 0;    
 	port->port_nbr = portnbr;	
 	port->busy = 0;		
 	port->readp = port->in_buffer;
-	port->writep = port->in_buffer + IN_BUFFER_SIZE/2;
-	port->odd_input = 0;
+	port->writep = port->in_buffer;
 
 	init_waitqueue_head(&port->out_wait_q);
 	init_waitqueue_head(&port->in_wait_q);
@@ -422,6 +417,10 @@
 		case SSP_MODE:
 			if (arg > 5)
 				return -EINVAL;
+			if (arg == MASTER_OUTPUT || arg == SLAVE_OUTPUT)
+				*R_IRQ_MASK1_CLR = 1 << port->data_avail_bit;
+			else
+				*R_IRQ_MASK1_SET = 1 << port->data_avail_bit;
 			SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, arg);
 			break;
 		case SSP_FRAME_SYNC:
@@ -466,8 +465,8 @@
 			if (arg & CLOCK_NOT_GATED)
 				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, normal);
 			else if (arg & CLOCK_GATED)
-				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, gated);
-    
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, gated);    
+
 			break;
 		case SSP_IPOLARITY:
 			if (arg & CLOCK_NORMAL)
@@ -553,11 +552,10 @@
 	copy_from_user(port->out_buffer, buf, count);
 	port->outp = port->out_buffer;
 	port->out_count = count;
-	port->odd_output = 1;
 	add_wait_queue(&port->out_wait_q, &wait);
 	set_current_state(TASK_INTERRUPTIBLE);
-	*R_IRQ_MASK1_SET = 1 << port->ready_irq_bit; /* transmitter ready IRQ on */
 	send_word(port); /* Start sender by sending first word */
+	*R_IRQ_MASK1_SET = 1 << port->ready_irq_bit; /* transmitter ready IRQ on */
 	schedule();
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&port->out_wait_q, &wait);
@@ -586,9 +584,15 @@
 
 	count = count > OUT_BUFFER_SIZE ? OUT_BUFFER_SIZE : count;
 
-	/* Make sure transmitter is running */
-	SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running);
-	SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable, enable);
+	/* Make sure transmitter/receiver is running */
+	if (!port->started)
+	{
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable, enable);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable, enable);
+		port->started = 1;
+	}
+
 	*port->ctrl_data = port->ctrl_data_shadow;
 
 	if (!port->use_dma)
@@ -629,9 +633,14 @@
 
 	DEBUG(printk("Read dev %d count %d\n", dev, count));
 
-	/* Make sure receiver is running */
-	SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running);
-	SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable, enable);
+	if (!port->started)
+	{
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable, enable);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable, enable);
+		port->started = 1;
+	}
+
 	*port->ctrl_data = port->ctrl_data_shadow;
 
 	/* Calculate number of available bytes */
@@ -680,13 +689,12 @@
 			*port->data_out = *port->outp++;
 			break;
 		case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size12bit):
-			port->out_count--;
-			if (port->odd_output)
-				*port->data_out = ((*port->outp) << 16) | (*(unsigned short *)(port->outp + 1));
-			else
-				*port->data_out = ((*(unsigned short *)port->outp) << 8) | (*(port->outp + 1));
-			port->odd_output = !port->odd_output;
-			port->outp++;
+			{
+				int data = (*port->outp++) << 8;
+				data |= *port->outp++;
+				port->out_count-=2;  
+				*port->data_out = data;
+			}
 			break;
 		case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size16bit):
 			port->out_count-=2;
@@ -710,7 +718,7 @@
 {
 	port->out_descr.hw_len = 0;
 	port->out_descr.next = 0;
-	port->out_descr.ctrl = d_int | d_eol | d_eop | d_wait;
+	port->out_descr.ctrl = d_eol | d_eop | d_wait;
 	port->out_descr.sw_len = count;
 	port->out_descr.buf = virt_to_phys(port->out_buffer);
 	port->out_descr.status = 0;
@@ -765,6 +773,9 @@
 	for (i = 0; i < NUMBER_OF_PORTS; i++) 
 	{
 		sync_port *port = &ports[i];
+		if (!port->enabled)
+			continue;
+
 		if (ireg & (1 << port->output_dma_bit)) /* IRQ active for the port? */
 		{
 			/* Clear IRQ */
@@ -783,19 +794,15 @@
 
 	for (i = 0; i < NUMBER_OF_PORTS; i++) 
 	{
-		int update = 0;
 		sync_port *port = &ports[i];
 
 		if (!port->enabled)
-		{
 			continue;
-		}    
 
 		if (ireg & (1 << port->input_dma_descr_bit)) /* Descriptor interrupt */
 		{
 			/* DMA has reached end of descriptor */
 			*port->input_dma_clr_irq = 
-			  IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do) | 
 			  IO_STATE(R_DMA_CH0_CLR_INTR, clr_descr, do);
 
 			/* Find out which descriptor that is ready */
@@ -847,18 +854,9 @@
 				case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size12bit):
 				{
 					int data = *(unsigned short *)port->data_in;
-					if (port->odd_input)
-					{
-						*port->writep |= (data & 0x0f00) >> 8;
-						*(port->writep + 1) = data & 0xff;
-					}
-					else
-					{
-						*port->writep = (data & 0x0ff0) >> 4;
-						*(port->writep + 1) = (data & 0x0f) << 4;
-					}
-					port->odd_input = !port->odd_input;
-					port->writep+=1;
+					*port->writep = (data & 0x0ff0) >> 4;
+					*(port->writep + 1) = data & 0x0f;
+					port->writep+=2;
 				}
 				break;
 				case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size16bit):
@@ -875,14 +873,14 @@
 					break;
 			}
 
-			if (port->writep > port->in_buffer + IN_BUFFER_SIZE) /* Wrap? */
+			if (port->writep >= port->in_buffer + IN_BUFFER_SIZE) /* Wrap? */
 				port->writep = port->in_buffer;
 			wake_up_interruptible(&port->in_wait_q); /* Wake up application */
 		}
 
 		if (*R_IRQ_MASK1_RD & (1 << port->transmitter_ready_bit)) /* Transmitter ready? */
 		{
-			if (port->out_count) /* More data to send */
+			if (port->out_count > 0) /* More data to send */
 				send_word(port);
 			else /* transmission finished */
 			{
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/entry.S linux-2.4.21/arch/cris/kernel/entry.S
--- linux-2.4.20/arch/cris/kernel/entry.S	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/arch/cris/kernel/entry.S	2002-12-18 18:58:07.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.39 2002/04/24 00:46:45 bjornw Exp $
+/* $Id: entry.S,v 1.40 2002/12/02 08:11:41 starvik Exp $
  *
  *  linux/arch/cris/entry.S
  *
@@ -7,6 +7,9 @@
  *  Authors:	Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: entry.S,v $
+ *  Revision 1.40  2002/12/02 08:11:41  starvik
+ *  Merge of Linux 2.4.20
+ *
  *  Revision 1.39  2002/04/24 00:46:45  bjornw
  *  Added sys_tkill
  *
@@ -1016,7 +1019,33 @@
         .long SYMBOL_NAME(sys_ni_syscall)       /* Reserved for Security */
         .long SYMBOL_NAME(sys_gettid)
         .long SYMBOL_NAME(sys_readahead)        /* 225 */
-	.long SYMBOL_NAME(sys_tkill)
+	.long SYMBOL_NAME(sys_setxattr)
+	.long SYMBOL_NAME(sys_lsetxattr)
+	.long SYMBOL_NAME(sys_fsetxattr)
+	.long SYMBOL_NAME(sys_getxattr)
+	.long SYMBOL_NAME(sys_lgetxattr)	/* 230 */
+	.long SYMBOL_NAME(sys_fgetxattr)
+	.long SYMBOL_NAME(sys_listxattr)
+	.long SYMBOL_NAME(sys_llistxattr)
+	.long SYMBOL_NAME(sys_flistxattr)
+	.long SYMBOL_NAME(sys_removexattr)	/* 235 */
+	.long SYMBOL_NAME(sys_lremovexattr)
+	.long SYMBOL_NAME(sys_fremovexattr)
+ 	.long SYMBOL_NAME(sys_tkill)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sendfile64 */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 240 reserved for futex */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sched_setaffinity */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sched_getaffinity */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_set_thread_area */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_get_thread_area */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 245 sys_io_setup */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_io_destroy */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_io_getevents */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_io_submit */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_io_cancel */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 250 sys_alloc_hugepages */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_free_hugepages */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_exit_group */
 	
         /*
          * NOTE!! This doesn't have to be exact - we just have
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/fasttimer.c linux-2.4.21/arch/cris/kernel/fasttimer.c
--- linux-2.4.20/arch/cris/kernel/fasttimer.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/cris/kernel/fasttimer.c	2002-12-18 18:58:06.000000000 +0000
@@ -1,10 +1,13 @@
-/* $Id: fasttimer.c,v 1.4 2002/05/28 17:47:59 johana Exp $
+/* $Id: fasttimer.c,v 1.5 2002/10/15 06:21:39 starvik Exp $
  * linux/arch/cris/kernel/fasttimer.c
  *
  * Fast timers for ETRAX100/ETRAX100LX
  * This may be useful in other OS than Linux so use 2 space indentation...
  *
  * $Log: fasttimer.c,v $
+ * Revision 1.5  2002/10/15 06:21:39  starvik
+ * Added call to init_waitqueue_head
+ *
  * Revision 1.4  2002/05/28 17:47:59  johana
  * Added del_fast_timer()
  *
@@ -551,6 +554,8 @@
   struct fast_timer t;
 #ifdef DECLARE_WAITQUEUE
   wait_queue_head_t sleep_wait;
+  init_waitqueue_head(&sleep_wait);
+  {
   DECLARE_WAITQUEUE(wait, current);
 #else
   struct wait_queue *sleep_wait = NULL;
@@ -566,6 +571,9 @@
   set_current_state(TASK_RUNNING);
   remove_wait_queue(&sleep_wait, &wait);
   D1(printk("done schedule_usleep(%d)\n", us));
+#ifdef DECLARE_WAITQUEUE
+  }
+#endif  
 }
 
 #ifdef CONFIG_PROC_FS
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/ksyms.c linux-2.4.21/arch/cris/kernel/ksyms.c
--- linux-2.4.20/arch/cris/kernel/ksyms.c	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.21/arch/cris/kernel/ksyms.c	2002-12-18 18:58:11.000000000 +0000
@@ -24,6 +24,7 @@
 extern void dump_thread(struct pt_regs *, struct user *);
 extern unsigned long get_cmos_time(void);
 extern void __Udiv(void);
+extern void __Umod(void);
 extern void __ashrdi3(void);
 extern void iounmap(void *addr);
 
@@ -47,9 +48,11 @@
 EXPORT_SYMBOL(strlen);
 EXPORT_SYMBOL(strncat);
 EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL(strncpy);
 
 /* Math functions */
 EXPORT_SYMBOL(__Udiv);
+EXPORT_SYMBOL(__Umod);
 EXPORT_SYMBOL(__ashrdi3);
 
 /* Memory functions */
@@ -70,14 +73,13 @@
 EXPORT_SYMBOL(port_g_data_shadow);
 
 /* Userspace access functions */
-EXPORT_SYMBOL(strncpy_from_user);
-EXPORT_SYMBOL(__strncpy_from_user);
-EXPORT_SYMBOL(__generic_copy_from_user);
-EXPORT_SYMBOL(__generic_copy_to_user);
-EXPORT_SYMBOL(strnlen_user);
 EXPORT_SYMBOL(__copy_user_zeroing);
 EXPORT_SYMBOL(__copy_user);
 
+/* Cache flush functions */
+EXPORT_SYMBOL(flush_etrax_cache);
+EXPORT_SYMBOL(prepare_rx_descriptor);
+
 #undef memcpy
 #undef memset
 extern void * memset(void *, int, __kernel_size_t);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/process.c linux-2.4.21/arch/cris/kernel/process.c
--- linux-2.4.20/arch/cris/kernel/process.c	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.21/arch/cris/kernel/process.c	2002-12-18 18:58:10.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.22 2001/11/13 09:40:43 orjanf Exp $
+/* $Id: process.c,v 1.23 2002/10/14 18:29:27 johana Exp $
  * 
  *  linux/arch/cris/kernel/process.c
  *
@@ -8,6 +8,10 @@
  *  Authors:   Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: process.c,v $
+ *  Revision 1.23  2002/10/14 18:29:27  johana
+ *  Call etrax_gpio_wake_up_check() from cpu_idle() to reduce gpio latency
+ *  from ~15 ms to ~6 ms.
+ *
  *  Revision 1.22  2001/11/13 09:40:43  orjanf
  *  Added dump_fpu (needed for core dumps).
  *
@@ -121,11 +125,18 @@
 {
 	hlt_counter--;
 }
- 
+#ifdef CONFIG_ETRAX_GPIO
+void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */
+#endif
+
 int cpu_idle(void *unused)
 {
 	while(1) {
 		current->counter = -100;
+#ifdef CONFIG_ETRAX_GPIO
+		/* This can reduce latency from 15 ms to 6 ms */
+		etrax_gpio_wake_up_check(); /* drivers/gpio.c */
+#endif
 		schedule();
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/setup.c linux-2.4.21/arch/cris/kernel/setup.c
--- linux-2.4.20/arch/cris/kernel/setup.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/cris/kernel/setup.c	2002-12-18 18:58:11.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.26 2002/06/04 07:57:56 jonashg Exp $
+/* $Id: setup.c,v 1.27 2002/10/11 12:57:15 pkj Exp $
  *
  *  linux/arch/cris/kernel/setup.c
  *
@@ -232,33 +232,34 @@
 		info = &cpu_info[revision];
 
 	return seq_printf(m,
-		       "cpu\t\t: CRIS\n"
-		       "cpu revision\t: %lu\n"
-		       "cpu model\t: %s\n"
-		       "cache size\t: %d kB\n"
-		       "fpu\t\t: %s\n"
-		       "mmu\t\t: %s\n"
-		       "mmu DMA bug\t: %s\n"
-		       "ethernet\t: %s Mbps\n"
-		       "token ring\t: %s\n"
-		       "scsi\t\t: %s\n"
-		       "ata\t\t: %s\n"
-		       "usb\t\t: %s\n"
-		       "bogomips\t: %lu.%02lu\n",
-
-		       revision,
-		       info->model,
-		       info->cache,
-		       info->flags & HAS_FPU ? "yes" : "no",
-		       info->flags & HAS_MMU ? "yes" : "no",
-		       info->flags & HAS_MMU_BUG ? "yes" : "no",
-		       info->flags & HAS_ETHERNET100 ? "10/100" : "10",
-		       info->flags & HAS_TOKENRING ? "4/16 Mbps" : "no",
-		       info->flags & HAS_SCSI ? "yes" : "no",
-		       info->flags & HAS_ATA ? "yes" : "no",
-		       info->flags & HAS_USB ? "yes" : "no",
-		       (loops_per_jiffy * HZ + 500) / 500000,
-		       ((loops_per_jiffy * HZ + 500) / 5000) % 100);
+			  "processor\t: 0\n"
+			  "cpu\t\t: CRIS\n"
+			  "cpu revision\t: %lu\n"
+			  "cpu model\t: %s\n"
+			  "cache size\t: %d kB\n"
+			  "fpu\t\t: %s\n"
+			  "mmu\t\t: %s\n"
+			  "mmu DMA bug\t: %s\n"
+			  "ethernet\t: %s Mbps\n"
+			  "token ring\t: %s\n"
+			  "scsi\t\t: %s\n"
+			  "ata\t\t: %s\n"
+			  "usb\t\t: %s\n"
+			  "bogomips\t: %lu.%02lu\n",
+
+			  revision,
+			  info->model,
+			  info->cache,
+			  info->flags & HAS_FPU ? "yes" : "no",
+			  info->flags & HAS_MMU ? "yes" : "no",
+			  info->flags & HAS_MMU_BUG ? "yes" : "no",
+			  info->flags & HAS_ETHERNET100 ? "10/100" : "10",
+			  info->flags & HAS_TOKENRING ? "4/16 Mbps" : "no",
+			  info->flags & HAS_SCSI ? "yes" : "no",
+			  info->flags & HAS_ATA ? "yes" : "no",
+			  info->flags & HAS_USB ? "yes" : "no",
+			  (loops_per_jiffy * HZ + 500) / 500000,
+			  ((loops_per_jiffy * HZ + 500) / 5000) % 100);
 }
 
 static void *c_start(struct seq_file *m, loff_t *pos)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/signal.c linux-2.4.21/arch/cris/kernel/signal.c
--- linux-2.4.20/arch/cris/kernel/signal.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/arch/cris/kernel/signal.c	2002-12-18 18:58:02.000000000 +0000
@@ -517,7 +517,7 @@
  * OK, we're invoking a handler
  */	
 
-static inline void
+extern inline void
 handle_signal(int canrestart, unsigned long sig, struct k_sigaction *ka,
 	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/time.c linux-2.4.21/arch/cris/kernel/time.c
--- linux-2.4.20/arch/cris/kernel/time.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/arch/cris/kernel/time.c	2002-12-18 18:58:01.000000000 +0000
@@ -1,9 +1,9 @@
-/* $Id: time.c,v 1.14 2002/03/05 13:31:03 johana Exp $
+/* $Id: time.c,v 1.17 2002/11/15 14:49:24 oskarp Exp $
  *
  *  linux/arch/cris/kernel/time.c
  *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *  Copyright (C) 1999, 2000, 2001 Axis Communications AB
+ *  Copyright (C) 1999, 2000, 2001, 2002 Axis Communications AB
  *
  * 1994-07-02    Alan Modra
  *	fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
@@ -25,6 +25,9 @@
  *      resolution within a jiffie as well.
  * 2002-03-05    Johan Adolfsson
  *      Use prescaler in do_slow_gettimeoffset() to get 1 us resolution (40ns)
+ * 2002-09-06    Johan Adolfsson
+ *      Handle lost ticks by checking wall_jiffies, more efficient code 
+ *      by using local vars and not the pointer argument.
  *
  */
 
@@ -62,6 +65,8 @@
 
 #define TICK_SIZE tick
 
+extern unsigned long wall_jiffies;
+
 /* The timers count from their initial value down to 1 
  * The R_TIMER0_DATA counts down when R_TIM_PRESC_STATUS reaches halv
  * of the divider value.
@@ -171,10 +176,8 @@
 
 	/*
 	 * avoiding timer inconsistencies (they are rare, but they happen)...
-	 * there are three kinds of problems that must be avoided here:
+	 * there are one problem that must be avoided here:
 	 *  1. the timer counter underflows
-	 *  2. we are after the timer interrupt, but the bottom half handler
-	 *     hasn't executed yet.
 	 */
 	if( jiffies_t == jiffies_p ) {
 		if( count > count_p ) {
@@ -198,7 +201,8 @@
 	return usec_count;
 }
 
-static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
+
+#define do_gettimeoffset() do_slow_gettimeoffset()
 
 /*
  * This version of gettimeofday has near microsecond resolution.
@@ -206,20 +210,33 @@
 void do_gettimeofday(struct timeval *tv)
 {
 	unsigned long flags;
-
+	unsigned long usec, sec;
 	save_flags(flags);
 	cli();
-	*tv = xtime;
-	tv->tv_usec += do_gettimeoffset();
+	usec = do_gettimeoffset();
+	{
+		unsigned long lost = jiffies - wall_jiffies;
+		if (lost)
+			usec += lost * (1000000 / HZ);
+	}
+	sec = xtime.tv_sec;
+	usec += xtime.tv_usec;
 	restore_flags(flags);
-	while (tv->tv_usec >= 1000000) {
-		tv->tv_usec -= 1000000;
-		tv->tv_sec++;
+
+	while (usec >= 1000000) {
+		usec -= 1000000;
+		sec++;
 	}
+
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
 }
 
 void do_settimeofday(struct timeval *tv)
 {
+	unsigned long flags;
+	signed long new_usec, new_sec;
+	save_flags(flags);  
 	cli();
 	/* This is revolting. We need to set the xtime.tv_usec
 	 * correctly. However, the value in this location is
@@ -227,20 +244,23 @@
 	 * Discover what correction gettimeofday
 	 * would have done, and then undo it!
 	 */
-	tv->tv_usec -= do_gettimeoffset();
-
-	if (tv->tv_usec < 0) {
-		tv->tv_usec += 1000000;
-		tv->tv_sec--;
+	new_usec = tv->tv_usec;
+	new_usec -= do_gettimeoffset();
+	new_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
+	new_sec = tv->tv_sec;
+	while (new_usec < 0) {
+		new_usec += 1000000;
+		new_sec--;
 	}
+	xtime.tv_sec = new_sec;
+	xtime.tv_usec = new_usec;
 
-	xtime = *tv;
 	time_adjust = 0;		/* stop active adjtime() */
 	time_status |= STA_UNSYNC;
 	time_state = TIME_ERROR;	/* p. 24, (a) */
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
-	sti();
+	restore_flags(flags);
 }
 
 
@@ -479,10 +499,16 @@
 void __init
 time_init(void)
 {	
-	/* probe for the RTC and read it if it exists */
+	/* Probe for the RTC and read it if it exists 
+	 * Before the RTC can be probed the loops_per_usec variable needs 
+	 * to be initialized to make usleep work. A better value for 
+	 * loops_per_usec is calculated by the kernel later once the 
+	 * clock has started.  
+	 */
+	loops_per_usec = 50;
 
 	if(RTC_INIT() < 0) {
-		/* no RTC, start at 1980 */
+		/* no RTC, start at the Epoch (00:00:00 UTC, January 1, 1970) */
 		xtime.tv_sec = 0;
 		xtime.tv_usec = 0;
 		have_rtc = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/traps.c linux-2.4.21/arch/cris/kernel/traps.c
--- linux-2.4.20/arch/cris/kernel/traps.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/cris/kernel/traps.c	2002-12-18 18:58:11.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.17 2001/12/07 17:02:34 bjornw Exp $
+/* $Id: traps.c,v 1.18 2002/12/02 08:11:41 starvik Exp $
  *
  *  linux/arch/cris/traps.c
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/lib/dram_init.S linux-2.4.21/arch/cris/lib/dram_init.S
--- linux-2.4.20/arch/cris/lib/dram_init.S	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/cris/lib/dram_init.S	2002-12-18 18:58:06.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: dram_init.S,v 1.12 2002/08/09 11:37:37 orjanf Exp $
+/* $Id: dram_init.S,v 1.13 2002/10/30 07:42:28 starvik Exp $
  * 
  * DRAM/SDRAM initialization - alter with care
  * This file is intended to be included from other assembler files
@@ -11,6 +11,9 @@
  * Authors:  Mikael Starvik (starvik@axis.com)	
  * 
  * $Log: dram_init.S,v $
+ * Revision 1.13  2002/10/30 07:42:28  starvik
+ * Always read SDRAM command sequence from flash
+ *
  * Revision 1.12  2002/08/09 11:37:37  orjanf
  * Added double initialization work-around for Samsung SDRAMs.
  *
@@ -143,7 +146,9 @@
 	
 	; Issue initialization command sequence
 	move.d   _sdram_commands_start, $r2
+	and.d    0x00ffffff, $r2 ; Make sure commands are read from flash
 	move.d   _sdram_commands_end,  $r3
+	and.d    0x00ffffff, $r2
 1:	clear.d  $r4
 	move.b   [$r2+], $r4
 	lslq     9, $r4	; Command starts at bit 9
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/lib/hw_settings.S linux-2.4.21/arch/cris/lib/hw_settings.S
--- linux-2.4.20/arch/cris/lib/hw_settings.S	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/cris/lib/hw_settings.S	2002-12-18 18:58:08.000000000 +0000
@@ -1,11 +1,11 @@
 /*
- * $Id: hw_settings.S,v 1.4 2002/07/04 16:58:56 pkj Exp $
+ * $Id: hw_settings.S,v 1.5 2002/08/15 09:16:06 bjornw Exp $
  * 
  * This table is used by some tools to extract hardware parameters.
  * The table should be included in the kernel and the decompressor.
  * Don't forget to update the tools if you change this table.
  *
- * Copyright (C) 2001 Axis Communications AB
+ * Copyright (C) 2001, 2002 Axis Communications AB
  *
  * Authors:  Mikael Starvik (starvik@axis.com)	
  */
@@ -16,8 +16,8 @@
 		(CONFIG_ETRAX_DEF_R_PORT_PB_DIR << 8) | \
 		(CONFIG_ETRAX_DEF_R_PORT_PB_DATA))
 	
-	.ascii "HW_PARAM_MAGIC"					; Magic number
-	.dword CONFIG_ETRAX_DRAM_VIRTUAL_BASE | 0x80004000	; Kernel start address
+	.ascii "HW_PARAM_MAGIC"	; Magic number
+	.dword 0xc0004000	; Where to load the kernel image (physical!)
 
 	; Debug port
 #ifdef CONFIG_ETRAX_DEBUG_PORT0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/lib/usercopy.c linux-2.4.21/arch/cris/lib/usercopy.c
--- linux-2.4.20/arch/cris/lib/usercopy.c	2001-10-08 18:43:54.000000000 +0000
+++ linux-2.4.21/arch/cris/lib/usercopy.c	2002-12-18 18:58:03.000000000 +0000
@@ -88,11 +88,11 @@
        If you want to check that the allocation was right; then
        check the equalities in the first comment.  It should say
        "r13=r13, r11=r11, r12=r12".  */
-    __asm__ volatile ("
-	;; Check that the following is true (same register names on
-	;; both sides of equal sign, as in r8=r8):
-	;; %0=r13, %1=r11, %2=r12 %3=r10
-	;;
+    __asm__ volatile ("\
+	.ifnc %0%1%2%3,$r13$r11$r12$r10					\n\
+	.err								\n\
+	.endif								\n\
+
 	;; Save the registers we'll use in the movem process
 	;; on the stack.
 	subq	11*4,$sp
@@ -189,7 +189,8 @@
 }
 
 /* Copy from user to kernel, zeroing the bytes that were inaccessible in
-   userland.  */
+   userland.  The return-value is the number of bytes that were
+   inaccessible.  */
 
 unsigned long
 __copy_user_zeroing (void *pdst, const void *psrc, unsigned long pn)
@@ -207,30 +208,34 @@
   register int n __asm__ ("r12") = pn;
   register int retn __asm__ ("r10") = 0;
 
-  /* When src is aligned but not dst, this makes a few extra needless
-     cycles.  I believe it would take as many to check that the
-     re-alignment was unnecessary.  */
-  if (((unsigned long) dst & 3) != 0
-      /* Don't align if we wouldn't copy more than a few bytes; so we
-	 don't have to check further for overflows.  */
-      && n >= 3)
+  /* The best reason to align src is that we then know that a read-fault
+     was for aligned bytes; there's no 1..3 remaining good bytes to
+     pickle.  */
+  if (((unsigned long) src & 3) != 0)
   {
-    if ((unsigned long) dst & 1)
+    if (((unsigned long) src & 1) && n != 0)
     {
       __asm_copy_from_user_1 (dst, src, retn);
       n--;
     }
 
-    if ((unsigned long) dst & 2)
+    if (((unsigned long) src & 2) && n >= 2)
     {
       __asm_copy_from_user_2 (dst, src, retn);
       n -= 2;
     }
+
+    /* We only need one check after the unalignment-adjustments, because
+       if both adjustments were done, either both or neither reference
+       had an exception.  */
+    if (retn != 0)
+      goto copy_exception_bytes;
   }
 
   /* Decide which copying method to use. */
   if (n >= 44*2)		/* Break even between movem and
-				   move16 is at 38.7*2, but modulo 44. */
+				   move16 is at 38.7*2, but modulo 44.
+				   FIXME: We use move4 now.  */
   {
     /* For large copies we use 'movem' */
 
@@ -249,10 +254,10 @@
        check the equalities in the first comment.  It should say
        "r13=r13, r11=r11, r12=r12" */
     __asm__ volatile ("
-	;; Check that the following is true (same register names on
-	;; both sides of equal sign, as in r8=r8):
-	;; %0=r13, %1=r11, %2=r12 %3=r10
-	;;
+	.ifnc %0%1%2%3,$r13$r11$r12$r10					\n\
+	.err								\n\
+	.endif								\n\
+
 	;; Save the registers we'll use in the movem process
 	;; on the stack.
 	subq	11*4,$sp
@@ -273,73 +278,30 @@
 	movem	$r10,[$r13+]
 
 	addq   44,$r12  ;; compensate for last loop underflowing n
-8:
+
 	;; Restore registers from stack
 	movem [$sp+],$r10
-
+4:
 	.section .fixup,\"ax\"
 
 ;; Do not jump back into the loop if we fail.  For some uses, we get a
-;; page fault but for performance reasons we care to not get further
-;; faults.  For example, fs/super.c at one time did
+;; page fault somewhere on the line.  Without checking for page limits,
+;; we don't know where, but we need to copy accurately and keep an
+;; accurate count; not just clear the whole line.  To do that, we fall
+;; down in the code below, proceeding with smaller amounts.  It should
+;; be kept in mind that we have to cater to code like what at one time
+;; was in fs/super.c:
 ;;  i = size - copy_from_user((void *)page, data, size);
 ;; which would cause repeated faults while clearing the remainder of
 ;; the SIZE bytes at PAGE after the first fault.
+;; A caveat here is that we must not fall through from a failing page
+;; to a valid page.
 
 3:
-	move.d [$sp],$r10
-
-;; Number of remaining bytes, cleared but not copied, is r12 + 44.
-
-	add.d $r12,$r10
-	addq 44,$r10
-
-	move.d $r10,[$sp]
-	clear.d $r0
-	clear.d $r1
-	clear.d $r2
-	clear.d $r3
-	clear.d $r4
-	clear.d $r5
-	clear.d $r6
-	clear.d $r7
-	clear.d $r8
-	clear.d $r9
-	clear.d $r10
-
-;; Perform clear similar to the copy-loop.
-
-4:
-	subq 44,$r12
-	bge 4b
-	movem $r10,[$r13+]
-
-;; Clear by four for the remaining multiples.
-
-	addq 40,$r12
-	bmi 6f
-	nop
-5:
-	subq 4,$r12
-	bpl 5b
-	clear.d [$r13+]
-6:
-	addq 4,$r12
-	beq 7f
-	nop
-
-	subq 1,$r12
-	beq 7f
-	clear.b [$r13+]
-
-	subq 1,$r12
-	beq 7f
-	clear.b [$r13+]
-
-	clear.d $r12
-	clear.b [$r13+]
-7:
-	jump 8b
+	movem  [$sp+],$r10
+	addq	44,$r12 ;; Get back count before faulting point.
+	subq	44,$r11 ;; Get back pointer to faulting movem-line.
+	jump	4b	;; Fall through, pretending the fault didn't happen.
 
 	.previous
 	.section __ex_table,\"a\"
@@ -354,25 +316,30 @@
   /* Either we directly start copying here, using dword copying in a loop,
      or we copy as much as possible with 'movem' and then the last block
      (<44 bytes) is copied here.  This will work since 'movem' will have
-     updated src, dst and n. */
+     updated src, dst and n.  (Except with failing src.)
 
-  while (n >= 16)
-  {
-    __asm_copy_from_user_16 (dst, src, retn);
-    n -= 16;
-  }
+     Since we want to keep src accurate, we can't use
+     __asm_copy_from_user_N with N != (1, 2, 4); it updates dst and
+     retn, but not src (by design; it's value is ignored elsewhere).  */
 
-  /* Having a separate by-four loops cuts down on cache footprint.
-     FIXME:  Test with and without; increasing switch to be 0..15.  */
   while (n >= 4)
   {
     __asm_copy_from_user_4 (dst, src, retn);
     n -= 4;
+
+    if (retn)
+      goto copy_exception_bytes;
   }
 
+  /* If we get here, there were no memory read faults.  */
   switch (n)
   {
+    /* These copies are at least "naturally aligned" (so we don't have
+       to check each byte), due to the src alignment code before the
+       movem loop.  The *_3 case *will* get the correct count for retn.  */
     case 0:
+      /* This case deliberately left in (if you have doubts check the
+	 generated assembly code).  */
       break;
     case 1:
       __asm_copy_from_user_1 (dst, src, retn);
@@ -385,7 +352,22 @@
       break;
   }
 
+  /* If we get here, retn correctly reflects the number of failing
+     bytes.  */
   return retn;
+
+copy_exception_bytes:
+  /* We already have "retn" bytes cleared, and need to clear the
+     remaining "n" bytes.  A non-optimized simple byte-for-byte in-line
+     memset is preferred here, since this isn't speed-critical code and
+     we'd rather have this a leaf-function than calling memset.  */
+  {
+    char *endp;
+    for (endp = dst + n; dst < endp; dst++)
+      *dst = 0;
+  }
+
+  return retn + n;
 }
 
 /* Zero userspace.  */
@@ -444,10 +426,10 @@
       check the equalities in the first comment.  It should say
       something like "r13=r13, r11=r11, r12=r12". */
     __asm__ volatile ("
-	;; Check that the following is true (same register names on
-	;; both sides of equal sign, as in r8=r8):
-	;; %0=r13, %1=r12 %2=r10
-	;;
+	.ifnc %0%1%2,$r13$r12$r10					\n\
+	.err								\n\
+	.endif								\n\
+
 	;; Save the registers we'll clobber in the movem process
 	;; on the stack.  Don't mention them to gcc, it will only be
 	;; upset.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/mm/ioremap.c linux-2.4.21/arch/cris/mm/ioremap.c
--- linux-2.4.20/arch/cris/mm/ioremap.c	2001-05-01 23:04:56.000000000 +0000
+++ linux-2.4.21/arch/cris/mm/ioremap.c	2002-12-18 18:58:03.000000000 +0000
@@ -13,7 +13,7 @@
 #include <asm/io.h>
 #include <asm/pgalloc.h>
 
-static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+extern inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
 	unsigned long phys_addr, unsigned long flags)
 {
 	unsigned long end;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/config.in linux-2.4.21/arch/i386/config.in
--- linux-2.4.20/arch/i386/config.in	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/i386/config.in	2002-12-18 18:58:06.000000000 +0000
@@ -216,12 +216,26 @@
       define_bool CONFIG_X86_IO_APIC y
    fi
 else
-   bool 'Multiquad NUMA system' CONFIG_MULTIQUAD
+   bool 'Multi-node NUMA system support' CONFIG_X86_NUMA
+   if [ "$CONFIG_X86_NUMA" = "y" ]; then
+      #Platform Choices
+      bool ' Multiquad (IBM/Sequent) NUMAQ support' CONFIG_X86_NUMAQ
+      if [ "$CONFIG_X86_NUMAQ" = "y" ]; then
+         define_bool CONFIG_X86_CLUSTERED_APIC y
+         define_bool CONFIG_MULTIQUAD y
+      fi
+      bool ' IBM x440 (Summit/EXA) support' CONFIG_X86_SUMMIT
+      if [ "$CONFIG_X86_SUMMIT" = "y" ]; then
+         define_bool CONFIG_X86_CLUSTERED_APIC y
+      fi
+   fi
 fi
 
-bool 'Unsynced TSC support' CONFIG_X86_TSC_DISABLE
-if [ "$CONFIG_X86_TSC_DISABLE" != "y" -a "$CONFIG_X86_HAS_TSC" = "y" ]; then
-   define_bool CONFIG_X86_TSC y
+if [ "$CONFIG_X86_NUMA" != "y" ]; then
+   bool 'Unsynced TSC support' CONFIG_X86_TSC_DISABLE
+   if [ "$CONFIG_X86_TSC_DISABLE" != "y" -a "$CONFIG_X86_HAS_TSC" = "y" ]; then
+      define_bool CONFIG_X86_TSC y
+   fi
 fi
 
 if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/apic.c linux-2.4.21/arch/i386/kernel/apic.c
--- linux-2.4.20/arch/i386/kernel/apic.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/i386/kernel/apic.c	2002-12-18 18:58:08.000000000 +0000
@@ -261,6 +261,16 @@
 	apic_write_around(APIC_LVT1, value);
 }
 
+static unsigned long calculate_ldr(unsigned long old)
+{
+	unsigned long id;
+	if(clustered_apic_mode == CLUSTERED_APIC_XAPIC)
+		id = physical_to_logical_apicid(hard_smp_processor_id());
+	else
+		id = 1UL << smp_processor_id();
+	return (old & ~APIC_LDR_MASK)|SET_APIC_LOGICAL_ID(id);
+}
+
 void __init setup_local_APIC (void)
 {
 	unsigned long value, ver, maxlvt;
@@ -298,15 +308,16 @@
 		 * for us. Otherwise put the APIC into clustered or flat
 		 * delivery mode. Must be "all ones" explicitly for 82489DX.
 		 */
-		apic_write_around(APIC_DFR, APIC_DFR_FLAT);
+		if(clustered_apic_mode == CLUSTERED_APIC_XAPIC)
+			apic_write_around(APIC_DFR, APIC_DFR_CLUSTER);
+		else
+			apic_write_around(APIC_DFR, APIC_DFR_FLAT);
 
 		/*
 		 * Set up the logical destination ID.
 		 */
 		value = apic_read(APIC_LDR);
-		value &= ~APIC_LDR_MASK;
-		value |= (1<<(smp_processor_id()+24));
-		apic_write_around(APIC_LDR, value);
+		apic_write_around(APIC_LDR, calculate_ldr(value));
 	}
 
 	/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/head.S linux-2.4.21/arch/i386/kernel/head.S
--- linux-2.4.20/arch/i386/kernel/head.S	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/arch/i386/kernel/head.S	2002-12-18 18:58:03.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/i386/head.S -- the 32-bit startup code.
+ *  linux/arch/i386/kernel/head.S -- the 32-bit startup code.
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/io_apic.c linux-2.4.21/arch/i386/kernel/io_apic.c
--- linux-2.4.20/arch/i386/kernel/io_apic.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/i386/kernel/io_apic.c	2002-12-18 18:58:06.000000000 +0000
@@ -1067,7 +1067,7 @@
 		
 		old_id = mp_ioapics[apic].mpc_apicid;
 
-		if (mp_ioapics[apic].mpc_apicid >= 0xf) {
+		if (mp_ioapics[apic].mpc_apicid >= apic_broadcast_id) {
 			printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
 				apic, mp_ioapics[apic].mpc_apicid);
 			printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
@@ -1079,14 +1079,16 @@
 		 * Sanity check, is the ID really free? Every APIC in a
 		 * system must have a unique ID or we get lots of nice
 		 * 'stuck on smp_invalidate_needed IPI wait' messages.
+		 * I/O APIC IDs no longer have any meaning for xAPICs and SAPICs.
 		 */
-		if (phys_id_present_map & (1 << mp_ioapics[apic].mpc_apicid)) {
+		if ((clustered_apic_mode != CLUSTERED_APIC_XAPIC) &&
+		    (phys_id_present_map & (1 << mp_ioapics[apic].mpc_apicid))) {
 			printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",
 				apic, mp_ioapics[apic].mpc_apicid);
 			for (i = 0; i < 0xf; i++)
 				if (!(phys_id_present_map & (1 << i)))
 					break;
-			if (i >= 0xf)
+			if (i >= apic_broadcast_id)
 				panic("Max APIC ID exceeded!\n");
 			printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
 				i);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/mpparse.c linux-2.4.21/arch/i386/kernel/mpparse.c
--- linux-2.4.20/arch/i386/kernel/mpparse.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/i386/kernel/mpparse.c	2002-12-18 18:58:06.000000000 +0000
@@ -36,18 +36,20 @@
  * MP-table.
  */
 int apic_version [MAX_APICS];
-int mp_bus_id_to_type [MAX_MP_BUSSES];
-int mp_bus_id_to_node [MAX_MP_BUSSES];
-int mp_bus_id_to_local [MAX_MP_BUSSES];
 int quad_local_to_mp_bus_id [NR_CPUS/4][4];
-int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
 int mp_current_pci_id;
+int *mp_bus_id_to_type;
+int *mp_bus_id_to_node;
+int *mp_bus_id_to_local;
+int *mp_bus_id_to_pci_bus;
+int max_mp_busses;
+int max_irq_sources;
 
 /* I/O APIC entries */
 struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
 
 /* # of MP IRQ source entries */
-struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
+struct mpc_config_intsrc *mp_irqs;
 
 /* MP IRQ source entries */
 int mp_irq_entries;
@@ -65,8 +67,14 @@
 
 /* Bitmask of physically existing CPUs */
 unsigned long phys_cpu_present_map;
+unsigned long logical_cpu_present_map;
 
+#ifdef CONFIG_X86_CLUSTERED_APIC
 unsigned char esr_disable = 0;
+unsigned char clustered_apic_mode = CLUSTERED_APIC_NONE;
+unsigned int apic_broadcast_id = APIC_BROADCAST_ID_APIC;
+#endif
+unsigned char raw_phys_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
 
 /*
  * Intel MP BIOS table parsing routines:
@@ -226,16 +234,14 @@
 	if (m->mpc_apicid > MAX_APICS) {
 		printk("Processor #%d INVALID. (Max ID: %d).\n",
 			m->mpc_apicid, MAX_APICS);
-			--num_processors;
+		--num_processors;
 		return;
 	}
 	ver = m->mpc_apicver;
 
-	if (clustered_apic_mode == CLUSTERED_APIC_NUMAQ) {
-		phys_cpu_present_map |= (logical_apicid&0xf) << (4*quad);
-	} else {
-		phys_cpu_present_map |= 1 << m->mpc_apicid;
-	}
+	logical_cpu_present_map |= 1 << (num_processors-1);
+ 	phys_cpu_present_map |= apicid_to_phys_cpu_present(m->mpc_apicid);
+ 
 	/*
 	 * Validate version
 	 */
@@ -244,6 +250,7 @@
 		ver = 0x10;
 	}
 	apic_version[m->mpc_apicid] = ver;
+	raw_phys_apicid[num_processors - 1] = m->mpc_apicid;
 }
 
 static void __init MP_bus_info (struct mpc_config_bus *m)
@@ -308,7 +315,7 @@
 			m->mpc_irqtype, m->mpc_irqflag & 3,
 			(m->mpc_irqflag >> 2) & 3, m->mpc_srcbus,
 			m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq);
-	if (++mp_irq_entries == MAX_IRQ_SOURCES)
+	if (++mp_irq_entries == max_irq_sources)
 		panic("Max # of irq sources exceeded!!\n");
 }
 
@@ -398,9 +405,12 @@
 
 static int __init smp_read_mpc(struct mp_config_table *mpc)
 {
-	char str[16];
+	char oem[16], prod[14];
 	int count=sizeof(*mpc);
 	unsigned char *mpt=((unsigned char *)mpc)+count;
+	int num_bus = 0;
+	int num_irq = 0;
+	unsigned char *bus_data;
 
 	if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) {
 		panic("SMP mptable: bad signature [%c%c%c%c]!\n",
@@ -423,14 +433,16 @@
 		printk(KERN_ERR "SMP mptable: null local APIC address!\n");
 		return 0;
 	}
-	memcpy(str,mpc->mpc_oem,8);
-	str[8]=0;
-	printk("OEM ID: %s ",str);
-
-	memcpy(str,mpc->mpc_productid,12);
-	str[12]=0;
-	printk("Product ID: %s ",str);
+	memcpy(oem,mpc->mpc_oem,8);
+	oem[8]=0;
+	printk("OEM ID: %s ",oem);
+
+	memcpy(prod,mpc->mpc_productid,12);
+	prod[12]=0;
+	printk("Product ID: %s ",prod);
 
+	detect_clustered_apic(oem, prod);
+	
 	printk("APIC at: 0x%lX\n",mpc->mpc_lapic);
 
 	/* save the local APIC address, it might be non-default,
@@ -446,9 +458,70 @@
 		mpc_record = 0;
 	}
 
+	/* Pre-scan to determine the number of bus and 
+	 * interrupts records we have
+	 */
+	while (count < mpc->mpc_length) {
+		switch (*mpt) {
+			case MP_PROCESSOR:
+				mpt += sizeof(struct mpc_config_processor);
+				count += sizeof(struct mpc_config_processor);
+				break;
+			case MP_BUS:
+				++num_bus;
+				mpt += sizeof(struct mpc_config_bus);
+				count += sizeof(struct mpc_config_bus);
+				break;
+			case MP_INTSRC:
+				++num_irq;
+				mpt += sizeof(struct mpc_config_intsrc);
+				count += sizeof(struct mpc_config_intsrc);
+				break;
+			case MP_IOAPIC:
+				mpt += sizeof(struct mpc_config_ioapic);
+				count += sizeof(struct mpc_config_ioapic);
+				break;
+			case MP_LINTSRC:
+				mpt += sizeof(struct mpc_config_lintsrc);
+				count += sizeof(struct mpc_config_lintsrc);
+				break;
+			default:
+				count = mpc->mpc_length;
+				break;
+		}
+	}
+	/* 
+	 * Paranoia: Allocate one extra of both the number of busses and number
+	 * of irqs, and make sure that we have at least 4 interrupts per PCI
+	 * slot.  But some machines do not report very many busses, so we need
+	 * to fall back on the older defaults.
+	 */
+	++num_bus;
+	max_mp_busses = max(num_bus, MAX_MP_BUSSES);
+	if (num_irq < (4 * max_mp_busses))
+		num_irq = 4 * num_bus;	/* 4 intr/PCI slot */
+	++num_irq;
+	max_irq_sources = max(num_irq, MAX_IRQ_SOURCES);
+	
+	count = (max_mp_busses * sizeof(int)) * 4;
+	count += (max_irq_sources * sizeof(struct mpc_config_intsrc));
+	bus_data = alloc_bootmem(count);
+	if (!bus_data) {
+		printk(KERN_ERR "SMP mptable: out of memory!\n");
+		return 0;
+	}
+	mp_bus_id_to_type = (int *)&bus_data[0];
+	mp_bus_id_to_node = (int *)&bus_data[(max_mp_busses * sizeof(int))];
+	mp_bus_id_to_local = (int *)&bus_data[(max_mp_busses * sizeof(int)) * 2];
+	mp_bus_id_to_pci_bus = (int *)&bus_data[(max_mp_busses * sizeof(int)) * 3];
+	mp_irqs = (struct mpc_config_intsrc *)&bus_data[(max_mp_busses * sizeof(int)) * 4];
+	memset(mp_bus_id_to_pci_bus, -1, max_mp_busses);
+
 	/*
 	 *	Now process the configuration blocks.
 	 */
+	count = sizeof(*mpc);
+	mpt = ((unsigned char *)mpc)+count;
 	while (count < mpc->mpc_length) {
 		switch(*mpt) {
 			case MP_PROCESSOR:
@@ -510,9 +583,19 @@
 	}
 
 	if (clustered_apic_mode){
-		esr_disable = 1;
+		phys_cpu_present_map = logical_cpu_present_map;
 	}
 
+
+	printk("Enabling APIC mode: ");
+	if(clustered_apic_mode == CLUSTERED_APIC_NUMAQ)
+		printk("Clustered Logical.	");
+	else if(clustered_apic_mode == CLUSTERED_APIC_XAPIC)
+		printk("Physical.	");
+	else
+		printk("Flat.	");
+	printk("Using %d I/O APICs\n",nr_ioapics);
+
 	if (!num_processors)
 		printk(KERN_ERR "SMP mptable: no processors registered!\n");
 	return num_processors;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/scx200.c linux-2.4.21/arch/i386/kernel/scx200.c
--- linux-2.4.20/arch/i386/kernel/scx200.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/arch/i386/kernel/scx200.c	2002-12-18 18:58:11.000000000 +0000
@@ -0,0 +1,128 @@
+/* linux/arch/i386/kernel/scx200.c 
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   National Semiconductor SCx200 support. */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <linux/scx200.h>
+#include <linux/scx200.h>
+
+#define NAME "scx200"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 Driver");
+MODULE_LICENSE("GPL");
+
+unsigned scx200_gpio_base = 0;
+long scx200_gpio_shadow[2];
+
+spinlock_t scx200_gpio_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t scx200_gpio_config_lock = SPIN_LOCK_UNLOCKED;
+
+u32 scx200_gpio_configure(int index, u32 mask, u32 bits)
+{
+	u32 config, new_config;
+	unsigned long flags;
+
+	spin_lock_irqsave(&scx200_gpio_config_lock, flags);
+
+	outl(index, scx200_gpio_base + 0x20);
+	config = inl(scx200_gpio_base + 0x24);
+
+	new_config = (config & mask) | bits;
+	outl(new_config, scx200_gpio_base + 0x24);
+
+	spin_unlock_irqrestore(&scx200_gpio_config_lock, flags);
+
+	return config;
+}
+
+void scx200_gpio_dump(unsigned index)
+{
+	u32 config = scx200_gpio_configure(index, ~0, 0);
+	printk(KERN_DEBUG "GPIO%02u: 0x%08lx", index, (unsigned long)config);
+	
+	if (config & 1) 
+		printk(" OE"); /* output enabled */
+	else
+		printk(" TS"); /* tristate */
+	if (config & 2) 
+		printk(" PP"); /* push pull */
+	else
+		printk(" OD"); /* open drain */
+	if (config & 4) 
+		printk(" PUE"); /* pull up enabled */
+	else
+		printk(" PUD"); /* pull up disabled */
+	if (config & 8) 
+		printk(" LOCKED"); /* locked */
+	if (config & 16) 
+		printk(" LEVEL"); /* level input */
+	else
+		printk(" EDGE"); /* edge input */
+	if (config & 32) 
+		printk(" HI"); /* trigger on rising edge */
+	else
+		printk(" LO"); /* trigger on falling edge */
+	if (config & 64) 
+		printk(" DEBOUNCE"); /* debounce */
+	printk("\n");
+}
+
+int __init scx200_init(void)
+{
+	struct pci_dev *bridge;
+	int bank;
+	unsigned base;
+
+	printk(KERN_INFO NAME ": NatSemi SCx200 Driver\n");
+
+	if ((bridge = pci_find_device(PCI_VENDOR_ID_NS, 
+				      PCI_DEVICE_ID_NS_SCx200_BRIDGE,
+				      NULL)) == NULL)
+		return -ENODEV;
+
+	base = pci_resource_start(bridge, 0);
+	printk(KERN_INFO NAME ": GPIO base 0x%x\n", base);
+
+	if (request_region(base, SCx200_GPIO_SIZE, "NatSemi SCx200 GPIO") == 0) {
+		printk(KERN_ERR NAME ": can't allocate I/O for GPIOs\n");
+		return -EBUSY;
+	}
+
+	scx200_gpio_base = base;
+
+	/* read the current values driven on the GPIO signals */
+	for (bank = 0; bank < 2; ++bank)
+		scx200_gpio_shadow[bank] = inl(scx200_gpio_base + 0x10 * bank);
+
+	return 0;
+}
+
+void __exit scx200_cleanup(void)
+{
+	release_region(scx200_gpio_base, SCx200_GPIO_SIZE);
+}
+
+module_init(scx200_init);
+module_exit(scx200_cleanup);
+
+EXPORT_SYMBOL(scx200_gpio_base);
+EXPORT_SYMBOL(scx200_gpio_shadow);
+EXPORT_SYMBOL(scx200_gpio_lock);
+EXPORT_SYMBOL(scx200_gpio_configure);
+EXPORT_SYMBOL(scx200_gpio_dump);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../../.. SUBDIRS=arch/i386/kernel modules"
+        c-basic-offset: 8
+    End:
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/setup.c linux-2.4.21/arch/i386/kernel/setup.c
--- linux-2.4.20/arch/i386/kernel/setup.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/i386/kernel/setup.c	2002-12-18 18:58:08.000000000 +0000
@@ -1259,15 +1259,6 @@
 			l2size = 256;
 	}
 
-	/* Intel PIII Tualatin. This comes in two flavours.
-	 * One has 256kb of cache, the other 512. We have no way
-	 * to determine which, so we use a boottime override
-	 * for the 512kb model, and assume 256 otherwise.
-	 */
-	if ((c->x86_vendor == X86_VENDOR_INTEL) && (c->x86 == 6) &&
-		(c->x86_model == 11) && (l2size == 0))
-		l2size = 256;
-
 	/* VIA C3 CPUs (670-68F) need further shifting. */
 	if (c->x86_vendor == X86_VENDOR_CENTAUR && (c->x86 == 6) &&
 		((c->x86_model == 7) || (c->x86_model == 8))) {
@@ -2183,6 +2174,7 @@
 #define LVL_1_DATA      2
 #define LVL_2           3
 #define LVL_3           4
+#define LVL_TRACE       5
 
 struct _cache_table
 {
@@ -2202,6 +2194,8 @@
 	{ 0x23, LVL_3,      1024 },
 	{ 0x25, LVL_3,      2048 },
 	{ 0x29, LVL_3,      4096 },
+	{ 0x39, LVL_2,      128 },
+	{ 0x3C, LVL_2,      256 },
 	{ 0x41, LVL_2,      128 },
 	{ 0x42, LVL_2,      256 },
 	{ 0x43, LVL_2,      512 },
@@ -2210,11 +2204,15 @@
 	{ 0x66, LVL_1_DATA, 8 },
 	{ 0x67, LVL_1_DATA, 16 },
 	{ 0x68, LVL_1_DATA, 32 },
+	{ 0x70, LVL_TRACE,  12 },
+	{ 0x71, LVL_TRACE,  16 },
+	{ 0x72, LVL_TRACE,  32 },
 	{ 0x79, LVL_2,      128 },
 	{ 0x7A, LVL_2,      256 },
 	{ 0x7B, LVL_2,      512 },
 	{ 0x7C, LVL_2,      1024 },
 	{ 0x82, LVL_2,      256 },
+	{ 0x83, LVL_2,      512 },
 	{ 0x84, LVL_2,      1024 },
 	{ 0x85, LVL_2,      2048 },
 	{ 0x00, 0, 0}
@@ -2222,7 +2220,7 @@
 
 static void __init init_intel(struct cpuinfo_x86 *c)
 {
-	unsigned int l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
+	unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
 	char *p = NULL;
 #ifndef CONFIG_X86_F00F_WORKS_OK
 	static int f00f_workaround_enabled = 0;
@@ -2282,8 +2280,10 @@
 						case LVL_3:
 							l3 += cache_table[k].size;
 							break;
+						case LVL_TRACE:
+							trace += cache_table[k].size;
+							break;
 						}
-
 						break;
 					}
 
@@ -2291,9 +2291,25 @@
 				}
 			}
 		}
-		if ( l1i || l1d )
-			printk(KERN_INFO "CPU: L1 I cache: %dK, L1 D cache: %dK\n",
-			       l1i, l1d);
+
+		/* Intel PIII Tualatin. This comes in two flavours.
+		 * One has 256kb of cache, the other 512. We have no way
+		 * to determine which, so we use a boottime override
+		 * for the 512kb model, and assume 256 otherwise.
+		 */
+		if ((c->x86 == 6) && (c->x86_model == 11) && (l2 == 0))
+			l2 = 256;
+		/* Allow user to override all this if necessary. */
+		if (cachesize_override != -1)
+			l2 = cachesize_override;
+
+		if ( trace )
+			printk (KERN_INFO "CPU: Trace cache: %dK uops", trace);
+		else if ( l1i )
+			printk (KERN_INFO "CPU: L1 I cache: %dK", l1i);
+		if ( l1d )
+			printk(", L1 D cache: %dK\n", l1d);
+
 		if ( l2 )
 			printk(KERN_INFO "CPU: L2 cache: %dK\n", l2);
 		if ( l3 )
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/smp.c linux-2.4.21/arch/i386/kernel/smp.c
--- linux-2.4.20/arch/i386/kernel/smp.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/i386/kernel/smp.c	2002-12-18 18:58:03.000000000 +0000
@@ -214,7 +214,10 @@
 			/*
 			 * prepare target chip field
 			 */
-			cfg = __prepare_ICR2(cpu_to_logical_apicid(query_cpu));
+			if(clustered_apic_mode == CLUSTERED_APIC_XAPIC)
+				cfg = __prepare_ICR2(cpu_to_physical_apicid(query_cpu));
+			else
+				cfg = __prepare_ICR2(cpu_to_logical_apicid(query_cpu));
 			apic_write_around(APIC_ICR2, cfg);
 		
 			/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/smpboot.c linux-2.4.21/arch/i386/kernel/smpboot.c
--- linux-2.4.20/arch/i386/kernel/smpboot.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/i386/kernel/smpboot.c	2002-12-18 18:58:08.000000000 +0000
@@ -410,7 +410,7 @@
 	Dprintk("CALLIN, before setup_local_APIC().\n");
 	/*
 	 * Because we use NMIs rather than the INIT-STARTUP sequence to
-	 * bootstrap the CPUs, the APIC may be in a wierd state. Kick it.
+	 * bootstrap the CPUs, the APIC may be in a weird state. Kick it.
 	 */
 	if (clustered_apic_mode)
 		clear_local_APIC();
@@ -525,12 +525,12 @@
 	int apicid, cpu;
 
 	for (apicid = 0; apicid < MAX_APICID; apicid++) {
-		physical_apicid_2_cpu[apicid] = -1;
-		logical_apicid_2_cpu[apicid] = -1;
+		physical_apicid_2_cpu[apicid] = BAD_APICID;
+		logical_apicid_2_cpu[apicid] = BAD_APICID;
 	}
 	for (cpu = 0; cpu < NR_CPUS; cpu++) {
-		cpu_2_physical_apicid[cpu] = -1;
-		cpu_2_logical_apicid[cpu] = -1;
+		cpu_2_physical_apicid[cpu] = BAD_APICID;
+		cpu_2_logical_apicid[cpu] = BAD_APICID;
 	}
 }
 
@@ -540,7 +540,7 @@
  * else physical apic ids
  */
 {
-	if (clustered_apic_mode) {
+	if (clustered_apic_mode == CLUSTERED_APIC_NUMAQ) {
 		logical_apicid_2_cpu[apicid] = cpu;	
 		cpu_2_logical_apicid[cpu] = apicid;
 	} else {
@@ -555,12 +555,12 @@
  * else physical apic ids
  */
 {
-	if (clustered_apic_mode) {
-		logical_apicid_2_cpu[apicid] = -1;	
-		cpu_2_logical_apicid[cpu] = -1;
+	if (clustered_apic_mode == CLUSTERED_APIC_NUMAQ) {
+		logical_apicid_2_cpu[apicid] = BAD_APICID;
+		cpu_2_logical_apicid[cpu] = BAD_APICID;
 	} else {
-		physical_apicid_2_cpu[apicid] = -1;	
-		cpu_2_physical_apicid[cpu] = -1;
+		physical_apicid_2_cpu[apicid] = BAD_APICID;
+		cpu_2_physical_apicid[cpu] = BAD_APICID;
 	}
 }
 
@@ -785,7 +785,7 @@
 	unsigned long boot_error = 0;
 	int timeout, cpu;
 	unsigned long start_eip;
-	unsigned short nmi_high, nmi_low;
+	unsigned short nmi_high = 0, nmi_low = 0;
 
 	cpu = ++cpucount;
 	/*
@@ -1019,7 +1019,10 @@
 	 * We have the boot CPU online for sure.
 	 */
 	set_bit(0, &cpu_online_map);
-	boot_cpu_logical_apicid = logical_smp_processor_id();
+	if (clustered_apic_mode == CLUSTERED_APIC_XAPIC)
+		boot_cpu_logical_apicid = physical_to_logical_apicid(boot_cpu_physical_apicid);
+	else
+		boot_cpu_logical_apicid = logical_smp_processor_id();
 	map_cpu_to_boot_apicid(0, boot_cpu_apicid);
 
 	global_irq_holder = 0;
@@ -1111,7 +1114,7 @@
 		if (apicid == boot_cpu_apicid)
 			continue;
 
-		if (!(phys_cpu_present_map & (1 << bit)))
+		if (!(phys_cpu_present_map & (1ul << bit)))
 			continue;
 		if ((max_cpus >= 0) && (max_cpus <= cpucount+1))
 			continue;
@@ -1122,9 +1125,9 @@
 		 * Make sure we unmap all failed CPUs
 		 */
 		if ((boot_apicid_to_cpu(apicid) == -1) &&
-				(phys_cpu_present_map & (1 << bit)))
-			printk("CPU #%d not responding - cannot use it.\n",
-								apicid);
+				(phys_cpu_present_map & (1ul << bit)))
+			printk("CPU #%d/0x%02x not responding - cannot use it.\n",
+								bit, apicid);
 	}
 
 	/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/time.c linux-2.4.21/arch/i386/kernel/time.c
--- linux-2.4.20/arch/i386/kernel/time.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/i386/kernel/time.c	2002-12-18 18:58:08.000000000 +0000
@@ -256,12 +256,177 @@
 
 static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
 
+
+/* IBM Summit (EXA) Cyclone Timer code*/
+#ifdef CONFIG_X86_SUMMIT
+
+#define CYCLONE_CBAR_ADDR 0xFEB00CD0
+#define CYCLONE_PMCC_OFFSET 0x51A0
+#define CYCLONE_MPMC_OFFSET 0x51D0
+#define CYCLONE_MPCS_OFFSET 0x51A8
+#define CYCLONE_TIMER_FREQ 100000000
+
+int use_cyclone = 0;
+int __init cyclone_setup(char *str) 
+{
+	use_cyclone = 1;
+	return 1;
+}
+
+static u32* volatile cyclone_timer;	/* Cyclone MPMC0 register */
+static u32 last_cyclone_timer;
+
+static inline void mark_timeoffset_cyclone(void)
+{
+	int count;
+	spin_lock(&i8253_lock);
+	/* quickly read the cyclone timer */
+	if(cyclone_timer)
+		last_cyclone_timer = cyclone_timer[0];
+
+	/* calculate delay_at_last_interrupt */
+	outb_p(0x00, 0x43);     /* latch the count ASAP */
+
+	count = inb_p(0x40);    /* read the latched count */
+	count |= inb(0x40) << 8;
+	spin_unlock(&i8253_lock);
+
+	count = ((LATCH-1) - count) * TICK_SIZE;
+	delay_at_last_interrupt = (count + LATCH/2) / LATCH;
+}
+
+static unsigned long do_gettimeoffset_cyclone(void)
+{
+	u32 offset;
+
+	if(!cyclone_timer)
+		return delay_at_last_interrupt;
+
+	/* Read the cyclone timer */
+	offset = cyclone_timer[0];
+
+	/* .. relative to previous jiffy */
+	offset = offset - last_cyclone_timer;
+
+	/* convert cyclone ticks to microseconds */	
+	/* XXX slow, can we speed this up? */
+	offset = offset/(CYCLONE_TIMER_FREQ/1000000);
+
+	/* our adjusted time offset in microseconds */
+	return delay_at_last_interrupt + offset;
+}
+
+static void __init init_cyclone_clock(void)
+{
+	u32* reg;	
+	u32 base;		/* saved cyclone base address */
+	u32 pageaddr;	/* page that contains cyclone_timer register */
+	u32 offset;		/* offset from pageaddr to cyclone_timer register */
+	int i;
+	
+	printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
+
+	/* find base address */
+	pageaddr = (CYCLONE_CBAR_ADDR)&PAGE_MASK;
+	offset = (CYCLONE_CBAR_ADDR)&(~PAGE_MASK);
+	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
+	reg = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
+	if(!reg){
+		printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n");
+		use_cyclone = 0;
+		return;
+	}
+	base = *reg;	
+	if(!base){
+		printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
+		use_cyclone = 0;
+		return;
+	}
+	
+	/* setup PMCC */
+	pageaddr = (base + CYCLONE_PMCC_OFFSET)&PAGE_MASK;
+	offset = (base + CYCLONE_PMCC_OFFSET)&(~PAGE_MASK);
+	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
+	reg = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
+	if(!reg){
+		printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n");
+		use_cyclone = 0;
+		return;
+	}
+	reg[0] = 0x00000001;
+
+	/* setup MPCS */
+	pageaddr = (base + CYCLONE_MPCS_OFFSET)&PAGE_MASK;
+	offset = (base + CYCLONE_MPCS_OFFSET)&(~PAGE_MASK);
+	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
+	reg = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
+	if(!reg){
+		printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n");
+		use_cyclone = 0;
+		return;
+	}
+	reg[0] = 0x00000001;
+
+	/* map in cyclone_timer */
+	pageaddr = (base + CYCLONE_MPMC_OFFSET)&PAGE_MASK;
+	offset = (base + CYCLONE_MPMC_OFFSET)&(~PAGE_MASK);
+	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
+	cyclone_timer = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
+	if(!cyclone_timer){
+		printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n");
+		use_cyclone = 0;
+		return;
+	}
+
+	/*quick test to make sure its ticking*/
+	for(i=0; i<3; i++){
+		u32 old = cyclone_timer[0];
+		int stall = 100;
+		while(stall--) barrier();
+		if(cyclone_timer[0] == old){
+			printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n");
+			cyclone_timer = 0;
+			use_cyclone = 0;
+			return;
+		}
+	}
+	/* Everything looks good, so set do_gettimeoffset */
+	do_gettimeoffset = do_gettimeoffset_cyclone;	
+}
+void __cyclone_delay(unsigned long loops)
+{
+	unsigned long bclock, now;
+	if(!cyclone_timer)
+		return;
+	bclock = cyclone_timer[0];
+	do {
+		rep_nop();
+		now = cyclone_timer[0];
+	} while ((now-bclock) < loops);
+}
+#endif /* CONFIG_X86_SUMMIT */
+
 #else
 
 #define do_gettimeoffset()	do_fast_gettimeoffset()
 
 #endif
 
+/* No-cyclone stubs */
+#ifndef CONFIG_X86_SUMMIT
+int __init cyclone_setup(char *str) 
+{
+	printk(KERN_ERR "cyclone: Kernel not compiled with CONFIG_X86_SUMMIT, cannot use the cyclone-timer.\n");
+	return 1;
+}
+
+const int use_cyclone = 0;
+static void mark_timeoffset_cyclone(void) {}
+static unsigned long do_gettimeoffset_cyclone(void) {return 0;}
+static void init_cyclone_clock(void) {}
+void __cyclone_delay(unsigned long loops) {}
+#endif /* CONFIG_X86_SUMMIT */
+
 /*
  * This version of gettimeofday has microsecond resolution
  * and better than microsecond precision on fast x86 machines with TSC.
@@ -481,8 +646,9 @@
 	 */
 	write_lock(&xtime_lock);
 
-	if (use_tsc)
-	{
+	if(use_cyclone)
+		mark_timeoffset_cyclone();
+	else if (use_tsc) {
 		/*
 		 * It is important that these two operations happen almost at
 		 * the same time. We do the RDTSC stuff first, since it's
@@ -504,12 +670,34 @@
 
 		count = inb_p(0x40);    /* read the latched count */
 		count |= inb(0x40) << 8;
+
+		/* Any unpaired read will cause the above to swap MSB/LSB
+		   forever.  Try to detect this and reset the counter. 
+		   
+		   This happens very occasionally with buggy SMM bios
+		   code at least */
+		   
+		if (count > LATCH) {
+			printk(KERN_WARNING 
+			       "i8253 count too high! resetting..\n");
+			outb_p(0x34, 0x43);
+			outb_p(LATCH & 0xff, 0x40);
+			outb(LATCH >> 8, 0x40);
+			count = LATCH - 1;
+		}
+
 		spin_unlock(&i8253_lock);
 
+		/* Some i8253 clones hold the LATCH value visible
+		   momentarily as they flip back to zero */
+		if (count == LATCH) {
+			count--;
+		}
+
 		count = ((LATCH-1) - count) * TICK_SIZE;
 		delay_at_last_interrupt = (count + LATCH/2) / LATCH;
 	}
- 
+
 	do_timer_interrupt(irq, NULL, regs);
 
 	write_unlock(&xtime_lock);
@@ -670,21 +858,30 @@
  	 */
  
  	dodgy_tsc();
- 	
+
+ 	if(use_cyclone)
+		init_cyclone_clock();
+		
 	if (cpu_has_tsc) {
 		unsigned long tsc_quotient = calibrate_tsc();
 		if (tsc_quotient) {
 			fast_gettimeoffset_quotient = tsc_quotient;
-			use_tsc = 1;
-			/*
-			 *	We could be more selective here I suspect
-			 *	and just enable this for the next intel chips ?
+			/* XXX: This is messy
+			 * However, we want to allow for the cyclone timer 
+			 * to work w/ or w/o the TSCs being avaliable
+			 *      -johnstul@us.ibm.com
 			 */
-			x86_udelay_tsc = 1;
+			if(!use_cyclone){
+				/*
+				 *	We could be more selective here I suspect
+				 *	and just enable this for the next intel chips ?
+			 	 */
+				use_tsc = 1;
+				x86_udelay_tsc = 1;
 #ifndef do_gettimeoffset
-			do_gettimeoffset = do_fast_gettimeoffset;
+				do_gettimeoffset = do_fast_gettimeoffset;
 #endif
-
+			}
 			/* report CPU clock rate in Hz.
 			 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
 			 * clock/second. Our precision is about 100 ppm.
@@ -699,6 +896,7 @@
 		}
 	}
 
+
 #ifdef CONFIG_VISWS
 	printk("Starting Cobalt Timer system clock\n");
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/lib/delay.c linux-2.4.21/arch/i386/lib/delay.c
--- linux-2.4.20/arch/i386/lib/delay.c	2001-08-12 17:29:44.000000000 +0000
+++ linux-2.4.21/arch/i386/lib/delay.c	2002-12-18 18:58:11.000000000 +0000
@@ -56,10 +56,13 @@
 		:"=&a" (d0)
 		:"0" (loops));
 }
-
+extern __cyclone_delay(unsigned long loops);
+extern int use_cyclone;
 void __delay(unsigned long loops)
 {
-	if (x86_udelay_tsc)
+	if (use_cyclone)
+		__cyclone_delay(loops);
+	else if (x86_udelay_tsc)
 		__rdtsc_delay(loops);
 	else
 		__loop_delay(loops);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/mm/init.c linux-2.4.21/arch/i386/mm/init.c
--- linux-2.4.20/arch/i386/mm/init.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/i386/mm/init.c	2002-12-18 18:58:04.000000000 +0000
@@ -356,7 +356,7 @@
 
 #if CONFIG_X86_PAE
 	/*
-	 * We will bail out later - printk doesnt work right now so
+	 * We will bail out later - printk doesn't work right now so
 	 * the user would just see a hanging kernel.
 	 */
 	if (cpu_has_pae)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/boot/bootloader.c linux-2.4.21/arch/ia64/boot/bootloader.c
--- linux-2.4.20/arch/ia64/boot/bootloader.c	2001-07-31 17:30:08.000000000 +0000
+++ linux-2.4.21/arch/ia64/boot/bootloader.c	2002-12-18 18:58:11.000000000 +0000
@@ -53,6 +53,15 @@
 
 #include "../kernel/fw-emu.c"
 
+/*
+ * Set a break point on this function so that symbols are available to set breakpoints in
+ * the kernel being debugged.
+ */
+static void
+debug_break (void)
+{
+}
+
 static void
 cons_write (const char *buf)
 {
@@ -187,6 +196,7 @@
 
 	ssc(0, (long) kpath, 0, 0, SSC_LOAD_SYMBOLS);
 
+	debug_break();
 	asm volatile ("mov sp=%2; mov r28=%1; br.sptk.few %0"
 		      :: "b"(e_entry), "r"(bp), "r"(__pa(&stack)));
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/config.in linux-2.4.21/arch/ia64/config.in
--- linux-2.4.20/arch/ia64/config.in	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/config.in	2002-12-18 18:58:09.000000000 +0000
@@ -51,8 +51,6 @@
 	 64KB			CONFIG_IA64_PAGE_SIZE_64KB" 16KB
 fi
 
-bool 'Virtually mapped mem_map?' CONFIG_VIRTUAL_MEM_MAP n
-
 if [ "$CONFIG_ITANIUM" = "y" ]; then
 	define_bool CONFIG_IA64_BRL_EMU y
 	bool '  Enable Itanium B-step specific code' CONFIG_ITANIUM_BSTEP_SPECIFIC
@@ -65,10 +63,6 @@
 
 if [ "$CONFIG_MCKINLEY" = "y" ]; then
 	define_int CONFIG_IA64_L1_CACHE_SHIFT 7
-	bool '  Enable McKinley A-step specific code' CONFIG_MCKINLEY_ASTEP_SPECIFIC
-	if [ "$CONFIG_MCKINLEY_ASTEP_SPECIFIC" = "y" ]; then
-	  bool '   Enable McKinley A0/A1-step specific code' CONFIG_MCKINLEY_A0_SPECIFIC
-	fi
 fi
 
 if [ "$CONFIG_IA64_GENERIC" = "y" -o "$CONFIG_IA64_DIG" = "y" -o "$CONFIG_IA64_HP_ZX1" = "y" ]; then
@@ -256,10 +250,10 @@
   mainmenu_option next_comment
   comment 'Simulated drivers'
 
-  bool 'Simulated Ethernet ' CONFIG_SIMETH
-  bool 'Simulated serial driver support' CONFIG_SIM_SERIAL
+  bool 'Simulated Ethernet ' CONFIG_HP_SIMETH
+  bool 'Simulated serial driver support' CONFIG_HP_SIMSERIAL
   if [ "$CONFIG_SCSI" != "n" ]; then
-    bool 'Simulated SCSI disk' CONFIG_SCSI_SIM
+    bool 'Simulated SCSI disk' CONFIG_HP_SIMSCSI
   fi
   endmenu
 fi
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/defconfig linux-2.4.21/arch/ia64/defconfig
--- linux-2.4.20/arch/ia64/defconfig	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/defconfig	2002-12-18 18:58:03.000000000 +0000
@@ -35,7 +35,6 @@
 # CONFIG_IA64_PAGE_SIZE_4KB is not set
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
 CONFIG_IA64_PAGE_SIZE_16KB=y
-CONFIG_VIRTUAL_MEM_MAP=y
 CONFIG_IA64_BRL_EMU=y
 # CONFIG_ITANIUM_BSTEP_SPECIFIC is not set
 CONFIG_IA64_L1_CACHE_SHIFT=6
@@ -164,6 +163,7 @@
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
 
 #
 # IEEE 1394 (FireWire) support (EXPERIMENTAL)
@@ -402,13 +402,13 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 CONFIG_TULIP=y
-# CONFIG_TC35815 is not set
 # CONFIG_TULIP_MWI is not set
 # CONFIG_TULIP_MMIO is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 CONFIG_EEPRO100=y
+# CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -420,11 +420,13 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -434,10 +436,9 @@
 # Ethernet (1000 Mbit)
 #
 # CONFIG_ACENIC is not set
-# CONFIG_NET_BROADCOM is not set
 # CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
 CONFIG_E1000=y
+# CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
@@ -502,7 +503,6 @@
 CONFIG_SERIAL_CONSOLE=y
 CONFIG_SERIAL_HCDP=y
 # CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_ACPI is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
@@ -563,6 +563,7 @@
 #
 # CONFIG_WATCHDOG is not set
 # CONFIG_INTEL_RNG is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 CONFIG_EFI_RTC=y
@@ -579,6 +580,7 @@
 # CONFIG_AGP_I810 is not set
 # CONFIG_AGP_VIA is not set
 # CONFIG_AGP_AMD is not set
+# CONFIG_AGP_AMD_8151 is not set
 # CONFIG_AGP_SIS is not set
 # CONFIG_AGP_ALI is not set
 # CONFIG_AGP_SWORKS is not set
@@ -626,21 +628,10 @@
 #
 # Radio Adapters
 #
-# CONFIG_RADIO_CADET is not set
-# CONFIG_RADIO_RTRACK is not set
-# CONFIG_RADIO_RTRACK2 is not set
-# CONFIG_RADIO_AZTECH is not set
-# CONFIG_RADIO_GEMTEK is not set
 # CONFIG_RADIO_GEMTEK_PCI is not set
 # CONFIG_RADIO_MAXIRADIO is not set
 # CONFIG_RADIO_MAESTRO is not set
 # CONFIG_RADIO_MIROPCM20 is not set
-# CONFIG_RADIO_MIROPCM20_RDS is not set
-# CONFIG_RADIO_SF16FMI is not set
-# CONFIG_RADIO_TERRATEC is not set
-# CONFIG_RADIO_TRUST is not set
-# CONFIG_RADIO_TYPHOON is not set
-# CONFIG_RADIO_ZOLTRIX is not set
 
 #
 # File systems
@@ -655,9 +646,11 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
 # CONFIG_BFS_FS is not set
-CONFIG_EXT3_FS=m
-CONFIG_JBD=m
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
 CONFIG_JBD_DEBUG=y
 CONFIG_FAT_FS=y
 CONFIG_MSDOS_FS=y
@@ -672,6 +665,9 @@
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -702,6 +698,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
@@ -716,7 +713,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -796,9 +792,9 @@
 # Sound
 #
 CONFIG_SOUND=y
+# CONFIG_SOUND_ALI5455 is not set
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
-# CONFIG_SOUND_FORTE is not set
 # CONFIG_SOUND_EMU10K1 is not set
 # CONFIG_MIDI_EMU10K1 is not set
 # CONFIG_SOUND_FUSION is not set
@@ -808,6 +804,7 @@
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
 # CONFIG_SOUND_ICH is not set
 # CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
@@ -846,6 +843,7 @@
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_EMI26 is not set
 # CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_MIDI is not set
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -854,6 +852,7 @@
 # CONFIG_USB_STORAGE_DPCM is not set
 # CONFIG_USB_STORAGE_HP8200e is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
@@ -866,6 +865,7 @@
 CONFIG_USB_HIDDEV=y
 CONFIG_USB_KBD=m
 CONFIG_USB_MOUSE=m
+# CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
 
 #
@@ -908,39 +908,21 @@
 # USB Serial Converter support
 #
 # CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
 
 #
 # USB Miscellaneous drivers
 #
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_TIGL is not set
 # CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Bluetooth support
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/hp/common/sba_iommu.c linux-2.4.21/arch/ia64/hp/common/sba_iommu.c
--- linux-2.4.20/arch/ia64/hp/common/sba_iommu.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/hp/common/sba_iommu.c	2002-12-18 18:58:10.000000000 +0000
@@ -39,8 +39,25 @@
 
 #define PFX "IOC: "
 
+/*
+** This option allows cards capable of 64bit DMA to bypass the IOMMU.  If
+** not defined, all DMA will be 32bit and go through the TLB.
+*/
 #define ALLOW_IOV_BYPASS
+
+/*
+** If a device prefetches beyond the end of a valid pdir entry, it will cause
+** a hard failure, ie. MCA.  Version 3.0 and later of the zx1 LBA should
+** disconnect on 4k boundaries and prevent such issues.  If the device is
+** particularly agressive, this option will keep the entire pdir valid such
+** that prefetching will hit a valid address.  This could severely impact
+** error containment, and is therefore off by default.  The page that is
+** used for spill-over is poisoned, so that should help debugging somewhat.
+*/
+#undef FULL_VALID_PDIR
+
 #define ENABLE_MARK_CLEAN
+
 /*
 ** The number of debug flags is a clue - this code is fragile.
 */
@@ -52,6 +69,10 @@
 #undef DEBUG_LARGE_SG_ENTRIES
 #undef DEBUG_BYPASS
 
+#if defined(FULL_VALID_PDIR) && defined(ASSERT_PDIR_SANITY)
+#error FULL_VALID_PDIR and ASSERT_PDIR_SANITY are mutually exclusive
+#endif
+
 #define SBA_INLINE	__inline__
 /* #define SBA_INLINE */
 
@@ -196,9 +217,12 @@
 static struct ioc *ioc_list;
 static int reserve_sba_gart = 1;
 
-#define sba_sg_iova(sg) (sg->address)
-#define sba_sg_len(sg) (sg->length)
-#define sba_sg_buffer(sg) (sg->orig_address)
+#define sba_sg_address(sg)	(sg->address ? sg->address : \
+				       page_address((sg)->page) + (sg)->offset)
+
+#ifdef FULL_VALID_PDIR
+static void* prefetch_spill_page;
+#endif
 
 #define GET_IOC(dev)	((struct ioc *) PCI_CONTROLLER(dev)->iommu)
 
@@ -338,10 +362,8 @@
 {
 	while (nents-- > 0) {
 		printk(" %d : %08lx/%05x %p\n",
-				nents,
-				(unsigned long) sba_sg_iova(startsg),
-				sba_sg_len(startsg),
-				sba_sg_buffer(startsg));
+				nents, startsg->dma_address,
+				startsg->dma_length, sba_sg_address(startsg));
 		startsg++;
 	}
 }
@@ -352,7 +374,7 @@
 	int the_nents = nents;
 
 	while (the_nents-- > 0) {
-		if (sba_sg_buffer(the_sg) == 0x0UL)
+		if (sba_sg_address(the_sg) == 0x0UL)
 			sba_dump_sg(NULL, startsg, nents);
 		the_sg++;
 	}
@@ -626,7 +648,7 @@
 	pg_addr = PAGE_ALIGN((unsigned long) addr);
 	end = (unsigned long) addr + size;
 	while (pg_addr + PAGE_SIZE <= end) {
-		struct page *page = virt_to_page(pg_addr);
+		struct page *page = virt_to_page((void *)pg_addr);
 		set_bit(PG_arch_1, &page->flags);
 		pg_addr += PAGE_SIZE;
 	}
@@ -673,6 +695,7 @@
 
 		iovp |= IOVP_SHIFT;     /* set "size" field for PCOM */
 
+#ifndef FULL_VALID_PDIR
 		/*
 		** clear I/O PDIR entry "valid" bit
 		** Do NOT clear the rest - save it for debugging.
@@ -680,6 +703,14 @@
 		** been enabled.
 		*/
 		ioc->pdir_base[off] &= ~(0x80000000000000FFULL);
+#else
+		/*
+  		** If we want to maintain the PDIR as valid, put in
+		** the spill page so devices prefetching won't
+		** cause a hard fail.
+		*/
+		ioc->pdir_base[off] = (0x80000000000000FFULL | (u64)prefetch_spill_page);
+#endif
 	} else {
 		u32 t = get_order(byte_cnt) + PAGE_SHIFT;
 
@@ -689,14 +720,18 @@
 		do {
 			/* verify this pdir entry is enabled */
 			ASSERT(ioc->pdir_base[off]  >> 63);
+#ifndef FULL_VALID_PDIR
 			/* clear I/O Pdir entry "valid" bit first */
 			ioc->pdir_base[off] &= ~(0x80000000000000FFULL);
+#else
+			ioc->pdir_base[off] = (0x80000000000000FFULL | (u64)prefetch_spill_page);
+#endif
 			off++;
 			byte_cnt -= IOVP_SIZE;
 		} while (byte_cnt > 0);
 	}
 
-	WRITE_REG(iovp, ioc->ioc_hpa+IOC_PCOM);
+	WRITE_REG(iovp | ioc->ibase, ioc->ioc_hpa+IOC_PCOM);
 }
 
 /**
@@ -991,32 +1026,28 @@
 
 	dma_sg--;
 	while (nents-- > 0) {
-		int     cnt = sba_sg_len(startsg);
-		sba_sg_len(startsg) = 0;
+		int     cnt = startsg->dma_length;
+		startsg->dma_length = 0;
 
 #ifdef DEBUG_LARGE_SG_ENTRIES
 		if (dump_run_sg)
 			printk(" %2d : %08lx/%05x %p\n",
-				nents,
-				(unsigned long) sba_sg_iova(startsg), cnt,
-				sba_sg_buffer(startsg)
-		);
+				nents, startsg->dma_address, cnt,
+				sba_sg_address(startsg));
 #else
 		DBG_RUN_SG(" %d : %08lx/%05x %p\n",
-				nents,
-				(unsigned long) sba_sg_iova(startsg), cnt,
-				sba_sg_buffer(startsg)
-		);
+				nents, startsg->dma_address, cnt,
+				sba_sg_address(startsg));
 #endif
 		/*
 		** Look for the start of a new DMA stream
 		*/
-		if ((u64)sba_sg_iova(startsg) & PIDE_FLAG) {
-			u32 pide = (u64)sba_sg_iova(startsg) & ~PIDE_FLAG;
+		if (startsg->dma_address & PIDE_FLAG) {
+			u32 pide = startsg->dma_address & ~PIDE_FLAG;
 			dma_offset = (unsigned long) pide & ~IOVP_MASK;
-			sba_sg_iova(startsg) = 0;
+			startsg->dma_address = 0;
 			dma_sg++;
-			sba_sg_iova(dma_sg) = (char *)(pide | ioc->ibase);
+			dma_sg->dma_address = pide | ioc->ibase;
 			pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]);
 			n_mappings++;
 		}
@@ -1025,13 +1056,13 @@
 		** Look for a VCONTIG chunk
 		*/
 		if (cnt) {
-			unsigned long vaddr = (unsigned long) sba_sg_buffer(startsg);
+			unsigned long vaddr = (unsigned long) sba_sg_address(startsg);
 			ASSERT(pdirp);
 
 			/* Since multiple Vcontig blocks could make up
 			** one DMA stream, *add* cnt to dma_len.
 			*/
-			sba_sg_len(dma_sg) += cnt;
+			dma_sg->dma_length += cnt;
 			cnt += dma_offset;
 			dma_offset=0;	/* only want offset on first chunk */
 			cnt = ROUNDUP(cnt, IOVP_SIZE);
@@ -1091,20 +1122,18 @@
 	int n_mappings = 0;
 
 	while (nents > 0) {
-		unsigned long vaddr = (unsigned long) (startsg->address); 
+		unsigned long vaddr = (unsigned long) sba_sg_address(startsg); 
 
 		/*
 		** Prepare for first/next DMA stream
 		*/
 		dma_sg = vcontig_sg = startsg;
-		dma_len = vcontig_len = vcontig_end = sba_sg_len(startsg);
+		dma_len = vcontig_len = vcontig_end = startsg->length;
 		vcontig_end +=  vaddr;
 		dma_offset = vaddr & ~IOVP_MASK;
 
 		/* PARANOID: clear entries */
-		sba_sg_buffer(startsg) = sba_sg_iova(startsg);
-		sba_sg_iova(startsg) = 0;
-		sba_sg_len(startsg) = 0;
+		startsg->dma_address = startsg->dma_length = 0;
 
 		/*
 		** This loop terminates one iteration "early" since
@@ -1115,6 +1144,9 @@
 
 			startsg++;
 
+			/* PARANOID */
+			startsg->dma_address = startsg->dma_length = 0;
+
 			/* catch brokenness in SCSI layer */
 			ASSERT(startsg->length <= DMA_CHUNK_SIZE);
 
@@ -1131,15 +1163,12 @@
 			**
 			** append the next transaction?
 			*/
-			vaddr = (unsigned long) sba_sg_iova(startsg);
+			vaddr = (unsigned long) sba_sg_address(startsg);
 			if  (vcontig_end == vaddr)
 			{
-				vcontig_len += sba_sg_len(startsg);
-				vcontig_end += sba_sg_len(startsg);
-				dma_len     += sba_sg_len(startsg);
-				sba_sg_buffer(startsg) = (char *)vaddr;
-				sba_sg_iova(startsg) = 0;
-				sba_sg_len(startsg) = 0;
+				vcontig_len += startsg->length;
+				vcontig_end += startsg->length;
+				dma_len     += startsg->length;
 				continue;
 			}
 
@@ -1158,10 +1187,10 @@
 			** must start on page boundaries and dove tail
 			** with it's predecessor.
 			*/
-			sba_sg_len(vcontig_sg) = vcontig_len;
+			vcontig_sg->dma_length = vcontig_len;
 
 			vcontig_sg = startsg;
-			vcontig_len = sba_sg_len(startsg);
+			vcontig_len = startsg->length;
 
 			/*
 			** 3) do the entries end/start on page boundaries?
@@ -1171,8 +1200,6 @@
 			{
 				vcontig_end = vcontig_len + vaddr;
 				dma_len += vcontig_len;
-				sba_sg_buffer(startsg) = (char *)vaddr;
-				sba_sg_iova(startsg) = 0;
 				continue;
 			} else {
 				break;
@@ -1184,10 +1211,10 @@
 		** Terminate last VCONTIG block.
 		** Allocate space for DMA stream.
 		*/
-		sba_sg_len(vcontig_sg) = vcontig_len;
+		vcontig_sg->dma_length = vcontig_len;
 		dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK;
 		ASSERT(dma_len <= DMA_CHUNK_SIZE);
-		sba_sg_iova(dma_sg) = (char *) (PIDE_FLAG 
+		dma_sg->dma_address = (dma_addr_t) (PIDE_FLAG 
 			| (sba_alloc_range(ioc, dma_len) << IOVP_SHIFT)
 			| dma_offset);
 		n_mappings++;
@@ -1223,8 +1250,8 @@
 #ifdef ALLOW_IOV_BYPASS
 	if (dev->dma_mask >= ioc->dma_mask) {
 		for (sg = sglist ; filled < nents ; filled++, sg++){
-			sba_sg_buffer(sg) = sba_sg_iova(sg);
-			sba_sg_iova(sg) = (char *)virt_to_phys(sba_sg_buffer(sg));
+			sg->dma_length = sg->length;
+			sg->dma_address = virt_to_phys(sba_sg_address(sg));
 		}
 #ifdef CONFIG_PROC_FS
 		spin_lock_irqsave(&ioc->res_lock, flags);
@@ -1236,10 +1263,10 @@
 #endif
 	/* Fast path single entry scatterlists. */
 	if (nents == 1) {
-		sba_sg_buffer(sglist) = sba_sg_iova(sglist);
-		sba_sg_iova(sglist) = (char *)sba_map_single(dev,
-						sba_sg_buffer(sglist),
-						sba_sg_len(sglist), direction);
+		sglist->dma_length = sglist->length;
+		sglist->dma_address = sba_map_single(dev,
+		                                     sba_sg_address(sglist),
+		                                     sglist->length, direction);
 #ifdef CONFIG_PROC_FS
 		/*
 		** Should probably do some stats counting, but trying to
@@ -1318,7 +1345,7 @@
 #endif
 
 	DBG_RUN_SG("%s() START %d entries,  %p,%x\n",
-		__FUNCTION__, nents, sba_sg_buffer(sglist), sglist->length);
+		__FUNCTION__, nents, sba_sg_address(sglist), sglist->length);
 
 	ioc = GET_IOC(dev);
 	ASSERT(ioc);
@@ -1333,10 +1360,10 @@
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
 #endif
 
-	while (sba_sg_len(sglist) && nents--) {
+	while (nents && sglist->dma_length) {
 
-		sba_unmap_single(dev, (dma_addr_t)sba_sg_iova(sglist),
-		                 sba_sg_len(sglist), direction);
+		sba_unmap_single(dev, sglist->dma_address,
+		                 sglist->dma_length, direction);
 #ifdef CONFIG_PROC_FS
 		/*
 		** This leaves inconsistent data in the stats, but we can't
@@ -1344,9 +1371,10 @@
 		** were coalesced to a single entry.  The stats are fun,
 		** but speed is more important.
 		*/
-		ioc->usg_pages += (((u64)sba_sg_iova(sglist) & ~IOVP_MASK) + sba_sg_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT;
+		ioc->usg_pages += ((sglist->dma_address & ~IOVP_MASK) + sglist->dma_length + IOVP_SIZE - 1) >> PAGE_SHIFT;
 #endif
-		++sglist;
+		sglist++;
+		nents--;
 	}
 
 	DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__,  nents);
@@ -1359,12 +1387,6 @@
 
 }
 
-unsigned long
-sba_dma_address (struct scatterlist *sg)
-{
-	return ((unsigned long)sba_sg_iova(sg));
-}
-
 int
 sba_dma_supported (struct pci_dev *dev, u64 mask)
 {
@@ -1384,6 +1406,9 @@
 	int iov_order, tcnfg;
 	int agp_found = 0;
 	struct pci_dev *device;
+#ifdef FULL_VALID_PDIR
+	unsigned long index;
+#endif
 
 	/*
 	** Firmware programs the base and size of a "safe IOVA space"
@@ -1481,7 +1506,7 @@
 	** Clear I/O TLB of any possible entries.
 	** (Yes. This is a bit paranoid...but so what)
 	*/
-	WRITE_REG(0 | 31, ioc->ioc_hpa + IOC_PCOM);
+	WRITE_REG(ioc->ibase | (iov_order+PAGE_SHIFT), ioc->ioc_hpa + IOC_PCOM);
 
 	/*
 	** If an AGP device is present, only use half of the IOV space
@@ -1499,6 +1524,34 @@
 		ioc->pdir_size /= 2;
 		((u64 *)ioc->pdir_base)[PDIR_INDEX(ioc->iov_size/2)] = ZX1_SBA_IOMMU_COOKIE;
 	}
+#ifdef FULL_VALID_PDIR
+	/*
+  	** Check to see if the spill page has been allocated, we don't need more than
+	** one across multiple SBAs.
+	*/
+	if (!prefetch_spill_page) {
+		char *spill_poison = "SBAIOMMU POISON";
+		int poison_size = 16;
+		void *poison_addr;
+									
+		prefetch_spill_page = (void *)__get_free_pages(GFP_KERNEL, get_order(IOVP_SIZE));
+		if (!prefetch_spill_page)
+			panic(PFX "Couldn't allocate PDIR spill page\n");
+
+		poison_addr = prefetch_spill_page;
+		for (; (u64)poison_addr < (u64)prefetch_spill_page + IOVP_SIZE ; poison_addr += poison_size)
+			(void)memcpy(poison_addr,spill_poison,poison_size);
+
+		prefetch_spill_page = (void *)virt_to_phys(prefetch_spill_page);
+
+		DBG_INIT("%s() prefetch spill addr: %p\n", __FUNCTION__, prefetch_spill_page);
+	}
+	/*
+  	** Set all the PDIR entries valid w/ the spill page as the target
+	*/
+	for (index = 0 ; index < (ioc->pdir_size / sizeof(u64)) ; index++)
+		((u64 *)ioc->pdir_base)[index] = (0x80000000000000FFULL | (u64)prefetch_spill_page);
+#endif
 }
 
 static void __init
@@ -1525,6 +1578,11 @@
 	ioc->res_map[0] = 0x1;
 	ioc->pdir_base[0] = 0x8000000000000000ULL | ZX1_SBA_IOMMU_COOKIE;
 #endif
+#ifdef FULL_VALID_PDIR
+	/* Mark the last resource used so we don't prefetch beyond IOVA space */
+	ioc->res_map[ioc->res_size - 1] |= 0x80UL; /* res_map is chars */
+	ioc->pdir_base[(ioc->pdir_size / sizeof(u64)) - 1] = (0x80000000000000FFULL | (u64)prefetch_spill_page);
+#endif
 
 	DBG_INIT("%s() res_map %x %p\n", __FUNCTION__,
 		 ioc->res_size, (void *) ioc->res_map);
@@ -1608,15 +1666,23 @@
 				(info->init)(ioc);
 		}
 	}
-	if (!ioc->name)
-		ioc->name = "Unknown";
+
+	if (!ioc->name) {
+		ioc->name = kmalloc(24, GFP_KERNEL);
+		if (ioc->name)
+			sprintf(ioc->name, "Unknown (%04x:%04x)",
+				ioc->func_id & 0xFFFF,
+				(ioc->func_id >> 16) & 0xFFFF);
+		else
+			ioc->name = "Unknown";
+	}
 
 	ioc_iova_init(ioc);
 	ioc_resource_init(ioc);
 	ioc_sac_init(ioc);
 
 	printk(KERN_INFO PFX
-		"Found %s IOC %d.%d HPA 0x%lx IOVA space %dMb at 0x%lx\n",
+		"%s %d.%d HPA 0x%lx IOVA space %dMb at 0x%lx\n",
 		ioc->name, (ioc->rev >> 4) & 0xF, ioc->rev & 0xF,
 		hpa, ioc->iov_size >> 20, ioc->ibase);
 
@@ -1861,7 +1927,6 @@
 EXPORT_SYMBOL(sba_unmap_single);
 EXPORT_SYMBOL(sba_map_sg);
 EXPORT_SYMBOL(sba_unmap_sg);
-EXPORT_SYMBOL(sba_dma_address);
 EXPORT_SYMBOL(sba_dma_supported);
 EXPORT_SYMBOL(sba_alloc_consistent);
 EXPORT_SYMBOL(sba_free_consistent);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/hp/sim/Makefile linux-2.4.21/arch/ia64/hp/sim/Makefile
--- linux-2.4.20/arch/ia64/hp/sim/Makefile	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/hp/sim/Makefile	2002-12-18 18:58:11.000000000 +0000
@@ -1,6 +1,8 @@
 #
 # ia64/platform/hp/sim/Makefile
 #
+# Copyright (C) 2002 Hewlett-Packard Co.
+#	David Mosberger-Tang <davidm@hpl.hp.com>
 # Copyright (C) 1999 Silicon Graphics, Inc.
 # Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
 #
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/hp/zx1/hpzx1_misc.c linux-2.4.21/arch/ia64/hp/zx1/hpzx1_misc.c
--- linux-2.4.20/arch/ia64/hp/zx1/hpzx1_misc.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/hp/zx1/hpzx1_misc.c	2002-12-18 18:58:03.000000000 +0000
@@ -17,8 +17,6 @@
 #include <asm/dma.h>
 #include <asm/iosapic.h>
 
-extern acpi_status acpi_evaluate_integer (acpi_handle, acpi_string, acpi_object_list *, unsigned long *);
-
 #define PFX "hpzx1: "
 
 static int hpzx1_devices;
@@ -252,40 +250,8 @@
 	 * HWP0003: AGP LBA device
 	 */
 	acpi_get_devices("HWP0001", hpzx1_sba_probe, "HWP0001", NULL);
-#ifdef CONFIG_IA64_HP_PROTO
-	if (hpzx1_devices) {
-#endif
 	acpi_get_devices("HWP0002", hpzx1_lba_probe, "HWP0002 PCI LBA", NULL);
 	acpi_get_devices("HWP0003", hpzx1_lba_probe, "HWP0003 AGP LBA", NULL);
-
-#ifdef CONFIG_IA64_HP_PROTO
-	}
-
-#define ZX1_FUNC_ID_VALUE    (PCI_DEVICE_ID_HP_ZX1_SBA << 16) | PCI_VENDOR_ID_HP
-	/*
-	 * Early protos don't have bridges in the ACPI namespace, so
-	 * if we didn't find anything, add the things we know are
-	 * there.
-	 */
-	if (hpzx1_devices == 0) {
-		u64 hpa, csr_base;
-
-		csr_base = 0xfed00000UL;
-		hpa = (u64) ioremap(csr_base, 0x2000);
-		if (__raw_readl(hpa) == ZX1_FUNC_ID_VALUE) {
-			hpzx1_fake_pci_dev("HWP0001 SBA", 0, csr_base, 0x1000);
-			hpzx1_fake_pci_dev("HWP0001 IOC", 0, csr_base + 0x1000,
-					    0x1000);
-
-			csr_base = 0xfed24000UL;
-			iounmap(hpa);
-			hpa = (u64) ioremap(csr_base, 0x1000);
-			hpzx1_fake_pci_dev("HWP0003 AGP LBA", 0x40, csr_base,
-					    0x1000);
-		}
-		iounmap(hpa);
-	}
-#endif
 }
 
 extern void sba_init(void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/ia32/ia32_signal.c linux-2.4.21/arch/ia64/ia32/ia32_signal.c
--- linux-2.4.20/arch/ia64/ia32/ia32_signal.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/arch/ia64/ia32/ia32_signal.c	2002-12-18 18:58:02.000000000 +0000
@@ -39,6 +39,16 @@
 #define __IA32_NR_sigreturn            119
 #define __IA32_NR_rt_sigreturn         173
 
+register double f16 asm ("f16"); register double f17 asm ("f17");
+register double f18 asm ("f18"); register double f19 asm ("f19");
+register double f20 asm ("f20"); register double f21 asm ("f21");
+register double f22 asm ("f22"); register double f23 asm ("f23");
+
+register double f24 asm ("f24"); register double f25 asm ("f25");
+register double f26 asm ("f26"); register double f27 asm ("f27");
+register double f28 asm ("f28"); register double f29 asm ("f29");
+register double f30 asm ("f30"); register double f31 asm ("f31");
+
 struct sigframe_ia32
 {
        int pretcode;
@@ -143,6 +153,304 @@
 	return err;
 }
 
+
+/*
+ *  SAVE and RESTORE of ia32 fpstate info, from ia64 current state
+ *  Used in exception handler to pass the fpstate to the user, and restore
+ *  the fpstate while returning from the exception handler.
+ *
+ *    fpstate info and their mapping to IA64 regs:
+ *    fpstate    REG(BITS)      Attribute    Comments
+ *    cw         ar.fcr(0:12)                with bits 7 and 6 not used
+ *    sw         ar.fsr(0:15)
+ *    tag        ar.fsr(16:31)               with odd numbered bits not used
+ *                                           (read returns 0, writes ignored)
+ *    ipoff      ar.fir(0:31)
+ *    cssel      ar.fir(32:47)
+ *    dataoff    ar.fdr(0:31)
+ *    datasel    ar.fdr(32:47)
+ *
+ *    _st[(0+TOS)%8]   f8
+ *    _st[(1+TOS)%8]   f9                    (f8, f9 from ptregs)
+ *      : :            :                     (f10..f15 from live reg)
+ *      : :            :
+ *    _st[(7+TOS)%8]   f15                   TOS=sw.top(bits11:13)
+ *
+ *    status     Same as sw     RO
+ *    magic      0                           as X86_FXSR_MAGIC in ia32
+ *    mxcsr      Bits(7:15)=ar.fcr(39:47)
+ *               Bits(0:5) =ar.fsr(32:37)    with bit 6 reserved
+ *    _xmm[0..7] f16..f31                    (live registers)
+ *                                           with _xmm[0]
+ *                                             Bit(64:127)=f17(0:63)
+ *                                             Bit(0:63)=f16(0:63)
+ *    All other fields unused...
+ */
+
+#define __ldfe(regnum, x)						\
+({									\
+ 	register double __f__ asm ("f"#regnum);				\
+	__asm__ __volatile__ ("ldfe %0=[%1] ;;" :"=f"(__f__): "r"(x));	\
+})
+
+#define __ldf8(regnum, x)						\
+({									\
+ 	register double __f__ asm ("f"#regnum);				\
+	__asm__ __volatile__ ("ldf8 %0=[%1] ;;" :"=f"(__f__): "r"(x));	\
+})
+
+#define __stfe(x, regnum)							\
+({										\
+ 	register double __f__ asm ("f"#regnum);					\
+	__asm__ __volatile__ ("stfe [%0]=%1" :: "r"(x), "f"(__f__) : "memory");	\
+})
+
+#define __stf8(x, regnum)							\
+({										\
+ 	register double __f__ asm ("f"#regnum);					\
+	__asm__ __volatile__ ("stf8 [%0]=%1" :: "r"(x), "f"(__f__) : "memory");	\
+})
+
+static int
+save_ia32_fpstate_live (struct _fpstate_ia32 *save)
+{
+	struct task_struct *tsk = current;
+	struct pt_regs *ptp;
+	struct _fpreg_ia32 *fpregp;
+	char buf[32];
+	unsigned long fsr, fcr, fir, fdr;
+	unsigned long new_fsr;
+	unsigned long num128[2];
+	unsigned long mxcsr=0;
+	int fp_tos, fr8_st_map;
+
+	if (!access_ok(VERIFY_WRITE, save, sizeof(*save)))
+		return -EFAULT;
+
+	/* Readin fsr, fcr, fir, fdr and copy onto fpstate */
+	asm volatile ( "mov %0=ar.fsr;" : "=r"(fsr));
+	asm volatile ( "mov %0=ar.fcr;" : "=r"(fcr));
+	asm volatile ( "mov %0=ar.fir;" : "=r"(fir));
+	asm volatile ( "mov %0=ar.fdr;" : "=r"(fdr));
+	/*
+	 * We need to clear the exception state before calling the signal handler. Clear
+	 * the bits 15, bits 0-7 in fp status word. Similar to the functionality of fnclex
+	 * instruction.
+	 */
+	new_fsr = fsr & ~0x80ff;
+	asm volatile ( "mov ar.fsr=%0;" :: "r"(new_fsr));
+
+	__put_user(fcr & 0xffff, &save->cw);
+	__put_user(fsr & 0xffff, &save->sw);
+	__put_user((fsr>>16) & 0xffff, &save->tag);
+	__put_user(fir, &save->ipoff);
+	__put_user((fir>>32) & 0xffff, &save->cssel);
+	__put_user(fdr, &save->dataoff);
+	__put_user((fdr>>32) & 0xffff, &save->datasel);
+	__put_user(fsr & 0xffff, &save->status);
+
+	mxcsr = ((fcr>>32) & 0xff80) | ((fsr>>32) & 0x3f);
+	__put_user(mxcsr & 0xffff, &save->mxcsr);
+	__put_user( 0, &save->magic); //#define X86_FXSR_MAGIC   0x0000
+
+	/*
+	 * save f8 and f9  from pt_regs
+	 * save f10..f15 from live register set
+	 */
+	/*
+	 *  Find the location where f8 has to go in fp reg stack.  This depends on
+	 *  TOP(11:13) field of sw. Other f reg continue sequentially from where f8 maps
+	 *  to.
+	 */
+	fp_tos = (fsr>>11)&0x7;
+	fr8_st_map = (8-fp_tos)&0x7;
+	ptp = ia64_task_regs(tsk);
+	fpregp = (struct _fpreg_ia32 *)(((unsigned long)buf + 15) & ~15);
+	ia64f2ia32f(fpregp, &ptp->f8);
+	copy_to_user(&save->_st[(0+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	ia64f2ia32f(fpregp, &ptp->f9);
+	copy_to_user(&save->_st[(1+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+
+	__stfe(fpregp, 10);
+	copy_to_user(&save->_st[(2+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	__stfe(fpregp, 11);
+	copy_to_user(&save->_st[(3+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	__stfe(fpregp, 12);
+	copy_to_user(&save->_st[(4+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	__stfe(fpregp, 13);
+	copy_to_user(&save->_st[(5+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	__stfe(fpregp, 14);
+	copy_to_user(&save->_st[(6+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	__stfe(fpregp, 15);
+	copy_to_user(&save->_st[(7+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+
+	__stf8(&num128[0], 16);
+	__stf8(&num128[1], 17);
+	copy_to_user(&save->_xmm[0], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 18);
+	__stf8(&num128[1], 19);
+	copy_to_user(&save->_xmm[1], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 20);
+	__stf8(&num128[1], 21);
+	copy_to_user(&save->_xmm[2], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 22);
+	__stf8(&num128[1], 23);
+	copy_to_user(&save->_xmm[3], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 24);
+	__stf8(&num128[1], 25);
+	copy_to_user(&save->_xmm[4], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 26);
+	__stf8(&num128[1], 27);
+	copy_to_user(&save->_xmm[5], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 28);
+	__stf8(&num128[1], 29);
+	copy_to_user(&save->_xmm[6], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 30);
+	__stf8(&num128[1], 31);
+	copy_to_user(&save->_xmm[7], num128, sizeof(struct _xmmreg_ia32));
+	return 0;
+}
+
+static int
+restore_ia32_fpstate_live (struct _fpstate_ia32 *save)
+{
+	struct task_struct *tsk = current;
+	struct pt_regs *ptp;
+	unsigned int lo, hi;
+	unsigned long num128[2];
+	unsigned long num64, mxcsr;
+	struct _fpreg_ia32 *fpregp;
+	char buf[32];
+	unsigned long fsr, fcr, fir, fdr;
+	int fp_tos, fr8_st_map;
+
+	if (!access_ok(VERIFY_READ, save, sizeof(*save)))
+		return(-EFAULT);
+
+	/*
+	 * Updating fsr, fcr, fir, fdr.
+	 * Just a bit more complicated than save.
+	 * - Need to make sure that we dont write any value other than the
+	 *   specific fpstate info
+	 * - Need to make sure that the untouched part of frs, fdr, fir, fcr
+	 *   should remain same while writing.
+	 * So, we do a read, change specific fields and write.
+	 */
+	asm volatile ( "mov %0=ar.fsr;" : "=r"(fsr));
+	asm volatile ( "mov %0=ar.fcr;" : "=r"(fcr));
+	asm volatile ( "mov %0=ar.fir;" : "=r"(fir));
+	asm volatile ( "mov %0=ar.fdr;" : "=r"(fdr));
+
+	__get_user(mxcsr, (unsigned int *)&save->mxcsr);
+	/* setting bits 0..5 8..12 with cw and 39..47 from mxcsr */
+	__get_user(lo, (unsigned int *)&save->cw);
+	num64 = mxcsr & 0xff10;
+	num64 = (num64 << 32) | (lo & 0x1f3f);
+	fcr = (fcr & (~0xff1000001f3f)) | num64;
+
+	/* setting bits 0..31 with sw and tag and 32..37 from mxcsr */
+	__get_user(lo, (unsigned int *)&save->sw);
+	/* set bits 15,7 (fsw.b, fsw.es) to reflect the current error status */
+	if ( !(lo & 0x7f) )
+		lo &= (~0x8080);
+	__get_user(hi, (unsigned int *)&save->tag);
+	num64 = mxcsr & 0x3f;
+	num64 = (num64 << 16) | (hi & 0xffff);
+	num64 = (num64 << 16) | (lo & 0xffff);
+	fsr = (fsr & (~0x3fffffffff)) | num64;
+
+	/* setting bits 0..47 with cssel and ipoff */
+	__get_user(lo, (unsigned int *)&save->ipoff);
+	__get_user(hi, (unsigned int *)&save->cssel);
+	num64 = hi & 0xffff;
+	num64 = (num64 << 32) | lo;
+	fir = (fir & (~0xffffffffffff)) | num64;
+
+	/* setting bits 0..47 with datasel and dataoff */
+	__get_user(lo, (unsigned int *)&save->dataoff);
+	__get_user(hi, (unsigned int *)&save->datasel);
+	num64 = hi & 0xffff;
+	num64 = (num64 << 32) | lo;
+	fdr = (fdr & (~0xffffffffffff)) | num64;
+
+	asm volatile ( "mov ar.fsr=%0;" :: "r"(fsr));
+	asm volatile ( "mov ar.fcr=%0;" :: "r"(fcr));
+	asm volatile ( "mov ar.fir=%0;" :: "r"(fir));
+	asm volatile ( "mov ar.fdr=%0;" :: "r"(fdr));
+
+	/*
+	 * restore f8, f9 onto pt_regs
+	 * restore f10..f15 onto live registers
+	 */
+	/*
+	 *  Find the location where f8 has to go in fp reg stack.  This depends on
+	 *  TOP(11:13) field of sw. Other f reg continue sequentially from where f8 maps
+	 *  to.
+	 */
+	fp_tos = (fsr>>11)&0x7;
+	fr8_st_map = (8-fp_tos)&0x7;
+	fpregp = (struct _fpreg_ia32 *)(((unsigned long)buf + 15) & ~15);
+
+	ptp = ia64_task_regs(tsk);
+	copy_from_user(fpregp, &save->_st[(0+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	ia32f2ia64f(&ptp->f8, fpregp);
+	copy_from_user(fpregp, &save->_st[(1+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	ia32f2ia64f(&ptp->f9, fpregp);
+
+	copy_from_user(fpregp, &save->_st[(2+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(10, fpregp);
+	copy_from_user(fpregp, &save->_st[(3+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(11, fpregp);
+	copy_from_user(fpregp, &save->_st[(4+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(12, fpregp);
+	copy_from_user(fpregp, &save->_st[(5+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(13, fpregp);
+	copy_from_user(fpregp, &save->_st[(6+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(14, fpregp);
+	copy_from_user(fpregp, &save->_st[(7+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(15, fpregp);
+
+	copy_from_user(num128, &save->_xmm[0], sizeof(struct _xmmreg_ia32));
+	__ldf8(16, &num128[0]);
+	__ldf8(17, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[1], sizeof(struct _xmmreg_ia32));
+	__ldf8(18, &num128[0]);
+	__ldf8(19, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[2], sizeof(struct _xmmreg_ia32));
+	__ldf8(20, &num128[0]);
+	__ldf8(21, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[3], sizeof(struct _xmmreg_ia32));
+	__ldf8(22, &num128[0]);
+	__ldf8(23, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[4], sizeof(struct _xmmreg_ia32));
+	__ldf8(24, &num128[0]);
+	__ldf8(25, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[5], sizeof(struct _xmmreg_ia32));
+	__ldf8(26, &num128[0]);
+	__ldf8(27, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[6], sizeof(struct _xmmreg_ia32));
+	__ldf8(28, &num128[0]);
+	__ldf8(29, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[7], sizeof(struct _xmmreg_ia32));
+	__ldf8(30, &num128[0]);
+	__ldf8(31, &num128[1]);
+	return 0;
+}
+
 static inline void
 sigact_set_handler (struct k_sigaction *sa, unsigned int handler, unsigned int restorer)
 {
@@ -371,6 +679,9 @@
 	int  err = 0;
 	unsigned long flag;
 
+	if (!access_ok(VERIFY_WRITE, sc, sizeof(*sc)))
+		return -EFAULT;
+
 	err |= __put_user((regs->r16 >> 32) & 0xffff, (unsigned int *)&sc->fs);
 	err |= __put_user((regs->r16 >> 48) & 0xffff, (unsigned int *)&sc->gs);
 	err |= __put_user((regs->r16 >> 16) & 0xffff, (unsigned int *)&sc->es);
@@ -397,6 +708,11 @@
 	err |= __put_user(regs->r12, &sc->esp_at_signal);
 	err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int *)&sc->ss);
 
+	if ( save_ia32_fpstate_live(fpstate) < 0 )
+		err = -EFAULT;
+	else
+		err |= __put_user((u32)(u64)fpstate, &sc->fpstate);
+
 #if 0
 	tmp = save_i387(fpstate);
 	if (tmp < 0)
@@ -418,6 +734,9 @@
 {
 	unsigned int err = 0;
 
+	if (!access_ok(VERIFY_READ, sc, sizeof(*sc)))
+		return(-EFAULT);
+
 #define COPY(ia64x, ia32x)	err |= __get_user(regs->ia64x, &sc->ia32x)
 
 #define copyseg_gs(tmp)		(regs->r16 |= (unsigned long) tmp << 48)
@@ -477,6 +796,16 @@
 		regs->r1 = -1;	/* disable syscall checks, r1 is orig_eax */
 	}
 
+	{
+		struct _fpstate_ia32 *buf = NULL;
+		u32    fpstate_ptr;
+		err |= get_user(fpstate_ptr, &(sc->fpstate));
+		buf = (struct _fpstate_ia32 *)(u64)fpstate_ptr;
+		if (buf) {
+			err |= restore_ia32_fpstate_live(buf);
+		}
+	}
+
 #if 0
 	{
 		struct _fpstate * buf;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/ia32/sys_ia32.c linux-2.4.21/arch/ia64/ia32/sys_ia32.c
--- linux-2.4.20/arch/ia64/ia32/sys_ia32.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/arch/ia64/ia32/sys_ia32.c	2002-12-18 18:58:10.000000000 +0000
@@ -2118,8 +2118,8 @@
 };
 
 struct ipc_kludge {
-	struct msgbuf *msgp;
-	long msgtyp;
+	u32 msgp;
+	s32 msgtyp;
 };
 
 #define SEMOP		 1
@@ -2843,20 +2843,6 @@
 	}
 }
 
-static inline void
-ia32f2ia64f (void *dst, void *src)
-{
-	asm volatile ("ldfe f6=[%1];; stf.spill [%0]=f6" :: "r"(dst), "r"(src) : "memory");
-	return;
-}
-
-static inline void
-ia64f2ia32f (void *dst, void *src)
-{
-	asm volatile ("ldf.fill f6=[%1];; stfe [%0]=f6" :: "r"(dst),  "r"(src) : "memory");
-	return;
-}
-
 static void
 put_fpreg (int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp,
 	   int tos)
@@ -2913,57 +2899,152 @@
 }
 
 static int
-save_ia32_fpstate (struct task_struct *tsk, struct _fpstate_ia32 *save)
+save_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *save)
 {
 	struct switch_stack *swp;
 	struct pt_regs *ptp;
 	int i, tos;
 
 	if (!access_ok(VERIFY_WRITE, save, sizeof(*save)))
-		return -EIO;
-	__put_user(tsk->thread.fcr, &save->cw);
-	__put_user(tsk->thread.fsr, &save->sw);
-	__put_user(tsk->thread.fsr >> 32, &save->tag);
-	__put_user(tsk->thread.fir, &save->ipoff);
-	__put_user(__USER_CS, &save->cssel);
-	__put_user(tsk->thread.fdr, &save->dataoff);
-	__put_user(__USER_DS, &save->datasel);
+		return -EFAULT;
+
+	__put_user(tsk->thread.fcr & 0xffff, &save->cwd);
+	__put_user(tsk->thread.fsr & 0xffff, &save->swd);
+	__put_user((tsk->thread.fsr>>16) & 0xffff, &save->twd);
+	__put_user(tsk->thread.fir, &save->fip);
+	__put_user((tsk->thread.fir>>32) & 0xffff, &save->fcs);
+	__put_user(tsk->thread.fdr, &save->foo);
+	__put_user((tsk->thread.fdr>>32) & 0xffff, &save->fos);
+
 	/*
 	 *  Stack frames start with 16-bytes of temp space
 	 */
 	swp = (struct switch_stack *)(tsk->thread.ksp + 16);
 	ptp = ia64_task_regs(tsk);
-	tos = (tsk->thread.fsr >> 11) & 3;
+	tos = (tsk->thread.fsr >> 11) & 7;
 	for (i = 0; i < 8; i++)
-		put_fpreg(i, &save->_st[i], ptp, swp, tos);
+		put_fpreg(i, (struct _fpreg_ia32 *)&save->st_space[4*i], ptp, swp, tos);
 	return 0;
 }
 
 static int
-restore_ia32_fpstate (struct task_struct *tsk, struct _fpstate_ia32 *save)
+restore_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *save)
 {
 	struct switch_stack *swp;
 	struct pt_regs *ptp;
-	int i, tos, ret;
-	int fsrlo, fsrhi;
+	int i, tos;
+	unsigned int fsrlo, fsrhi, num32;
 
 	if (!access_ok(VERIFY_READ, save, sizeof(*save)))
-		return(-EIO);
-	ret = __get_user(tsk->thread.fcr, (unsigned int *)&save->cw);
-	ret |= __get_user(fsrlo, (unsigned int *)&save->sw);
-	ret |= __get_user(fsrhi, (unsigned int *)&save->tag);
-	tsk->thread.fsr = ((long)fsrhi << 32) | (long)fsrlo;
-	ret |= __get_user(tsk->thread.fir, (unsigned int *)&save->ipoff);
-	ret |= __get_user(tsk->thread.fdr, (unsigned int *)&save->dataoff);
+		return(-EFAULT);
+
+	__get_user(num32, (unsigned int *)&save->cwd);
+	tsk->thread.fcr = (tsk->thread.fcr & (~0x1f3f)) | (num32 & 0x1f3f);
+	__get_user(fsrlo, (unsigned int *)&save->swd);
+	__get_user(fsrhi, (unsigned int *)&save->twd);
+	num32 = (fsrhi << 16) | fsrlo;
+	tsk->thread.fsr = (tsk->thread.fsr & (~0xffffffff)) | num32;
+	__get_user(num32, (unsigned int *)&save->fip);
+	tsk->thread.fir = (tsk->thread.fir & (~0xffffffff)) | num32;
+	__get_user(num32, (unsigned int *)&save->foo);
+	tsk->thread.fdr = (tsk->thread.fdr & (~0xffffffff)) | num32;
+
 	/*
 	 *  Stack frames start with 16-bytes of temp space
 	 */
 	swp = (struct switch_stack *)(tsk->thread.ksp + 16);
 	ptp = ia64_task_regs(tsk);
-	tos = (tsk->thread.fsr >> 11) & 3;
+	tos = (tsk->thread.fsr >> 11) & 7;
 	for (i = 0; i < 8; i++)
-		get_fpreg(i, &save->_st[i], ptp, swp, tos);
-	return ret ? -EFAULT : 0;
+		get_fpreg(i, (struct _fpreg_ia32 *)&save->st_space[4*i], ptp, swp, tos);
+	return 0;
+}
+
+static int
+save_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save)
+{
+	struct switch_stack *swp;
+	struct pt_regs *ptp;
+	int i, tos;
+	unsigned long mxcsr=0;
+	unsigned long num128[2];
+
+	if (!access_ok(VERIFY_WRITE, save, sizeof(*save)))
+		return -EFAULT;
+
+	__put_user(tsk->thread.fcr & 0xffff, &save->cwd);
+	__put_user(tsk->thread.fsr & 0xffff, &save->swd);
+	__put_user((tsk->thread.fsr>>16) & 0xffff, &save->twd);
+	__put_user(tsk->thread.fir, &save->fip);
+	__put_user((tsk->thread.fir>>32) & 0xffff, &save->fcs);
+	__put_user(tsk->thread.fdr, &save->foo);
+	__put_user((tsk->thread.fdr>>32) & 0xffff, &save->fos);
+
+        /*
+         *  Stack frames start with 16-bytes of temp space
+         */
+        swp = (struct switch_stack *)(tsk->thread.ksp + 16);
+        ptp = ia64_task_regs(tsk);
+	tos = (tsk->thread.fsr >> 11) & 7;
+        for (i = 0; i < 8; i++)
+		put_fpreg(i, (struct _fpxreg_ia32 *)&save->st_space[4*i], ptp, swp, tos);
+
+	mxcsr = ((tsk->thread.fcr>>32) & 0xff80) | ((tsk->thread.fsr>>32) & 0x3f);
+	__put_user(mxcsr & 0xffff, &save->mxcsr);
+	for (i = 0; i < 8; i++) {
+		memcpy(&(num128[0]), &(swp->f16) + i*2, sizeof(unsigned long));
+		memcpy(&(num128[1]), &(swp->f17) + i*2, sizeof(unsigned long));
+		copy_to_user(&save->xmm_space[0] + 4*i, num128, sizeof(struct _xmmreg_ia32));
+	}
+	return 0;
+}
+
+static int
+restore_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save)
+{
+	struct switch_stack *swp;
+	struct pt_regs *ptp;
+	int i, tos;
+	unsigned int fsrlo, fsrhi, num32;
+	int mxcsr;
+	unsigned long num64;
+	unsigned long num128[2];
+
+	if (!access_ok(VERIFY_READ, save, sizeof(*save)))
+		return(-EFAULT);
+
+	__get_user(num32, (unsigned int *)&save->cwd);
+	tsk->thread.fcr = (tsk->thread.fcr & (~0x1f3f)) | (num32 & 0x1f3f);
+	__get_user(fsrlo, (unsigned int *)&save->swd);
+	__get_user(fsrhi, (unsigned int *)&save->twd);
+	num32 = (fsrhi << 16) | fsrlo;
+	tsk->thread.fsr = (tsk->thread.fsr & (~0xffffffff)) | num32;
+	__get_user(num32, (unsigned int *)&save->fip);
+	tsk->thread.fir = (tsk->thread.fir & (~0xffffffff)) | num32;
+	__get_user(num32, (unsigned int *)&save->foo);
+	tsk->thread.fdr = (tsk->thread.fdr & (~0xffffffff)) | num32;
+
+	/*
+	 *  Stack frames start with 16-bytes of temp space
+	 */
+	swp = (struct switch_stack *)(tsk->thread.ksp + 16);
+	ptp = ia64_task_regs(tsk);
+	tos = (tsk->thread.fsr >> 11) & 7;
+	for (i = 0; i < 8; i++)
+	get_fpreg(i, (struct _fpxreg_ia32 *)&save->st_space[4*i], ptp, swp, tos);
+
+	__get_user(mxcsr, (unsigned int *)&save->mxcsr);
+	num64 = mxcsr & 0xff10;
+	tsk->thread.fcr = (tsk->thread.fcr & (~0xff1000000000)) | (num64<<32);
+	num64 = mxcsr & 0x3f;
+	tsk->thread.fsr = (tsk->thread.fsr & (~0x3f00000000)) | (num64<<32);
+
+	for (i = 0; i < 8; i++) {
+		copy_from_user(num128, &save->xmm_space[0] + 4*i, sizeof(struct _xmmreg_ia32));
+		memcpy(&(swp->f16) + i*2, &(num128[0]), sizeof(unsigned long));
+		memcpy(&(swp->f17) + i*2, &(num128[1]), sizeof(unsigned long));
+	}
+	return 0;
 }
 
 extern asmlinkage long sys_ptrace (long, pid_t, unsigned long, unsigned long, long, long, long,
@@ -3075,11 +3156,19 @@
 		break;
 
 	      case IA32_PTRACE_GETFPREGS:
-		ret = save_ia32_fpstate(child, (struct _fpstate_ia32 *) A(data));
+		ret = save_ia32_fpstate(child, (struct ia32_user_i387_struct *) A(data));
+		break;
+
+	      case IA32_PTRACE_GETFPXREGS:
+		ret = save_ia32_fpxstate(child, (struct ia32_user_fxsr_struct *) A(data));
 		break;
 
 	      case IA32_PTRACE_SETFPREGS:
-		ret = restore_ia32_fpstate(child, (struct _fpstate_ia32 *) A(data));
+		ret = restore_ia32_fpstate(child, (struct ia32_user_i387_struct *) A(data));
+		break;
+
+	      case IA32_PTRACE_SETFPXREGS:
+		ret = restore_ia32_fpxstate(child, (struct ia32_user_fxsr_struct *) A(data));
 		break;
 
 	      case PTRACE_SYSCALL:	/* continue, stop after next syscall */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/acpi.c linux-2.4.21/arch/ia64/kernel/acpi.c
--- linux-2.4.20/arch/ia64/kernel/acpi.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/acpi.c	2002-12-18 18:58:08.000000000 +0000
@@ -102,8 +102,6 @@
 	return "sn2";
 # elif defined (CONFIG_IA64_DIG)
 	return "dig";
-# elif defined (CONFIG_IA64_HP_ZX1)
-	return "hpzx1";
 # else
 #	error Unknown platform.  Fix acpi.c.
 # endif
@@ -112,33 +110,7 @@
 
 #ifdef CONFIG_ACPI
 
-/**
- * acpi_get_crs - Return the current resource settings for a device
- * obj: A handle for this device
- * buf: A buffer to be populated by this call.
- *
- * Pass a valid handle, typically obtained by walking the namespace and a
- * pointer to an allocated buffer, and this function will fill in the buffer
- * with a list of acpi_resource structures.
- */
-acpi_status
-acpi_get_crs (acpi_handle obj, acpi_buffer *buf)
-{
-	acpi_status result;
-	buf->length = 0;
-	buf->pointer = NULL;
-
-	result = acpi_get_current_resources(obj, buf);
-	if (result != AE_BUFFER_OVERFLOW)
-		return result;
-	buf->pointer = kmalloc(buf->length, GFP_KERNEL);
-	if (!buf->pointer)
-		return -ENOMEM;
-
-	return acpi_get_current_resources(obj, buf);
-}
-
-acpi_resource *
+static acpi_resource *
 acpi_get_crs_next (acpi_buffer *buf, int *offset)
 {
 	acpi_resource *res;
@@ -146,12 +118,12 @@
 	if (*offset >= buf->length)
 		return NULL;
 
-	res = buf->pointer + *offset;
+	res = (acpi_resource *)((char *) buf->pointer + *offset);
 	*offset += res->length;
 	return res;
 }
 
-acpi_resource_data *
+static acpi_resource_data *
 acpi_get_crs_type (acpi_buffer *buf, int *offset, int type)
 {
 	for (;;) {
@@ -163,12 +135,6 @@
 	}
 }
 
-void
-acpi_dispose_crs (acpi_buffer *buf)
-{
-	kfree(buf->pointer);
-}
-
 static void
 acpi_get_crs_addr (acpi_buffer *buf, int type, u64 *base, u64 *length, u64 *tra)
 {
@@ -210,6 +176,9 @@
 					return;
 				}
 				break;
+			case ACPI_RSTYPE_END_TAG:
+				return;
+				break;
 		}
 	}
 }
@@ -218,13 +187,14 @@
 acpi_get_addr_space(acpi_handle obj, u8 type, u64 *base, u64 *length, u64 *tra)
 {
 	acpi_status status;
-	acpi_buffer buf;
+	acpi_buffer buf = { .length  = ACPI_ALLOCATE_BUFFER,
+			    .pointer = NULL };
 
 	*base = 0;
 	*length = 0;
 	*tra = 0;
 
-	status = acpi_get_crs(obj, &buf);
+	status = acpi_get_current_resources(obj, &buf);
 	if (ACPI_FAILURE(status)) {
 		printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n");
 		return status;
@@ -232,7 +202,7 @@
 
 	acpi_get_crs_addr(&buf, type, base, length, tra);
 
-	acpi_dispose_crs(&buf);
+	acpi_os_free(buf.pointer);
 
 	return AE_OK;
 }
@@ -254,7 +224,8 @@
 {
 	int i, offset = 0;
 	acpi_status status;
-	acpi_buffer buf;
+	acpi_buffer buf = { .length  = ACPI_ALLOCATE_BUFFER,
+			    .pointer = NULL };
 	acpi_resource_vendor *res;
 	acpi_hp_vendor_long *hp_res;
 	efi_guid_t vendor_guid;
@@ -262,42 +233,41 @@
 	*csr_base = 0;
 	*csr_length = 0;
 
-	status = acpi_get_crs(obj, &buf);
+	status = acpi_get_current_resources(obj, &buf);
 	if (ACPI_FAILURE(status)) {
 		printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n");
 		return status;
 	}
 
+	status = AE_NOT_FOUND;
 	res = (acpi_resource_vendor *)acpi_get_crs_type(&buf, &offset, ACPI_RSTYPE_VENDOR);
 	if (!res) {
 		printk(KERN_ERR PREFIX "Failed to find config space for device\n");
-		acpi_dispose_crs(&buf);
-		return AE_NOT_FOUND;
+		goto out;
 	}
 
+	status = AE_TYPE; /* Revisit error? */
 	hp_res = (acpi_hp_vendor_long *)(res->reserved);
 
 	if (res->length != HP_CCSR_LENGTH || hp_res->guid_id != HP_CCSR_TYPE) {
 		printk(KERN_ERR PREFIX "Unknown Vendor data\n");
-		acpi_dispose_crs(&buf);
-		return AE_TYPE; /* Revisit error? */
+		goto out;
 	}
 
 	memcpy(&vendor_guid, hp_res->guid, sizeof(efi_guid_t));
 	if (efi_guidcmp(vendor_guid, HP_CCSR_GUID) != 0) {
 		printk(KERN_ERR PREFIX "Vendor GUID does not match\n");
-		acpi_dispose_crs(&buf);
-		return AE_TYPE; /* Revisit error? */
-	}
-
-	for (i = 0 ; i < 8 ; i++) {
-		*csr_base |= ((u64)(hp_res->csr_base[i]) << (i * 8));
-		*csr_length |= ((u64)(hp_res->csr_length[i]) << (i * 8));
+		goto out;
 	}
 
-	acpi_dispose_crs(&buf);
+	/* It's probably unaligned, so use memcpy */
+	memcpy(csr_base, hp_res->csr_base, 8);
+	memcpy(csr_length, hp_res->csr_length, 8);
+	status = AE_OK;
 
-	return AE_OK;
+ out:
+	acpi_os_free(buf.pointer);
+	return status;
 }
 #endif /* CONFIG_ACPI */
 
@@ -368,6 +338,7 @@
 acpi_parse_lsapic (acpi_table_entry_header *header)
 {
 	struct acpi_table_lsapic *lsapic;
+	int phys_id;
 
 	lsapic = (struct acpi_table_lsapic *) header;
 	if (!lsapic)
@@ -375,13 +346,21 @@
 
 	acpi_table_print_madt_entry(header);
 
-	printk("CPU %d (0x%04x)", total_cpus, (lsapic->id << 8) | lsapic->eid);
+	phys_id = (lsapic->id << 8) | lsapic->eid;
+
+	if (total_cpus == NR_CPUS) {
+		printk(KERN_ERR PREFIX "Ignoring CPU (0x%04x) (NR_CPUS == %d)\n",
+			phys_id, NR_CPUS);
+		return 0;
+	}
+
+	printk("CPU %d (0x%04x)", total_cpus, phys_id);
 
 	if (lsapic->flags.enabled) {
 		available_cpus++;
 		printk(" enabled");
 #ifdef CONFIG_SMP
-		smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid;
+		smp_boot_data.cpu_phys_id[total_cpus] = phys_id;
 		if (hard_smp_processor_id() == smp_boot_data.cpu_phys_id[total_cpus])
 			printk(" (BSP)");
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/efi.c linux-2.4.21/arch/ia64/kernel/efi.c
--- linux-2.4.20/arch/ia64/kernel/efi.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/efi.c	2002-12-18 18:58:02.000000000 +0000
@@ -51,66 +51,156 @@
 
 static unsigned long mem_limit = ~0UL;
 
-static efi_status_t
-phys_get_time (efi_time_t *tm, efi_time_cap_t *tc)
-{
-	return efi_call_phys(__va(runtime->get_time), __pa(tm), __pa(tc));
-}
-
-static efi_status_t
-phys_set_time (efi_time_t *tm)
-{
-	return efi_call_phys(__va(runtime->set_time), __pa(tm));
-}
+#define efi_call_virt(f, args...)	(*(f))(args)
 
-static efi_status_t
-phys_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm)
-{
-	return efi_call_phys(__va(runtime->get_wakeup_time), __pa(enabled), __pa(pending),
-			     __pa(tm));
-}
-
-static efi_status_t
-phys_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm)
-{
-	return efi_call_phys(__va(runtime->set_wakeup_time), enabled, __pa(tm));
-}
-
-static efi_status_t
-phys_get_variable (efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
-		   unsigned long *data_size, void *data)
-{
-	return efi_call_phys(__va(runtime->get_variable), __pa(name), __pa(vendor), __pa(attr),
-			     __pa(data_size), __pa(data));
-}
-
-static efi_status_t
-phys_get_next_variable (unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor)
-{
-	return efi_call_phys(__va(runtime->get_next_variable), __pa(name_size), __pa(name),
-			     __pa(vendor));
-}
-
-static efi_status_t
-phys_set_variable (efi_char16_t *name, efi_guid_t *vendor, u32 attr,
-		   unsigned long data_size, void *data)
-{
-	return efi_call_phys(__va(runtime->set_variable), __pa(name), __pa(vendor), attr,
-			     data_size, __pa(data));
-}
-
-static efi_status_t
-phys_get_next_high_mono_count (u64 *count)
-{
-	return efi_call_phys(__va(runtime->get_next_high_mono_count), __pa(count));
-}
-
-static void
-phys_reset_system (int reset_type, efi_status_t status,
-		   unsigned long data_size, efi_char16_t *data)
-{
-	efi_call_phys(__va(runtime->reset_system), status, data_size, __pa(data));
-}
+#define STUB_GET_TIME(prefix, adjust_arg)							\
+static efi_status_t										\
+prefix##_get_time (efi_time_t *tm, efi_time_cap_t *tc)						\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_get_time_t *) __va(runtime->get_time), adjust_arg(tm),	\
+				adjust_arg(tc));						\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_SET_TIME(prefix, adjust_arg)							\
+static efi_status_t										\
+prefix##_set_time (efi_time_t *tm)								\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_set_time_t *) __va(runtime->set_time), adjust_arg(tm));	\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_GET_WAKEUP_TIME(prefix, adjust_arg)						\
+static efi_status_t										\
+prefix##_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm)		\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_get_wakeup_time_t *) __va(runtime->get_wakeup_time),	\
+				adjust_arg(enabled), adjust_arg(pending), adjust_arg(tm));	\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_SET_WAKEUP_TIME(prefix, adjust_arg)						\
+static efi_status_t										\
+prefix##_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm)					\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_set_wakeup_time_t *) __va(runtime->set_wakeup_time),	\
+				enabled, adjust_arg(tm));					\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_GET_VARIABLE(prefix, adjust_arg)						\
+static efi_status_t									\
+prefix##_get_variable (efi_char16_t *name, efi_guid_t *vendor, u32 *attr,		\
+		       unsigned long *data_size, void *data)				\
+{											\
+	struct ia64_fpreg fr[6];							\
+	efi_status_t ret;								\
+											\
+	ia64_save_scratch_fpregs(fr);							\
+	ret = efi_call_##prefix((efi_get_variable_t *) __va(runtime->get_variable),	\
+				adjust_arg(name), adjust_arg(vendor), adjust_arg(attr),	\
+				adjust_arg(data_size), adjust_arg(data));		\
+	ia64_load_scratch_fpregs(fr);							\
+	return ret;									\
+}
+
+#define STUB_GET_NEXT_VARIABLE(prefix, adjust_arg)						\
+static efi_status_t										\
+prefix##_get_next_variable (unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor)	\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_get_next_variable_t *) __va(runtime->get_next_variable),	\
+				adjust_arg(name_size), adjust_arg(name), adjust_arg(vendor));	\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_SET_VARIABLE(prefix, adjust_arg)						\
+static efi_status_t									\
+prefix##_set_variable (efi_char16_t *name, efi_guid_t *vendor, u32 attr,		\
+		       unsigned long data_size, void *data)				\
+{											\
+	struct ia64_fpreg fr[6];							\
+	efi_status_t ret;								\
+											\
+	ia64_save_scratch_fpregs(fr);							\
+	ret = efi_call_##prefix((efi_set_variable_t *) __va(runtime->set_variable),	\
+				adjust_arg(name), adjust_arg(vendor), attr, data_size,	\
+				adjust_arg(data));					\
+	ia64_load_scratch_fpregs(fr);							\
+	return ret;									\
+}
+
+#define STUB_GET_NEXT_HIGH_MONO_COUNT(prefix, adjust_arg)					\
+static efi_status_t										\
+prefix##_get_next_high_mono_count (u64 *count)							\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_get_next_high_mono_count_t *)				\
+				__va(runtime->get_next_high_mono_count), adjust_arg(count));	\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_RESET_SYSTEM(prefix, adjust_arg)					\
+static void									\
+prefix##_reset_system (int reset_type, efi_status_t status,			\
+		       unsigned long data_size, efi_char16_t *data)		\
+{										\
+	struct ia64_fpreg fr[6];						\
+										\
+	ia64_save_scratch_fpregs(fr);						\
+	efi_call_##prefix((efi_reset_system_t *) __va(runtime->reset_system),	\
+			  reset_type, status, data_size, adjust_arg(data));	\
+	/* should not return, but just in case... */				\
+	ia64_load_scratch_fpregs(fr);						\
+}
+
+STUB_GET_TIME(phys, __pa)
+STUB_SET_TIME(phys, __pa)
+STUB_GET_WAKEUP_TIME(phys, __pa)
+STUB_SET_WAKEUP_TIME(phys, __pa)
+STUB_GET_VARIABLE(phys, __pa)
+STUB_GET_NEXT_VARIABLE(phys, __pa)
+STUB_SET_VARIABLE(phys, __pa)
+STUB_GET_NEXT_HIGH_MONO_COUNT(phys, __pa)
+STUB_RESET_SYSTEM(phys, __pa)
+
+STUB_GET_TIME(virt, )
+STUB_SET_TIME(virt, )
+STUB_GET_WAKEUP_TIME(virt, )
+STUB_SET_WAKEUP_TIME(virt, )
+STUB_GET_VARIABLE(virt, )
+STUB_GET_NEXT_VARIABLE(virt, )
+STUB_SET_VARIABLE(virt, )
+STUB_GET_NEXT_HIGH_MONO_COUNT(virt, )
+STUB_RESET_SYSTEM(virt, )
 
 void
 efi_gettimeofday (struct timeval *tv)
@@ -207,7 +297,7 @@
 		u64 start;
 		u64 end;
 	} prev, curr;
-	void *efi_map_start, *efi_map_end, *p, *q;
+	void *efi_map_start, *efi_map_end, *p, *q, *r;
 	efi_memory_desc_t *md, *check_md;
 	u64 efi_desc_size, start, end, granule_addr, first_non_wb_addr = 0;
 
@@ -252,11 +342,10 @@
 
 			if (!(first_non_wb_addr > granule_addr))
 				continue;	/* couldn't find enough contiguous memory */
-		}
-
-		/* BUG_ON((md->phys_addr >> IA64_GRANULE_SHIFT) < first_non_wb_addr); */
 
-		trim_top(md, first_non_wb_addr);
+			for (r = p; r < q; r += efi_desc_size)
+				trim_top(r, first_non_wb_addr);
+		}
 
 		if (is_available_memory(md)) {
 			if (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) > mem_limit) {
@@ -540,23 +629,22 @@
 			       efi_desc_size, ia64_boot_param->efi_memdesc_version,
 			       ia64_boot_param->efi_memmap);
 	if (status != EFI_SUCCESS) {
-		printk("Warning: unable to switch EFI into virtual mode (status=%lu)\n", status);
+		printk("Warning: unable to switch EFI into virtual mode (status=0x%lx)\n", status);
 		return;
 	}
 
 	/*
-	 * Now that EFI is in virtual mode, we arrange for EFI functions to be
-	 * called directly:
+	 * Now that EFI is in virtual mode, we call the EFI functions more efficiently:
 	 */
-	efi.get_time = __va(runtime->get_time);
-	efi.set_time = __va(runtime->set_time);
-	efi.get_wakeup_time = __va(runtime->get_wakeup_time);
-	efi.set_wakeup_time = __va(runtime->set_wakeup_time);
-	efi.get_variable = __va(runtime->get_variable);
-	efi.get_next_variable = __va(runtime->get_next_variable);
-	efi.set_variable = __va(runtime->set_variable);
-	efi.get_next_high_mono_count = __va(runtime->get_next_high_mono_count);
-	efi.reset_system = __va(runtime->reset_system);
+	efi.get_time = virt_get_time;
+	efi.set_time = virt_set_time;
+	efi.get_wakeup_time = virt_get_wakeup_time;
+	efi.set_wakeup_time = virt_set_wakeup_time;
+	efi.get_variable = virt_get_variable;
+	efi.get_next_variable = virt_get_next_variable;
+	efi.set_variable = virt_set_variable;
+	efi.get_next_high_mono_count = virt_get_next_high_mono_count;
+	efi.reset_system = virt_reset_system;
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/entry.S linux-2.4.21/arch/ia64/kernel/entry.S
--- linux-2.4.20/arch/ia64/kernel/entry.S	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/entry.S	2002-12-18 18:58:05.000000000 +0000
@@ -1109,7 +1109,7 @@
 	data8 sys_mlock
 	data8 sys_mlockall
 	data8 sys_mprotect			// 1155
-	data8 sys_mremap
+	data8 ia64_mremap
 	data8 sys_msync
 	data8 sys_munlock
 	data8 sys_munlockall
@@ -1170,18 +1170,18 @@
 	data8 sys_getdents64
 	data8 sys_getunwind			// 1215
 	data8 sys_readahead
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall			// 1220
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall			// 1225
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
+	data8 sys_setxattr
+	data8 sys_lsetxattr
+	data8 sys_fsetxattr
+	data8 sys_getxattr			// 1220
+	data8 sys_lgetxattr
+	data8 sys_fgetxattr
+	data8 sys_listxattr
+	data8 sys_llistxattr
+	data8 sys_flistxattr			// 1225
+	data8 sys_removexattr
+	data8 sys_lremovexattr
+	data8 sys_fremovexattr
 	data8 sys_tkill
 	data8 ia64_ni_syscall			// 1230
 	data8 ia64_ni_syscall
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/fw-emu.c linux-2.4.21/arch/ia64/kernel/fw-emu.c
--- linux-2.4.20/arch/ia64/kernel/fw-emu.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/fw-emu.c	2002-12-18 18:58:02.000000000 +0000
@@ -2,7 +2,7 @@
  * PAL & SAL emulation.
  *
  * Copyright (C) 1998-2001 Hewlett-Packard Co
- * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * For the HP simulator, this file gets include in boot/bootloader.c.
  * For SoftSDV, this file gets included in sys_softsdv.c.
@@ -19,10 +19,14 @@
 #include <asm/sal.h>
 
 #define MB	(1024*1024UL)
-#define GB	(1024*MB)
-#define TB	(1024*GB)
 
-#define NUM_MEM_DESCS	4
+#define SIMPLE_MEMMAP	1
+
+#if SIMPLE_MEMMAP
+# define NUM_MEM_DESCS	4
+#else
+# define NUM_MEM_DESCS	16
+#endif
 
 static char fw_mem[(  sizeof(struct ia64_boot_param)
 		    + sizeof(efi_system_table_t)
@@ -381,6 +385,17 @@
 	struct ia64_boot_param *bp;
 	unsigned char checksum = 0;
 	char *cp, *cmd_line;
+	int i = 0;
+#	define MAKE_MD(typ, attr, start, end)		\
+	do {						\
+		md = efi_memmap + i++;			\
+		md->type = typ;				\
+		md->pad = 0;				\
+		md->phys_addr = start;			\
+		md->virt_addr = 0;			\
+		md->num_pages = (end - start) >> 12;	\
+		md->attribute = attr;			\
+	} while (0)
 
 	memset(fw_mem, 0, sizeof(fw_mem));
 
@@ -466,41 +481,30 @@
 
 	sal_systab->checksum = -checksum;
 
+#if SIMPLE_MEMMAP
 	/* simulate free memory at physical address zero */
-	md = &efi_memmap[0];
-	md->type = EFI_BOOT_SERVICES_DATA;
-	md->pad = 0;
-	md->phys_addr = 0*MB;
-	md->virt_addr = 0;
-	md->num_pages = (1*MB) >> 12;	/* 1MB (in 4KB pages) */
-	md->attribute = EFI_MEMORY_WB | EFI_MEMORY_WC | EFI_MEMORY_UC;
-
-	/* fill in a memory descriptor: */
-	md = &efi_memmap[1];
-	md->type = EFI_CONVENTIONAL_MEMORY;
-	md->pad = 0;
-	md->phys_addr = 2*MB;
-	md->virt_addr = 0;
-	md->num_pages = (128*MB) >> 12;	/* 128MB (in 4KB pages) */
-	md->attribute = EFI_MEMORY_WB;
-
-	/* descriptor for firmware emulator: */
-	md = &efi_memmap[2];
-	md->type = EFI_PAL_CODE;
-	md->pad = 0;
-	md->phys_addr = 1*MB;
-	md->virt_addr = 1*MB;
-	md->num_pages = (1*MB) >> 12;	/* 1MB (in 4KB pages) */
-	md->attribute = EFI_MEMORY_WB | EFI_MEMORY_WC | EFI_MEMORY_UC;
-
-	/* descriptor for high memory (>4TB): */
-	md = &efi_memmap[3];
-	md->type = EFI_CONVENTIONAL_MEMORY;
-	md->pad = 0;
-	md->phys_addr = 4*TB;
-	md->virt_addr = 0;
-	md->num_pages = (64*MB) >> 12;	/* 64MB (in 4KB pages) */
-	md->attribute = EFI_MEMORY_WB;
+	MAKE_MD(EFI_BOOT_SERVICES_DATA,		EFI_MEMORY_WB,    0*MB,    1*MB);
+	MAKE_MD(EFI_PAL_CODE,			EFI_MEMORY_WB,    1*MB,    2*MB);
+	MAKE_MD(EFI_CONVENTIONAL_MEMORY,	EFI_MEMORY_WB,    2*MB,  130*MB);
+	MAKE_MD(EFI_CONVENTIONAL_MEMORY,	EFI_MEMORY_WB, 4096*MB, 4128*MB);
+#else
+	MAKE_MD( 4,		   0x9, 0x0000000000000000, 0x0000000000001000);
+	MAKE_MD( 7,		   0x9, 0x0000000000001000, 0x000000000008a000);
+	MAKE_MD( 4,		   0x9, 0x000000000008a000, 0x00000000000a0000);
+	MAKE_MD( 5, 0x8000000000000009, 0x00000000000c0000, 0x0000000000100000);
+	MAKE_MD( 7,		   0x9, 0x0000000000100000, 0x0000000004400000);
+	MAKE_MD( 2,		   0x9, 0x0000000004400000, 0x0000000004be5000);
+	MAKE_MD( 7,		   0x9, 0x0000000004be5000, 0x000000007f77e000);
+	MAKE_MD( 6, 0x8000000000000009, 0x000000007f77e000, 0x000000007fb94000);
+	MAKE_MD( 6, 0x8000000000000009, 0x000000007fb94000, 0x000000007fb95000);
+	MAKE_MD( 6, 0x8000000000000009, 0x000000007fb95000, 0x000000007fc00000);
+	MAKE_MD(13, 0x8000000000000009, 0x000000007fc00000, 0x000000007fc3a000);
+	MAKE_MD( 7,		   0x9, 0x000000007fc3a000, 0x000000007fea0000);
+	MAKE_MD( 5, 0x8000000000000009, 0x000000007fea0000, 0x000000007fea8000);
+	MAKE_MD( 7,		   0x9, 0x000000007fea8000, 0x000000007feab000);
+	MAKE_MD( 5, 0x8000000000000009, 0x000000007feab000, 0x000000007ffff000);
+	MAKE_MD( 7,		   0x9, 0x00000000ff400000, 0x0000000104000000);
+#endif
 
 	bp->efi_systab = __pa(&fw_mem);
 	bp->efi_memmap = __pa(efi_memmap);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/gate.S linux-2.4.21/arch/ia64/kernel/gate.S
--- linux-2.4.20/arch/ia64/kernel/gate.S	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/gate.S	2002-12-18 18:58:05.000000000 +0000
@@ -2,7 +2,7 @@
  * This file contains the code that gets mapped at the upper end of each task's text
  * region.  For now, it contains the signal trampoline code only.
  *
- * Copyright (C) 1999-2001 Hewlett-Packard Co
+ * Copyright (C) 1999-2002 Hewlett-Packard Co
  * 	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
@@ -135,7 +135,7 @@
 	;;
 	ld8 r8=[base0]				// restore (perhaps modified) CFM0, EC0, and CPL0
 	cmp.ne p8,p0=r14,r15			// do we need to restore the rbs?
-(p8)	br.cond.spnt restore_rbs		// yup -> (clobbers r14 and r16)
+(p8)	br.cond.spnt restore_rbs		// yup -> (clobbers r14-r18, f6 & f7)
 	;;
 back_from_restore_rbs:
 	adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp
@@ -189,20 +189,69 @@
 	.spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF
 	.body
 restore_rbs:
+	// On input:
+	//	r14 = bsp1 (bsp at the time of return from signal handler)
+	//	r15 = bsp0 (bsp at the time the signal occurred)
+	//
+	// Here, we need to calculate bspstore0, the value that ar.bspstore needs
+	// to be set to, based on bsp0 and the size of the dirty partition on
+	// the alternate stack (sc_loadrs >> 16).  This can be done with the
+	// following algorithm:
+	//
+	//  bspstore0 = rse_skip_regs(bsp0, -rse_num_regs(bsp1 - (loadrs >> 19), bsp1));
+	//
+	// This is what the code below does.
+	//
 	alloc r2=ar.pfs,0,0,0,0			// alloc null frame
 	adds r16=(LOADRS_OFF+SIGCONTEXT_OFF),sp
+	adds r18=(RNAT_OFF+SIGCONTEXT_OFF),sp
 	;;
-	ld8 r14=[r16]
-	adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp
+	ld8 r17=[r16]
+	ld8 r16=[r18]			// get new rnat
+	extr.u r18=r15,3,6	// r18 <- rse_slot_num(bsp0)
 	;;
-	mov ar.rsc=r14				// put RSE into enforced lazy mode
-	ld8 r14=[r16]				// get new rnat
+	mov ar.rsc=r17			// put RSE into enforced lazy mode
+	shr.u r17=r17,16
 	;;
-	loadrs					// restore dirty partition
+	sub r14=r14,r17		// r14 (bspstore1) <- bsp1 - (sc_loadrs >> 16)
+	shr.u r17=r17,3		// r17 <- (sc_loadrs >> 19)
+	;;
+	loadrs			// restore dirty partition
+	extr.u r14=r14,3,6	// r14 <- rse_slot_num(bspstore1)
+	;;
+	add r14=r14,r17		// r14 <- rse_slot_num(bspstore1) + (sc_loadrs >> 19)
+	;;
+	shr.u r14=r14,6		// r14 <- (rse_slot_num(bspstore1) + (sc_loadrs >> 19))/0x40
+	;;
+	sub r14=r14,r17		// r14 <- -rse_num_regs(bspstore1, bsp1)
+	movl r17=0x8208208208208209
+	;;
+	add r18=r18,r14		// r18 (delta) <- rse_slot_num(bsp0) - rse_num_regs(bspstore1,bsp1)
+	setf.sig f7=r17
+	cmp.lt p7,p0=r14,r0	// p7 <- (r14 < 0)?
+	;;
+(p7)	adds r18=-62,r18	// delta -= 62
+	;;
+	setf.sig f6=r18
+	;;
+	xmpy.h f6=f6,f7
+	;;
+	getf.sig r17=f6
+	;;
+	add r17=r17,r18
+	shr r18=r18,63
+	;;
+	shr r17=r17,5
+	;;
+	sub r17=r17,r18		// r17 = delta/63
+	;;
+	add r17=r14,r17		// r17 <- delta/63 - rse_num_regs(bspstore1, bsp1)
+	;;
+	shladd r15=r17,3,r15	// r15 <- bsp0 + 8*(delta/63 - rse_num_regs(bspstore1, bsp1))
 	;;
 	mov ar.bspstore=r15			// switch back to old register backing store area
 	;;
-	mov ar.rnat=r14				// restore RNaT
+	mov ar.rnat=r16				// restore RNaT
 	mov ar.rsc=0xf				// (will be restored later on from sc_ar_rsc)
 	// invala not necessary as that will happen when returning to user-mode
 	br.cond.sptk back_from_restore_rbs
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/head.S linux-2.4.21/arch/ia64/kernel/head.S
--- linux-2.4.20/arch/ia64/kernel/head.S	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/head.S	2002-12-18 18:58:10.000000000 +0000
@@ -13,6 +13,8 @@
  * Copyright (C) 1999 Intel Corp.
  * Copyright (C) 1999 Asit Mallick <Asit.K.Mallick@intel.com>
  * Copyright (C) 1999 Don Dugger <Don.Dugger@intel.com>
+ * Copyright (C) 2002 Fenghua Yu <fenghua.yu@intel.com>
+ *   -Optimize __ia64_save_fpu() and __ia64_load_fpu() for Itanium 2.
  */
 
 #include <linux/config.h>
@@ -262,302 +264,297 @@
 END(ia64_load_debug_regs)
 
 GLOBAL_ENTRY(__ia64_save_fpu)
-	alloc r2=ar.pfs,1,0,0,0
-	adds r3=16,in0
+	alloc r2=ar.pfs,1,4,0,0
+	adds loc0=96*16-16,in0
+	adds loc1=96*16-16-128,in0
 	;;
-	stf.spill.nta [in0]=f32,32
-	stf.spill.nta [ r3]=f33,32
+	stf.spill.nta [loc0]=f127,-256
+	stf.spill.nta [loc1]=f119,-256
 	;;
-	stf.spill.nta [in0]=f34,32
-	stf.spill.nta [ r3]=f35,32
+	stf.spill.nta [loc0]=f111,-256
+	stf.spill.nta [loc1]=f103,-256
 	;;
-	stf.spill.nta [in0]=f36,32
-	stf.spill.nta [ r3]=f37,32
+	stf.spill.nta [loc0]=f95,-256
+	stf.spill.nta [loc1]=f87,-256
 	;;
-	stf.spill.nta [in0]=f38,32
-	stf.spill.nta [ r3]=f39,32
+	stf.spill.nta [loc0]=f79,-256
+	stf.spill.nta [loc1]=f71,-256
 	;;
-	stf.spill.nta [in0]=f40,32
-	stf.spill.nta [ r3]=f41,32
+	stf.spill.nta [loc0]=f63,-256
+	stf.spill.nta [loc1]=f55,-256
+	adds loc2=96*16-32,in0
 	;;
-	stf.spill.nta [in0]=f42,32
-	stf.spill.nta [ r3]=f43,32
+	stf.spill.nta [loc0]=f47,-256
+	stf.spill.nta [loc1]=f39,-256
+	adds loc3=96*16-32-128,in0
 	;;
-	stf.spill.nta [in0]=f44,32
-	stf.spill.nta [ r3]=f45,32
+	stf.spill.nta [loc2]=f126,-256
+	stf.spill.nta [loc3]=f118,-256
 	;;
-	stf.spill.nta [in0]=f46,32
-	stf.spill.nta [ r3]=f47,32
+	stf.spill.nta [loc2]=f110,-256
+	stf.spill.nta [loc3]=f102,-256
 	;;
-	stf.spill.nta [in0]=f48,32
-	stf.spill.nta [ r3]=f49,32
+	stf.spill.nta [loc2]=f94,-256
+	stf.spill.nta [loc3]=f86,-256
 	;;
-	stf.spill.nta [in0]=f50,32
-	stf.spill.nta [ r3]=f51,32
+	stf.spill.nta [loc2]=f78,-256
+	stf.spill.nta [loc3]=f70,-256
 	;;
-	stf.spill.nta [in0]=f52,32
-	stf.spill.nta [ r3]=f53,32
+	stf.spill.nta [loc2]=f62,-256
+	stf.spill.nta [loc3]=f54,-256
+	adds loc0=96*16-48,in0
 	;;
-	stf.spill.nta [in0]=f54,32
-	stf.spill.nta [ r3]=f55,32
+	stf.spill.nta [loc2]=f46,-256
+	stf.spill.nta [loc3]=f38,-256
+	adds loc1=96*16-48-128,in0
 	;;
-	stf.spill.nta [in0]=f56,32
-	stf.spill.nta [ r3]=f57,32
+	stf.spill.nta [loc0]=f125,-256
+	stf.spill.nta [loc1]=f117,-256
 	;;
-	stf.spill.nta [in0]=f58,32
-	stf.spill.nta [ r3]=f59,32
+	stf.spill.nta [loc0]=f109,-256
+	stf.spill.nta [loc1]=f101,-256
 	;;
-	stf.spill.nta [in0]=f60,32
-	stf.spill.nta [ r3]=f61,32
+	stf.spill.nta [loc0]=f93,-256
+	stf.spill.nta [loc1]=f85,-256
 	;;
-	stf.spill.nta [in0]=f62,32
-	stf.spill.nta [ r3]=f63,32
+	stf.spill.nta [loc0]=f77,-256
+	stf.spill.nta [loc1]=f69,-256
 	;;
-	stf.spill.nta [in0]=f64,32
-	stf.spill.nta [ r3]=f65,32
+	stf.spill.nta [loc0]=f61,-256
+	stf.spill.nta [loc1]=f53,-256
+	adds loc2=96*16-64,in0
 	;;
-	stf.spill.nta [in0]=f66,32
-	stf.spill.nta [ r3]=f67,32
+	stf.spill.nta [loc0]=f45,-256
+	stf.spill.nta [loc1]=f37,-256
+	adds loc3=96*16-64-128,in0
 	;;
-	stf.spill.nta [in0]=f68,32
-	stf.spill.nta [ r3]=f69,32
+	stf.spill.nta [loc2]=f124,-256
+	stf.spill.nta [loc3]=f116,-256
 	;;
-	stf.spill.nta [in0]=f70,32
-	stf.spill.nta [ r3]=f71,32
+	stf.spill.nta [loc2]=f108,-256
+	stf.spill.nta [loc3]=f100,-256
 	;;
-	stf.spill.nta [in0]=f72,32
-	stf.spill.nta [ r3]=f73,32
+	stf.spill.nta [loc2]=f92,-256
+	stf.spill.nta [loc3]=f84,-256
 	;;
-	stf.spill.nta [in0]=f74,32
-	stf.spill.nta [ r3]=f75,32
+	stf.spill.nta [loc2]=f76,-256
+	stf.spill.nta [loc3]=f68,-256
 	;;
-	stf.spill.nta [in0]=f76,32
-	stf.spill.nta [ r3]=f77,32
+	stf.spill.nta [loc2]=f60,-256
+	stf.spill.nta [loc3]=f52,-256
+	adds loc0=96*16-80,in0
 	;;
-	stf.spill.nta [in0]=f78,32
-	stf.spill.nta [ r3]=f79,32
+	stf.spill.nta [loc2]=f44,-256
+	stf.spill.nta [loc3]=f36,-256
+	adds loc1=96*16-80-128,in0
 	;;
-	stf.spill.nta [in0]=f80,32
-	stf.spill.nta [ r3]=f81,32
+	stf.spill.nta [loc0]=f123,-256
+	stf.spill.nta [loc1]=f115,-256
 	;;
-	stf.spill.nta [in0]=f82,32
-	stf.spill.nta [ r3]=f83,32
+	stf.spill.nta [loc0]=f107,-256
+	stf.spill.nta [loc1]=f99,-256
 	;;
-	stf.spill.nta [in0]=f84,32
-	stf.spill.nta [ r3]=f85,32
+	stf.spill.nta [loc0]=f91,-256
+	stf.spill.nta [loc1]=f83,-256
 	;;
-	stf.spill.nta [in0]=f86,32
-	stf.spill.nta [ r3]=f87,32
+	stf.spill.nta [loc0]=f75,-256
+	stf.spill.nta [loc1]=f67,-256
 	;;
-	stf.spill.nta [in0]=f88,32
-	stf.spill.nta [ r3]=f89,32
+	stf.spill.nta [loc0]=f59,-256
+	stf.spill.nta [loc1]=f51,-256
+	adds loc2=96*16-96,in0
 	;;
-	stf.spill.nta [in0]=f90,32
-	stf.spill.nta [ r3]=f91,32
+	stf.spill.nta [loc0]=f43,-256
+	stf.spill.nta [loc1]=f35,-256
+	adds loc3=96*16-96-128,in0
 	;;
-	stf.spill.nta [in0]=f92,32
-	stf.spill.nta [ r3]=f93,32
+	stf.spill.nta [loc2]=f122,-256
+	stf.spill.nta [loc3]=f114,-256
 	;;
-	stf.spill.nta [in0]=f94,32
-	stf.spill.nta [ r3]=f95,32
+	stf.spill.nta [loc2]=f106,-256
+	stf.spill.nta [loc3]=f98,-256
 	;;
-	stf.spill.nta [in0]=f96,32
-	stf.spill.nta [ r3]=f97,32
+	stf.spill.nta [loc2]=f90,-256
+	stf.spill.nta [loc3]=f82,-256
 	;;
-	stf.spill.nta [in0]=f98,32
-	stf.spill.nta [ r3]=f99,32
+	stf.spill.nta [loc2]=f74,-256
+	stf.spill.nta [loc3]=f66,-256
 	;;
-	stf.spill.nta [in0]=f100,32
-	stf.spill.nta [ r3]=f101,32
+	stf.spill.nta [loc2]=f58,-256
+	stf.spill.nta [loc3]=f50,-256
+	adds loc0=96*16-112,in0
 	;;
-	stf.spill.nta [in0]=f102,32
-	stf.spill.nta [ r3]=f103,32
+	stf.spill.nta [loc2]=f42,-256
+	stf.spill.nta [loc3]=f34,-256
+	adds loc1=96*16-112-128,in0
 	;;
-	stf.spill.nta [in0]=f104,32
-	stf.spill.nta [ r3]=f105,32
+	stf.spill.nta [loc0]=f121,-256
+	stf.spill.nta [loc1]=f113,-256
 	;;
-	stf.spill.nta [in0]=f106,32
-	stf.spill.nta [ r3]=f107,32
+	stf.spill.nta [loc0]=f105,-256
+	stf.spill.nta [loc1]=f97,-256
 	;;
-	stf.spill.nta [in0]=f108,32
-	stf.spill.nta [ r3]=f109,32
+	stf.spill.nta [loc0]=f89,-256
+	stf.spill.nta [loc1]=f81,-256
 	;;
-	stf.spill.nta [in0]=f110,32
-	stf.spill.nta [ r3]=f111,32
+	stf.spill.nta [loc0]=f73,-256
+	stf.spill.nta [loc1]=f65,-256
 	;;
-	stf.spill.nta [in0]=f112,32
-	stf.spill.nta [ r3]=f113,32
+	stf.spill.nta [loc0]=f57,-256
+	stf.spill.nta [loc1]=f49,-256
+	adds loc2=96*16-128,in0
 	;;
-	stf.spill.nta [in0]=f114,32
-	stf.spill.nta [ r3]=f115,32
+	stf.spill.nta [loc0]=f41,-256
+	stf.spill.nta [loc1]=f33,-256
+	adds loc3=96*16-128-128,in0
 	;;
-	stf.spill.nta [in0]=f116,32
-	stf.spill.nta [ r3]=f117,32
+	stf.spill.nta [loc2]=f120,-256
+	stf.spill.nta [loc3]=f112,-256
 	;;
-	stf.spill.nta [in0]=f118,32
-	stf.spill.nta [ r3]=f119,32
+	stf.spill.nta [loc2]=f104,-256
+	stf.spill.nta [loc3]=f96,-256
 	;;
-	stf.spill.nta [in0]=f120,32
-	stf.spill.nta [ r3]=f121,32
+	stf.spill.nta [loc2]=f88,-256
+	stf.spill.nta [loc3]=f80,-256
 	;;
-	stf.spill.nta [in0]=f122,32
-	stf.spill.nta [ r3]=f123,32
+	stf.spill.nta [loc2]=f72,-256
+	stf.spill.nta [loc3]=f64,-256
 	;;
-	stf.spill.nta [in0]=f124,32
-	stf.spill.nta [ r3]=f125,32
+	stf.spill.nta [loc2]=f56,-256
+	stf.spill.nta [loc3]=f48,-256
 	;;
-	stf.spill.nta [in0]=f126,32
-	stf.spill.nta [ r3]=f127,32
+	stf.spill.nta [loc2]=f40
+	stf.spill.nta [loc3]=f32
 	br.ret.sptk.many rp
 END(__ia64_save_fpu)
 
 GLOBAL_ENTRY(__ia64_load_fpu)
-	alloc r2=ar.pfs,1,0,0,0
-	adds r3=16,in0
-	;;
-	ldf.fill.nta f32=[in0],32
-	ldf.fill.nta f33=[ r3],32
-	;;
-	ldf.fill.nta f34=[in0],32
-	ldf.fill.nta f35=[ r3],32
-	;;
-	ldf.fill.nta f36=[in0],32
-	ldf.fill.nta f37=[ r3],32
-	;;
-	ldf.fill.nta f38=[in0],32
-	ldf.fill.nta f39=[ r3],32
-	;;
-	ldf.fill.nta f40=[in0],32
-	ldf.fill.nta f41=[ r3],32
-	;;
-	ldf.fill.nta f42=[in0],32
-	ldf.fill.nta f43=[ r3],32
-	;;
-	ldf.fill.nta f44=[in0],32
-	ldf.fill.nta f45=[ r3],32
-	;;
-	ldf.fill.nta f46=[in0],32
-	ldf.fill.nta f47=[ r3],32
-	;;
-	ldf.fill.nta f48=[in0],32
-	ldf.fill.nta f49=[ r3],32
-	;;
-	ldf.fill.nta f50=[in0],32
-	ldf.fill.nta f51=[ r3],32
-	;;
-	ldf.fill.nta f52=[in0],32
-	ldf.fill.nta f53=[ r3],32
-	;;
-	ldf.fill.nta f54=[in0],32
-	ldf.fill.nta f55=[ r3],32
-	;;
-	ldf.fill.nta f56=[in0],32
-	ldf.fill.nta f57=[ r3],32
-	;;
-	ldf.fill.nta f58=[in0],32
-	ldf.fill.nta f59=[ r3],32
-	;;
-	ldf.fill.nta f60=[in0],32
-	ldf.fill.nta f61=[ r3],32
-	;;
-	ldf.fill.nta f62=[in0],32
-	ldf.fill.nta f63=[ r3],32
-	;;
-	ldf.fill.nta f64=[in0],32
-	ldf.fill.nta f65=[ r3],32
-	;;
-	ldf.fill.nta f66=[in0],32
-	ldf.fill.nta f67=[ r3],32
-	;;
-	ldf.fill.nta f68=[in0],32
-	ldf.fill.nta f69=[ r3],32
-	;;
-	ldf.fill.nta f70=[in0],32
-	ldf.fill.nta f71=[ r3],32
-	;;
-	ldf.fill.nta f72=[in0],32
-	ldf.fill.nta f73=[ r3],32
-	;;
-	ldf.fill.nta f74=[in0],32
-	ldf.fill.nta f75=[ r3],32
-	;;
-	ldf.fill.nta f76=[in0],32
-	ldf.fill.nta f77=[ r3],32
-	;;
-	ldf.fill.nta f78=[in0],32
-	ldf.fill.nta f79=[ r3],32
-	;;
-	ldf.fill.nta f80=[in0],32
-	ldf.fill.nta f81=[ r3],32
-	;;
-	ldf.fill.nta f82=[in0],32
-	ldf.fill.nta f83=[ r3],32
-	;;
-	ldf.fill.nta f84=[in0],32
-	ldf.fill.nta f85=[ r3],32
-	;;
-	ldf.fill.nta f86=[in0],32
-	ldf.fill.nta f87=[ r3],32
-	;;
-	ldf.fill.nta f88=[in0],32
-	ldf.fill.nta f89=[ r3],32
-	;;
-	ldf.fill.nta f90=[in0],32
-	ldf.fill.nta f91=[ r3],32
-	;;
-	ldf.fill.nta f92=[in0],32
-	ldf.fill.nta f93=[ r3],32
-	;;
-	ldf.fill.nta f94=[in0],32
-	ldf.fill.nta f95=[ r3],32
-	;;
-	ldf.fill.nta f96=[in0],32
-	ldf.fill.nta f97=[ r3],32
-	;;
-	ldf.fill.nta f98=[in0],32
-	ldf.fill.nta f99=[ r3],32
-	;;
-	ldf.fill.nta f100=[in0],32
-	ldf.fill.nta f101=[ r3],32
-	;;
-	ldf.fill.nta f102=[in0],32
-	ldf.fill.nta f103=[ r3],32
-	;;
-	ldf.fill.nta f104=[in0],32
-	ldf.fill.nta f105=[ r3],32
-	;;
-	ldf.fill.nta f106=[in0],32
-	ldf.fill.nta f107=[ r3],32
-	;;
-	ldf.fill.nta f108=[in0],32
-	ldf.fill.nta f109=[ r3],32
-	;;
-	ldf.fill.nta f110=[in0],32
-	ldf.fill.nta f111=[ r3],32
-	;;
-	ldf.fill.nta f112=[in0],32
-	ldf.fill.nta f113=[ r3],32
-	;;
-	ldf.fill.nta f114=[in0],32
-	ldf.fill.nta f115=[ r3],32
-	;;
-	ldf.fill.nta f116=[in0],32
-	ldf.fill.nta f117=[ r3],32
-	;;
-	ldf.fill.nta f118=[in0],32
-	ldf.fill.nta f119=[ r3],32
-	;;
-	ldf.fill.nta f120=[in0],32
-	ldf.fill.nta f121=[ r3],32
-	;;
-	ldf.fill.nta f122=[in0],32
-	ldf.fill.nta f123=[ r3],32
-	;;
-	ldf.fill.nta f124=[in0],32
-	ldf.fill.nta f125=[ r3],32
-	;;
-	ldf.fill.nta f126=[in0],32
-	ldf.fill.nta f127=[ r3],32
+	alloc r2=ar.pfs,1,2,0,0
+	adds r3=128,in0
+	adds r14=256,in0
+	adds r15=384,in0
+	mov loc0=512
+	mov loc1=-1024+16
+	;;
+	ldf.fill.nta f32=[in0],loc0
+	ldf.fill.nta f40=[ r3],loc0
+	ldf.fill.nta f48=[r14],loc0
+	ldf.fill.nta f56=[r15],loc0
+	;;
+	ldf.fill.nta f64=[in0],loc0
+	ldf.fill.nta f72=[ r3],loc0
+	ldf.fill.nta f80=[r14],loc0
+	ldf.fill.nta f88=[r15],loc0
+	;;
+	ldf.fill.nta f96=[in0],loc1
+	ldf.fill.nta f104=[ r3],loc1
+	ldf.fill.nta f112=[r14],loc1
+	ldf.fill.nta f120=[r15],loc1
+	;;
+	ldf.fill.nta f33=[in0],loc0
+	ldf.fill.nta f41=[ r3],loc0
+	ldf.fill.nta f49=[r14],loc0
+	ldf.fill.nta f57=[r15],loc0
+	;;
+	ldf.fill.nta f65=[in0],loc0
+	ldf.fill.nta f73=[ r3],loc0
+	ldf.fill.nta f81=[r14],loc0
+	ldf.fill.nta f89=[r15],loc0
+	;;
+	ldf.fill.nta f97=[in0],loc1
+	ldf.fill.nta f105=[ r3],loc1
+	ldf.fill.nta f113=[r14],loc1
+	ldf.fill.nta f121=[r15],loc1
+	;;
+	ldf.fill.nta f34=[in0],loc0
+	ldf.fill.nta f42=[ r3],loc0
+	ldf.fill.nta f50=[r14],loc0
+	ldf.fill.nta f58=[r15],loc0
+	;;
+	ldf.fill.nta f66=[in0],loc0
+	ldf.fill.nta f74=[ r3],loc0
+	ldf.fill.nta f82=[r14],loc0
+	ldf.fill.nta f90=[r15],loc0
+	;;
+	ldf.fill.nta f98=[in0],loc1
+	ldf.fill.nta f106=[ r3],loc1
+	ldf.fill.nta f114=[r14],loc1
+	ldf.fill.nta f122=[r15],loc1
+	;;
+	ldf.fill.nta f35=[in0],loc0
+	ldf.fill.nta f43=[ r3],loc0
+	ldf.fill.nta f51=[r14],loc0
+	ldf.fill.nta f59=[r15],loc0
+	;;
+	ldf.fill.nta f67=[in0],loc0
+	ldf.fill.nta f75=[ r3],loc0
+	ldf.fill.nta f83=[r14],loc0
+	ldf.fill.nta f91=[r15],loc0
+	;;
+	ldf.fill.nta f99=[in0],loc1
+	ldf.fill.nta f107=[ r3],loc1
+	ldf.fill.nta f115=[r14],loc1
+	ldf.fill.nta f123=[r15],loc1
+	;;
+	ldf.fill.nta f36=[in0],loc0
+	ldf.fill.nta f44=[ r3],loc0
+	ldf.fill.nta f52=[r14],loc0
+	ldf.fill.nta f60=[r15],loc0
+	;;
+	ldf.fill.nta f68=[in0],loc0
+	ldf.fill.nta f76=[ r3],loc0
+	ldf.fill.nta f84=[r14],loc0
+	ldf.fill.nta f92=[r15],loc0
+	;;
+	ldf.fill.nta f100=[in0],loc1
+	ldf.fill.nta f108=[ r3],loc1
+	ldf.fill.nta f116=[r14],loc1
+	ldf.fill.nta f124=[r15],loc1
+	;;
+	ldf.fill.nta f37=[in0],loc0
+	ldf.fill.nta f45=[ r3],loc0
+	ldf.fill.nta f53=[r14],loc0
+	ldf.fill.nta f61=[r15],loc0
+	;;
+	ldf.fill.nta f69=[in0],loc0
+	ldf.fill.nta f77=[ r3],loc0
+	ldf.fill.nta f85=[r14],loc0
+	ldf.fill.nta f93=[r15],loc0
+	;;
+	ldf.fill.nta f101=[in0],loc1
+	ldf.fill.nta f109=[ r3],loc1
+	ldf.fill.nta f117=[r14],loc1
+	ldf.fill.nta f125=[r15],loc1
+	;;
+	ldf.fill.nta f38 =[in0],loc0
+	ldf.fill.nta f46 =[ r3],loc0
+	ldf.fill.nta f54 =[r14],loc0
+	ldf.fill.nta f62 =[r15],loc0
+	;;
+	ldf.fill.nta f70 =[in0],loc0
+	ldf.fill.nta f78 =[ r3],loc0
+	ldf.fill.nta f86 =[r14],loc0
+	ldf.fill.nta f94 =[r15],loc0
+	;;
+	ldf.fill.nta f102=[in0],loc1
+	ldf.fill.nta f110=[ r3],loc1
+	ldf.fill.nta f118=[r14],loc1
+	ldf.fill.nta f126=[r15],loc1
+	;;
+	ldf.fill.nta f39 =[in0],loc0
+	ldf.fill.nta f47 =[ r3],loc0
+	ldf.fill.nta f55 =[r14],loc0
+	ldf.fill.nta f63 =[r15],loc0
+	;;
+	ldf.fill.nta f71 =[in0],loc0
+	ldf.fill.nta f79 =[ r3],loc0
+	ldf.fill.nta f87 =[r14],loc0
+	ldf.fill.nta f95 =[r15],loc0
+	;;
+	ldf.fill.nta f103=[in0]
+	ldf.fill.nta f111=[ r3]
+	ldf.fill.nta f119=[r14]
+	ldf.fill.nta f127=[r15]
 	br.ret.sptk.many rp
 END(__ia64_load_fpu)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/ia64_ksyms.c linux-2.4.21/arch/ia64/kernel/ia64_ksyms.c
--- linux-2.4.20/arch/ia64/kernel/ia64_ksyms.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/ia64_ksyms.c	2002-12-18 18:58:08.000000000 +0000
@@ -57,6 +57,10 @@
 #include <asm/page.h>
 EXPORT_SYMBOL(clear_page);
 
+#include <asm/pgtable.h>
+EXPORT_SYMBOL(vmalloc_end);
+EXPORT_SYMBOL(ia64_page_valid);
+
 #include <asm/processor.h>
 # ifndef CONFIG_NUMA
 EXPORT_SYMBOL(_cpu_data);
@@ -100,7 +104,7 @@
 
 #else /* !CONFIG_SMP */
 
-EXPORT_SYMBOL(__flush_tlb_all);
+EXPORT_SYMBOL(local_flush_tlb_all);
 
 #endif /* !CONFIG_SMP */
 
@@ -141,6 +145,8 @@
 EXPORT_SYMBOL(ia64_pal_call_phys_static);
 EXPORT_SYMBOL(ia64_pal_call_stacked);
 EXPORT_SYMBOL(ia64_pal_call_static);
+EXPORT_SYMBOL(ia64_load_scratch_fpregs);
+EXPORT_SYMBOL(ia64_save_scratch_fpregs);
 
 extern struct efi efi;
 EXPORT_SYMBOL(efi);
@@ -154,4 +160,8 @@
 EXPORT_SYMBOL(ia64_mv);
 #endif
 EXPORT_SYMBOL(machvec_noop);
-
+#ifdef CONFIG_PERFMON
+#include <asm/perfmon.h>
+EXPORT_SYMBOL(pfm_install_alternate_syswide_subsystem);
+EXPORT_SYMBOL(pfm_remove_alternate_syswide_subsystem);
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/iosapic.c linux-2.4.21/arch/ia64/kernel/iosapic.c
--- linux-2.4.20/arch/ia64/kernel/iosapic.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/iosapic.c	2002-12-18 18:58:08.000000000 +0000
@@ -590,7 +590,7 @@
 		      gsi_base, addr);
 
 	DBG("ISA: IRQ %u -> GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
-	    isa_irq, global_vector,
+	    isa_irq, gsi,
 	    polarity ? "high" : "low", edge_triggered ? "edge" : "level",
 	    dest, vector);
 
@@ -661,7 +661,7 @@
 		register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
 			      0, 0, gsi_base, addr);
 
-		DBG("PCI: (%02x:%02x:%02x:%02x INT%c) -> GSI 0x%x -> vector %d\n",
+		DBG("PCI: (%02x:%02x:%02x INT%c) -> GSI 0x%x -> vector %d\n",
 		    segment, bus, slot, 'A' + pci_pin, gsi, vector);
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/irq.c linux-2.4.21/arch/ia64/kernel/irq.c
--- linux-2.4.20/arch/ia64/kernel/irq.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/irq.c	2002-12-18 18:58:06.000000000 +0000
@@ -1060,7 +1060,7 @@
 
 	if (!shared) {
 		desc->depth = 0;
-		desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING);
+		desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
 		desc->handler->startup(irq);
 	}
 	spin_unlock_irqrestore(&desc->lock,flags);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/irq_ia64.c linux-2.4.21/arch/ia64/kernel/irq_ia64.c
--- linux-2.4.20/arch/ia64/kernel/irq_ia64.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/irq_ia64.c	2002-12-18 18:58:07.000000000 +0000
@@ -178,7 +178,7 @@
 	register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction);
 #endif
 #ifdef CONFIG_PERFMON
-	perfmon_init_percpu();
+	pfm_init_percpu();
 #endif
 	platform_irq_init();
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/machvec.c linux-2.4.21/arch/ia64/kernel/machvec.c
--- linux-2.4.20/arch/ia64/kernel/machvec.c	2001-01-04 20:50:17.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/machvec.c	2002-12-18 18:58:08.000000000 +0000
@@ -15,7 +15,7 @@
  * into a memory map index.
  */
 unsigned long
-map_nr_dense (unsigned long addr)
+map_nr_dense (void *addr)
 {
 	return MAP_NR_DENSE(addr);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/mca.c linux-2.4.21/arch/ia64/kernel/mca.c
--- linux-2.4.20/arch/ia64/kernel/mca.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/mca.c	2002-12-18 18:58:08.000000000 +0000
@@ -42,6 +42,9 @@
 #include <linux/smp_lock.h>
 #include <linux/bootmem.h>
 #include <linux/acpi.h>
+#include <linux/timer.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
 
 #include <asm/machvec.h>
 #include <asm/page.h>
@@ -69,10 +72,10 @@
 u64				ia64_mca_bspstore[1024];
 u64				ia64_init_stack[INIT_TASK_SIZE] __attribute__((aligned(16)));
 u64				ia64_mca_sal_data_area[1356];
-u64				ia64_mca_min_state_save_info;
 u64				ia64_tlb_functional;
 u64				ia64_os_mca_recovery_successful;
-
+/* TODO: need to assign min-state structure to UC memory */
+u64				ia64_mca_min_state_save_info[MIN_STATE_AREA_SIZE] __attribute__((aligned(512)));
 static void			ia64_mca_wakeup_ipi_wait(void);
 static void			ia64_mca_wakeup(int cpu);
 static void			ia64_mca_wakeup_all(void);
@@ -105,6 +108,11 @@
 	name:       "cpe_hndlr"
 };
 
+#define MAX_CPE_POLL_INTERVAL (15*60*HZ) /* 15 minutes */
+#define MIN_CPE_POLL_INTERVAL (2*60*HZ)  /* 2 minutes */
+
+static struct timer_list cpe_poll_timer;
+
 /*
  *  ia64_mca_log_sal_error_record
  *
@@ -116,7 +124,7 @@
  *  Outputs :   platform error status
  */
 int
-ia64_mca_log_sal_error_record(int sal_info_type)
+ia64_mca_log_sal_error_record(int sal_info_type, int called_from_init)
 {
 	int platform_err = 0;
 
@@ -131,7 +139,10 @@
 	 */
 
 	platform_err = ia64_log_print(sal_info_type, (prfunc_t)printk);
-	ia64_sal_clear_state_info(sal_info_type);
+	/* temporary: only clear SAL logs on hardware-corrected errors
+		or if we're logging an error after an MCA-initiated reboot */
+	if ((sal_info_type > 1) || (called_from_init))
+		ia64_sal_clear_state_info(sal_info_type);
 
 	return platform_err;
 }
@@ -152,7 +163,7 @@
 	IA64_MCA_DEBUG("ia64_mca_cpe_int_handler: received interrupt. vector = %#x\n", cpe_irq);
 
 	/* Get the CMC error record and log it */
-	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE);
+	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE, 0);
 }
 
 /*
@@ -205,7 +216,7 @@
 	/*
 	 *  If there is an MCA error record pending, get it and log it.
 	 */
-	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
+	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 1);
 }
 
 /*
@@ -257,15 +268,23 @@
  *
  */
 void
-ia64_process_min_state_save (pal_min_state_area_t *pmss, struct pt_regs *ptregs)
+ia64_process_min_state_save (pal_min_state_area_t *pmss)
 {
-	int i, max=57;
-	u64 *tpmss_ptr=(u64 *)pmss;
+	int i, max = MIN_STATE_AREA_SIZE;
+	u64 *tpmss_ptr = (u64 *)pmss;
+	u64 *return_min_state_ptr = ia64_mca_min_state_save_info;
 
 	/* dump out the min_state_area information */
 
 	for (i=0;i<max;i++) {
 
+		/* copy min-state register info for eventual return to PAL */
+		*return_min_state_ptr++ = *tpmss_ptr;
+
+#if 1
+		tpmss_ptr++;  /* skip to next entry */
+#else
+		/* the printing part */
 		if(!ia64_pmss_dump_bank0) {
 			if(strncmp("B0",min_state_labels[i],2)==0) {
 				tpmss_ptr++;  /* skip to next entry */
@@ -278,6 +297,7 @@
 		if (((i+1)%3)==0 || ((!strcmp("GR16",min_state_labels[i]))
 				     && !ia64_pmss_dump_bank0))
 			printk("\n");
+#endif
 	}
 }
 
@@ -510,8 +530,7 @@
 					setup_irq(irq, &mca_cpe_irqaction);
 				}
 			ia64_mca_register_cpev(cpev);
-		} else
-			printk("ia64_mca_init: Failed to get routed CPEI vector from ACPI.\n");
+		}
 	}
 
 	/* Initialize the areas set aside by the OS to buffer the
@@ -523,19 +542,17 @@
 	ia64_log_init(SAL_INFO_TYPE_CMC);
 	ia64_log_init(SAL_INFO_TYPE_CPE);
 
-	/* Zero the min state save info */
-	ia64_mca_min_state_save_info = 0;
-
 #if defined(MCA_TEST)
 	mca_test();
 #endif /* #if defined(MCA_TEST) */
 
 	printk("Mca related initialization done\n");
 
-#if 0   // Too early in initialization -- error log is lost
+	/* commented out because this is done elsewhere */
+#if 0
 	/* Do post-failure MCA error logging */
 	ia64_mca_check_errors();
-#endif  // Too early in initialization -- error log is lost
+#endif
 }
 
 /*
@@ -701,8 +718,8 @@
 	ia64_os_to_sal_handoff_state.imots_context = IA64_MCA_SAME_CONTEXT;
 
 	/* Register pointer to new min state values */
-	/* NOTE: need to do something with this during recovery phase */
-	ia64_os_to_sal_handoff_state.imots_new_min_state = &ia64_mca_min_state_save_info;
+	ia64_os_to_sal_handoff_state.imots_new_min_state =
+		(pal_min_state_area_t *)ia64_mca_min_state_save_info;
 }
 
 /*
@@ -727,7 +744,7 @@
 	int platform_err = 0;
 
 	/* Get the MCA error record and log it */
-	platform_err = ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
+	platform_err = ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 0);
 
 	/*
 	 *  Do Platform-specific mca error handling if required.
@@ -767,7 +784,7 @@
 		       cmc_irq, smp_processor_id());
 
 	/* Get the CMC error record and log it */
-	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC);
+	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC, 0);
 }
 
 /*
@@ -803,6 +820,62 @@
 #define IA64_LOG_CURR_BUFFER(it)   (void *)((ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)]))
 
 /*
+ *  ia64_mca_cpe_poll
+ *
+ *	Poll for Corrected Platform Errors (CPEs), dynamically adjust
+ *	polling interval based on occurance of an event.
+ *
+ * Inputs   :   dummy(unused)
+ * Outputs  :   None
+ *
+ */
+static void
+ia64_mca_cpe_poll (unsigned long dummy)
+{
+	int start_index;
+	static int poll_time = MAX_CPE_POLL_INTERVAL;
+
+	start_index = IA64_LOG_CURR_INDEX(SAL_INFO_TYPE_CPE);
+
+	/* Call the interrupt handler */
+	ia64_mca_cpe_int_handler(0, NULL, NULL);
+
+	/*
+	 * If a log was recorded, increase our polling frequency,
+	 * otherwise, backoff.
+	 */
+	if (start_index != IA64_LOG_CURR_INDEX(SAL_INFO_TYPE_CPE)) {
+		poll_time = max(MIN_CPE_POLL_INTERVAL, poll_time/2);
+	} else {
+		poll_time = min(MAX_CPE_POLL_INTERVAL, poll_time * 2);
+	}
+	mod_timer(&cpe_poll_timer, jiffies + poll_time);
+}
+
+/*
+ * ia64_mca_late_init
+ *
+ *	Opportunity to setup things that require initialization later
+ *	than ia64_mca_init.  Setup a timer to poll for CPEs if the
+ *	platform doesn't support an interrupt driven mechanism.
+ *
+ *  Inputs  :   None
+ *  Outputs :   Status
+ */
+static int __init
+ia64_mca_late_init(void)
+{
+	if (acpi_request_vector(ACPI_INTERRUPT_CPEI) < 0) {
+		init_timer(&cpe_poll_timer);
+		cpe_poll_timer.function = ia64_mca_cpe_poll;
+		ia64_mca_cpe_poll(0);
+	}
+	return 0;
+}
+
+module_init(ia64_mca_late_init);
+
+/*
  * C portion of the OS INIT handler
  *
  * Called from ia64_monarch_init_handler
@@ -837,8 +910,7 @@
 	plog_ptr=(ia64_err_rec_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT);
 	proc_ptr = &plog_ptr->proc_err;
 
-	ia64_process_min_state_save(&proc_ptr->processor_static_info.min_state_area,
-				    regs);
+	ia64_process_min_state_save(&proc_ptr->processor_static_info.min_state_area);
 
 	/* Clear the INIT SAL logs now that they have been saved in the OS buffer */
 	ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT);
@@ -962,7 +1034,6 @@
 		return total_len;
 	} else {
 		IA64_LOG_UNLOCK(sal_info_type);
-		prfunc("ia64_log_get: No SAL error record available for type %d\n", sal_info_type);
 		return 0;
 	}
 }
@@ -1004,28 +1075,13 @@
 void
 ia64_log_rec_header_print (sal_log_record_header_t *lh, prfunc_t prfunc)
 {
-	char str_buf[32];
-
-	sprintf(str_buf, "%2d.%02d",
-		(lh->revision.major >> 4) * 10 + (lh->revision.major & 0xf),
-		(lh->revision.minor >> 4) * 10 + (lh->revision.minor & 0xf));
-	prfunc("+Err Record ID: %d    SAL Rev: %s\n", lh->id, str_buf);
-	sprintf(str_buf, "%02d/%02d/%04d/ %02d:%02d:%02d",
-		(lh->timestamp.slh_month >> 4) * 10 +
-		(lh->timestamp.slh_month & 0xf),
-		(lh->timestamp.slh_day >> 4) * 10 +
-		(lh->timestamp.slh_day & 0xf),
-		(lh->timestamp.slh_century >> 4) * 1000 +
-		(lh->timestamp.slh_century & 0xf) * 100 +
-		(lh->timestamp.slh_year >> 4) * 10 +
-		(lh->timestamp.slh_year & 0xf),
-		(lh->timestamp.slh_hour >> 4) * 10 +
-		(lh->timestamp.slh_hour & 0xf),
-		(lh->timestamp.slh_minute >> 4) * 10 +
-		(lh->timestamp.slh_minute & 0xf),
-		(lh->timestamp.slh_second >> 4) * 10 +
-		(lh->timestamp.slh_second & 0xf));
-	prfunc("+Time: %s    Severity %d\n", str_buf, lh->severity);
+	prfunc("+Err Record ID: %d    SAL Rev: %2x.%02x\n", lh->id,
+		lh->revision.major, lh->revision.minor);
+	prfunc("+Time: %02x/%02x/%02x%02x %02d:%02d:%02d    Severity %d\n",
+		lh->timestamp.slh_month, lh->timestamp.slh_day,
+		lh->timestamp.slh_century, lh->timestamp.slh_year,
+		lh->timestamp.slh_hour, lh->timestamp.slh_minute,
+		lh->timestamp.slh_second, lh->severity);
 }
 
 /*
@@ -1684,6 +1740,9 @@
 	if (slpi->valid.psi_static_struct) {
 		spsi = (sal_processor_static_info_t *)p_data;
 
+		/* copy interrupted context PAL min-state info */
+		ia64_process_min_state_save(&spsi->min_state_area);
+
 		/* Print branch register contents if valid */
 		if (spsi->valid.br)
 			ia64_log_processor_regs_print(spsi->br, 8, "Branch", "br",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/pal.S linux-2.4.21/arch/ia64/kernel/pal.S
--- linux-2.4.20/arch/ia64/kernel/pal.S	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/pal.S	2002-12-18 18:58:12.000000000 +0000
@@ -245,3 +245,49 @@
 	br.ret.sptk.many b0
 END(ia64_pal_call_phys_stacked)
 
+/*
+ * Save scratch fp scratch regs (fp10-fp15)
+ *
+ * NOTE: We need to do this since firmware (SAL or PAL) uses more
+ * scratch fp regs than the Linux kernel does.
+ *
+ * Inputs:
+ *      in0         Address of stack storage for fp regs
+ */
+
+GLOBAL_ENTRY(ia64_save_scratch_fpregs)
+	alloc r3=ar.pfs,1,0,0,0
+	add r2=16,in0
+	;;
+	stf.spill [in0] = f10,32
+	stf.spill [r2]  = f11,32
+	;;
+	stf.spill [in0] = f12,32
+	stf.spill [r2]  = f13,32
+	;;
+	stf.spill [in0] = f14,32
+	stf.spill [r2]  = f15,32
+	br.ret.sptk.many rp
+END(ia64_save_scratch_fpregs)
+
+/*
+ * Load scratch fp scratch regs (fp10-fp15)
+ *
+ * Inputs:
+ *      in0         Address of stack storage for fp regs
+ */
+
+GLOBAL_ENTRY(ia64_load_scratch_fpregs)
+	alloc r3=ar.pfs,1,0,0,0
+	add r2=16,in0
+	;;
+	ldf.fill  f10 = [in0],32
+	ldf.fill  f11 = [r2],32
+	;;
+	ldf.fill  f12 = [in0],32
+	ldf.fill  f13 = [r2],32
+	;;
+	ldf.fill  f14 = [in0],32
+	ldf.fill  f15 = [r2],32
+	br.ret.sptk.many rp
+END(ia64_load_scratch_fpregs)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/pci.c linux-2.4.21/arch/ia64/kernel/pci.c
--- linux-2.4.20/arch/ia64/kernel/pci.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/pci.c	2002-12-18 18:58:08.000000000 +0000
@@ -43,6 +43,8 @@
 extern void ia64_mca_check_errors( void );
 #endif
 
+static unsigned int acpi_root_bridges;
+
 struct pci_fixup pcibios_fixups[1];
 
 struct pci_ops *pci_root_ops;
@@ -217,7 +219,7 @@
 	struct pci_controller *controller;
 	u64 base, size, offset;
 
-	printk("PCI: Probing PCI hardware on bus (%02x:%02x)\n", seg, bus);
+	acpi_root_bridges++;
 
 	controller = alloc_pci_controller(seg);
 	if (!controller)
@@ -249,7 +251,7 @@
 void __init
 pcibios_init (void)
 {
-#	define PCI_BUSES_TO_SCAN 255
+#	define PCI_BUSES_TO_SCAN 256
 	int i = 0;
 	struct pci_controller *controller;
 
@@ -261,11 +263,14 @@
 
 	platform_pci_fixup(0);	/* phase 0 fixups (before buses scanned) */
 
-	printk("PCI: Probing PCI hardware\n");
-	controller = alloc_pci_controller(0);
-	if (controller)
-		for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
-			pci_scan_bus(i, pci_root_ops, controller);
+	/* Only probe blindly if ACPI didn't tell us about root bridges */
+	if (!acpi_root_bridges) {
+		printk("PCI: Probing PCI hardware\n");
+		controller = alloc_pci_controller(0);
+		if (controller)
+			for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
+				pci_scan_bus(i, pci_root_ops, controller);
+	}
 
 	platform_pci_fixup(1);	/* phase 1 fixups (after buses scanned) */
 
@@ -294,10 +299,9 @@
 }
 
 /*
- *  Called after each bus is probed, but before its children
- *  are examined.
+ *  Called after each bus is probed, but before its children are examined.
  */
-void __init
+void __devinit
 pcibios_fixup_bus (struct pci_bus *b)
 {
 	struct list_head *ln;
@@ -306,7 +310,7 @@
 		pcibios_fixup_device_resources(pci_dev_b(ln), b);
 }
 
-void __init
+void __devinit
 pcibios_update_resource (struct pci_dev *dev, struct resource *root,
 			 struct resource *res, int resource)
 {
@@ -322,7 +326,7 @@
 	/* ??? FIXME -- record old value for shutdown.  */
 }
 
-void __init
+void __devinit
 pcibios_update_irq (struct pci_dev *dev, int irq)
 {
 	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
@@ -330,7 +334,7 @@
 	/* ??? FIXME -- record old value for shutdown.  */
 }
 
-void __init
+void __devinit
 pcibios_fixup_pbus_ranges (struct pci_bus * bus, struct pbus_set_ranges_data * ranges)
 {
 	ranges->io_start -= bus->resource[0]->start;
@@ -339,8 +343,8 @@
 	ranges->mem_end -= bus->resource[1]->start;
 }
 
-int
-pcibios_enable_device (struct pci_dev *dev)
+static inline int
+pcibios_enable_resources (struct pci_dev *dev, int mask)
 {
 	u16 cmd, old_cmd;
 	int idx;
@@ -349,11 +353,13 @@
 	if (!dev)
 		return -EINVAL;
 
- 	platform_pci_enable_device(dev);
-
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
 	for (idx=0; idx<6; idx++) {
+		/* Only set up the desired resources.  */
+		if (!(mask & (1 << idx)))
+			continue;
+
 		r = &dev->resource[idx];
 		if (!r->start && r->end) {
 			printk(KERN_ERR
@@ -372,6 +378,19 @@
 		printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
 		pci_write_config_word(dev, PCI_COMMAND, cmd);
 	}
+	return 0;
+}
+
+int
+pcibios_enable_device (struct pci_dev *dev, int mask)
+{
+	int ret;
+
+	ret = pcibios_enable_resources(dev, mask);
+	if (ret < 0)
+		return ret;
+
+ 	platform_pci_enable_device(dev);
 
 	printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", dev->irq, dev->slot_name);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/perfmon.c linux-2.4.21/arch/ia64/kernel/perfmon.c
--- linux-2.4.20/arch/ia64/kernel/perfmon.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/perfmon.c	2002-12-18 18:58:07.000000000 +0000
@@ -28,7 +28,6 @@
 #include <asm/bitops.h>
 #include <asm/errno.h>
 #include <asm/page.h>
-#include <asm/pal.h>
 #include <asm/perfmon.h>
 #include <asm/processor.h>
 #include <asm/signal.h>
@@ -56,27 +55,53 @@
 /*
  * Reset register flags
  */
-#define PFM_RELOAD_LONG_RESET	1
-#define PFM_RELOAD_SHORT_RESET	2
+#define PFM_PMD_LONG_RESET	1
+#define PFM_PMD_SHORT_RESET	2
 
 /*
  * Misc macros and definitions
  */
 #define PMU_FIRST_COUNTER	4
+#define PMU_MAX_PMCS		256
+#define PMU_MAX_PMDS		256
 
-#define PFM_IS_DISABLED() pmu_conf.pfm_is_disabled
+/*
+ * type of a PMU register (bitmask).
+ * bitmask structure:
+ * 	bit0   : register implemented
+ * 	bit1   : end marker 
+ * 	bit2-3 : reserved
+ * 	bit4-7 : register type
+ * 	bit8-31: reserved
+ */
+#define PFM_REG_IMPL		0x1 /* register implemented */
+#define PFM_REG_END		0x2 /* end marker */
+#define PFM_REG_MONITOR		(0x1<<4|PFM_REG_IMPL) /* a PMC with a pmc.pm field only */
+#define PFM_REG_COUNTING	(0x2<<4|PFM_REG_IMPL) /* a PMC with a pmc.pm AND pmc.oi, a PMD used as a counter */
+#define PFM_REG_CONTROL		(0x3<<4|PFM_REG_IMPL) /* PMU control register */
+#define	PFM_REG_CONFIG		(0x4<<4|PFM_REG_IMPL) /* refine configuration */
+#define PFM_REG_BUFFER	 	(0x5<<4|PFM_REG_IMPL) /* PMD used as buffer */
+
+#define PMC_IS_LAST(i)	(pmu_conf.pmc_desc[i].type & PFM_REG_END)
+#define PMD_IS_LAST(i)	(pmu_conf.pmd_desc[i].type & PFM_REG_END)
+
+#define PFM_IS_DISABLED() pmu_conf.disabled
 
 #define PMC_OVFL_NOTIFY(ctx, i)	((ctx)->ctx_soft_pmds[i].flags &  PFM_REGFL_OVFL_NOTIFY)
 #define PFM_FL_INHERIT_MASK	(PFM_FL_INHERIT_NONE|PFM_FL_INHERIT_ONCE|PFM_FL_INHERIT_ALL)
 
 /* i assume unsigned */
-#define PMC_IS_IMPL(i)	  (i<pmu_conf.num_pmcs && pmu_conf.impl_regs[i>>6] & (1UL<< (i) %64))
-#define PMD_IS_IMPL(i)	  (i<pmu_conf.num_pmds &&  pmu_conf.impl_regs[4+(i>>6)] & (1UL<<(i) % 64))
+#define PMC_IS_IMPL(i)	  (i< PMU_MAX_PMCS && (pmu_conf.pmc_desc[i].type & PFM_REG_IMPL))
+#define PMD_IS_IMPL(i)	  (i< PMU_MAX_PMDS && (pmu_conf.pmd_desc[i].type & PFM_REG_IMPL))
 
 /* XXX: these three assume that register i is implemented */
 #define PMD_IS_COUNTING(i) (pmu_conf.pmd_desc[i].type == PFM_REG_COUNTING)
 #define PMC_IS_COUNTING(i) (pmu_conf.pmc_desc[i].type == PFM_REG_COUNTING)
-#define PMC_IS_MONITOR(c)  (pmu_conf.pmc_desc[i].type == PFM_REG_MONITOR)
+#define PMC_IS_MONITOR(i)  (pmu_conf.pmc_desc[i].type == PFM_REG_MONITOR)
+#define PMC_DFL_VAL(i)     pmu_conf.pmc_desc[i].default_value
+#define PMC_RSVD_MASK(i)   pmu_conf.pmc_desc[i].reserved_mask
+#define PMD_PMD_DEP(i)	   pmu_conf.pmd_desc[i].dep_pmd[0]
+#define PMC_PMD_DEP(i)	   pmu_conf.pmc_desc[i].dep_pmd[0]
 
 /* k assume unsigned */
 #define IBR_IS_IMPL(k)	  (k<pmu_conf.num_ibrs)
@@ -176,28 +201,17 @@
 #define UNLOCK_PSB(p)	spin_unlock(&(p)->psb_lock)
 
 /*
- * The possible type of a PMU register
- */
-typedef enum { 
-	PFM_REG_NOTIMPL, /* not implemented */
-	PFM_REG_NONE, 	 /* end marker */
-	PFM_REG_MONITOR, /* a PMC with a pmc.pm field only */
-	PFM_REG_COUNTING,/* a PMC with a pmc.pm AND pmc.oi, a PMD used as a counter */
-	PFM_REG_CONTROL, /* PMU control register */
-	PFM_REG_CONFIG,  /* refine configuration */
-	PFM_REG_BUFFER	 /* PMD used as buffer */
-} pfm_pmu_reg_type_t;
-
-/*
  * 64-bit software counter structure
  */
 typedef struct {
 	u64 val;	/* virtual 64bit counter value */
-	u64 ival;	/* initial value from user */
+	u64 lval;	/* last value */
 	u64 long_reset;	/* reset value on sampling overflow */
 	u64 short_reset;/* reset value on overflow */
 	u64 reset_pmds[4]; /* which other pmds to reset when this counter overflows */
-	int flags;	/* notify/do not notify */
+	u64 seed;	/* seed for random-number generator */
+	u64 mask;	/* mask for random-number generator */
+	unsigned int flags; /* notify/do not notify */
 } pfm_counter_t;
 
 /*
@@ -268,10 +282,10 @@
 typedef struct {
 	spinlock_t		pfs_lock;		   /* lock the structure */
 
-	unsigned long		pfs_task_sessions;	   /* number of per task sessions */
-	unsigned long		pfs_sys_sessions;	   /* number of per system wide sessions */
-	unsigned long   	pfs_sys_use_dbregs;	   /* incremented when a system wide session uses debug regs */
-	unsigned long   	pfs_ptrace_use_dbregs;	   /* incremented when a process uses debug regs */
+	unsigned int 		pfs_task_sessions;	   /* number of per task sessions */
+	unsigned int		pfs_sys_sessions;	   /* number of per system wide sessions */
+	unsigned int		pfs_sys_use_dbregs;	   /* incremented when a system wide session uses debug regs */
+	unsigned int		pfs_ptrace_use_dbregs;	   /* incremented when a process uses debug regs */
 	struct task_struct	*pfs_sys_session[NR_CPUS]; /* point to task owning a system-wide session */
 } pfm_session_t;
 
@@ -281,13 +295,16 @@
  * dep_pmc[]: a bitmask of dependent PMC registers
  */
 typedef struct {
-	pfm_pmu_reg_type_t	type;
+	unsigned int		type;
 	int			pm_pos;
+	unsigned long		default_value;	/* power-on default value */
+	unsigned long		reserved_mask;	/* bitmask of reserved bits */
 	int			(*read_check)(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 	int			(*write_check)(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 	unsigned long		dep_pmd[4];
 	unsigned long		dep_pmc[4];
 } pfm_reg_desc_t;
+
 /* assume cnum is a valid monitor */
 #define PMC_PM(cnum, val)	(((val) >> (pmu_conf.pmc_desc[cnum].pm_pos)) & 0x1)
 #define PMC_WR_FUNC(cnum)	(pmu_conf.pmc_desc[cnum].write_check)
@@ -296,23 +313,22 @@
 
 /*
  * This structure is initialized at boot time and contains
- * a description of the PMU main characteristic as indicated
- * by PAL along with a list of inter-registers dependencies and configurations.
+ * a description of the PMU main characteristics.
  */
 typedef struct {
-	unsigned long pfm_is_disabled;	/* indicates if perfmon is working properly */
-	unsigned long perf_ovfl_val;	/* overflow value for generic counters   */
-	unsigned long max_counters;	/* upper limit on counter pair (PMC/PMD) */
-	unsigned long num_pmcs ;	/* highest PMC implemented (may have holes) */
-	unsigned long num_pmds;		/* highest PMD implemented (may have holes) */
-	unsigned long impl_regs[16];	/* buffer used to hold implememted PMC/PMD mask */
-	unsigned long num_ibrs;		/* number of instruction debug registers */
-	unsigned long num_dbrs;		/* number of data debug registers */
-	pfm_reg_desc_t *pmc_desc;	/* detailed PMC register descriptions */
-	pfm_reg_desc_t *pmd_desc;	/* detailed PMD register descriptions */
+	unsigned int  disabled;		/* indicates if perfmon is working properly */
+	unsigned long ovfl_val;		/* overflow value for generic counters   */
+	unsigned long impl_pmcs[4];	/* bitmask of implemented PMCS */
+	unsigned long impl_pmds[4];	/* bitmask of implemented PMDS */
+	unsigned int  num_pmcs;		/* number of implemented PMCS */
+	unsigned int  num_pmds;		/* number of implemented PMDS */
+	unsigned int  num_ibrs;		/* number of implemented IBRS */
+	unsigned int  num_dbrs;		/* number of implemented DBRS */
+	unsigned int  num_counters;	/* number of PMD/PMC counters */
+	pfm_reg_desc_t *pmc_desc;	/* detailed PMC register dependencies descriptions */
+	pfm_reg_desc_t *pmd_desc;	/* detailed PMD register dependencies descriptions */
 } pmu_config_t;
 
-
 /*
  * structure used to pass argument to/from remote CPU 
  * using IPI to check and possibly save the PMU context on SMP systems.
@@ -336,7 +352,7 @@
 
 #define PFM_CMD_PID		0x1	/* command requires pid argument */
 #define PFM_CMD_ARG_READ	0x2	/* command must read argument(s) */
-#define PFM_CMD_ARG_WRITE	0x4	/* command must write argument(s) */
+#define PFM_CMD_ARG_RW		0x4	/* command must read/write argument(s) */
 #define PFM_CMD_CTX		0x8	/* command needs a perfmon context */
 #define PFM_CMD_NOCHK		0x10	/* command does not need to check task's state */
 
@@ -347,7 +363,7 @@
 
 #define PFM_CMD_USE_PID(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_PID) != 0)
 #define PFM_CMD_READ_ARG(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_READ) != 0)
-#define PFM_CMD_WRITE_ARG(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_WRITE) != 0)
+#define PFM_CMD_RW_ARG(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_RW) != 0)
 #define PFM_CMD_USE_CTX(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_CTX) != 0)
 #define PFM_CMD_CHK(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_NOCHK) == 0)
 
@@ -366,15 +382,16 @@
 	unsigned long pfm_ovfl_intr_count; /* keep track of ovfl interrupts */
 	unsigned long pfm_recorded_samples_count;
 	unsigned long pfm_full_smpl_buffer_count; /* how many times the sampling buffer was full */
+	char pad[SMP_CACHE_BYTES] ____cacheline_aligned;
 } pfm_stats_t;
 
 /*
  * perfmon internal variables
  */
-static pmu_config_t	pmu_conf; 	/* PMU configuration */
 static pfm_session_t	pfm_sessions;	/* global sessions information */
 static struct proc_dir_entry *perfmon_dir; /* for debug only */
-static pfm_stats_t	pfm_stats;
+static pfm_stats_t	pfm_stats[NR_CPUS];
+static pfm_intr_handler_desc_t	*pfm_alternate_intr_handler;
 
 /* sysctl() controls */
 static pfm_sysctl_t pfm_sysctl;
@@ -395,8 +412,6 @@
 };
 static struct ctl_table_header *pfm_sysctl_header;
 
-static unsigned long reset_pmcs[IA64_NUM_PMC_REGS];	/* contains PAL reset values for PMCS */
-
 static void pfm_vm_close(struct vm_area_struct * area);
 
 static struct vm_operations_struct pfm_vm_ops={
@@ -408,14 +423,15 @@
  */
 static struct {
 	struct task_struct *owner;
-} ____cacheline_aligned pmu_owners[NR_CPUS];
+	char pad[SMP_CACHE_BYTES] ____cacheline_aligned;
+} pmu_owners[NR_CPUS];
 
 
 
 /*
  * forward declarations
  */
-static void ia64_reset_pmu(struct task_struct *);
+static void pfm_reset_pmu(struct task_struct *);
 #ifdef CONFIG_SMP
 static void pfm_fetch_regs(int cpu, struct task_struct *task, pfm_context_t *ctx);
 #endif
@@ -432,40 +448,21 @@
 static inline unsigned long
 pfm_read_soft_counter(pfm_context_t *ctx, int i)
 {
-	return ctx->ctx_soft_pmds[i].val + (ia64_get_pmd(i) & pmu_conf.perf_ovfl_val);
+	return ctx->ctx_soft_pmds[i].val + (ia64_get_pmd(i) & pmu_conf.ovfl_val);
 }
 
 static inline void
 pfm_write_soft_counter(pfm_context_t *ctx, int i, unsigned long val)
 {
-	ctx->ctx_soft_pmds[i].val = val  & ~pmu_conf.perf_ovfl_val;
+	ctx->ctx_soft_pmds[i].val = val  & ~pmu_conf.ovfl_val;
 	/*
 	 * writing to unimplemented part is ignore, so we do not need to
 	 * mask off top part
 	 */
-	ia64_set_pmd(i, val & pmu_conf.perf_ovfl_val);
+	ia64_set_pmd(i, val & pmu_conf.ovfl_val);
 }
 
 /*
- * finds the number of PM(C|D) registers given
- * the bitvector returned by PAL
- */
-static unsigned long __init
-find_num_pm_regs(long *buffer)
-{
-	int i=3; /* 4 words/per bitvector */
-
-	/* start from the most significant word */
-	while (i>=0 && buffer[i] == 0 ) i--;
-	if (i< 0) {
-		printk(KERN_ERR "perfmon: No bit set in pm_buffer\n");
-		return 0;
-	}
-	return 1+ ia64_fls(buffer[i]) + 64 * i;
-}
-
-
-/*
  * Generates a unique (per CPU) timestamp
  */
 static inline unsigned long
@@ -767,15 +764,14 @@
 	psb = kmalloc(sizeof(*psb), GFP_KERNEL);
 	if (psb == NULL) {
 		DBprintk(("Can't allocate sampling buffer descriptor\n"));
-		pfm_rvfree(smpl_buf, size);
-		return -ENOMEM;
+		goto error_kmalloc;
 	}
 
 	/* allocate vma */
 	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (!vma) {
 		DBprintk(("Cannot allocate vma\n"));
-		goto error;
+		goto error_kmem;
 	}
 	/*
 	 * partially initialize the vma for the sampling buffer
@@ -875,11 +871,126 @@
 	return 0;
 
 error:
-	pfm_rvfree(smpl_buf, size);
+	kmem_cache_free(vm_area_cachep, vma);
+error_kmem:
 	kfree(psb);
+error_kmalloc:
+	pfm_rvfree(smpl_buf, size);
 	return -ENOMEM;
 }
 
+static int
+pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned long cpu_mask)
+{
+	unsigned long m, undo_mask;
+	unsigned int n, i;
+
+	/*
+	 * validy checks on cpu_mask have been done upstream
+	 */
+	LOCK_PFS();
+
+	if (is_syswide) {
+		/* 
+		 * cannot mix system wide and per-task sessions
+		 */
+		if (pfm_sessions.pfs_task_sessions > 0UL) {
+			DBprintk(("system wide not possible, %u conflicting task_sessions\n", 
+			  	pfm_sessions.pfs_task_sessions));
+			goto abort;
+		}
+
+		m = cpu_mask; undo_mask = 0UL; n = 0;
+		for(i=0; m; i++, m>>=1) {
+
+			if ((m & 0x1) == 0UL) continue;
+
+			if (pfm_sessions.pfs_sys_session[i]) goto undo;
+
+			DBprintk(("reserving CPU%d currently on CPU%d\n", i, smp_processor_id()));
+
+			pfm_sessions.pfs_sys_session[i] = task;
+			undo_mask |= 1UL << i;
+			n++;
+		}
+		pfm_sessions.pfs_sys_sessions += n;
+	} else {
+		if (pfm_sessions.pfs_sys_sessions) goto abort;
+		pfm_sessions.pfs_task_sessions++;
+	}
+	UNLOCK_PFS();
+	return 0;
+undo:
+	DBprintk(("system wide not possible, conflicting session [%d] on CPU%d\n",
+  		pfm_sessions.pfs_sys_session[i]->pid, i));
+
+	for(i=0; undo_mask; i++, undo_mask >>=1) {
+		pfm_sessions.pfs_sys_session[i] = NULL;
+	}
+abort:
+	UNLOCK_PFS();
+
+	return -EBUSY;
+
+}
+
+static int
+pfm_unreserve_session(struct task_struct *task, int is_syswide, unsigned long cpu_mask)
+{
+	pfm_context_t *ctx;
+	unsigned long m;
+	unsigned int n, i;
+
+	ctx = task ? task->thread.pfm_context : NULL;
+
+	/*
+	 * validy checks on cpu_mask have been done upstream
+	 */
+	LOCK_PFS();
+
+	DBprintk(("[%d] sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu_mask=0x%lx\n",
+		task->pid,
+		pfm_sessions.pfs_sys_sessions,
+		pfm_sessions.pfs_task_sessions,
+		pfm_sessions.pfs_sys_use_dbregs,
+		is_syswide,
+		cpu_mask));
+		
+
+	if (is_syswide) {
+		m = cpu_mask; n = 0;
+		for(i=0; m; i++, m>>=1) {
+			if ((m & 0x1) == 0UL) continue;
+			pfm_sessions.pfs_sys_session[i] = NULL;
+			n++;
+		}
+		/* 
+		 * would not work with perfmon+more than one bit in cpu_mask
+		 */
+		if (ctx && ctx->ctx_fl_using_dbreg) {
+			if (pfm_sessions.pfs_sys_use_dbregs == 0) {
+				printk("perfmon: invalid release for [%d] sys_use_dbregs=0\n", task->pid);
+			} else {
+				pfm_sessions.pfs_sys_use_dbregs--;
+			}
+		}
+		pfm_sessions.pfs_sys_sessions -= n;
+
+		DBprintk(("CPU%d sys_sessions=%u\n", 
+			smp_processor_id(), pfm_sessions.pfs_sys_sessions));
+	} else {
+		pfm_sessions.pfs_task_sessions--;
+		DBprintk(("[%d] task_sessions=%u\n", 
+			task->pid, pfm_sessions.pfs_task_sessions));
+	}
+
+	UNLOCK_PFS();
+
+	return 0;
+}
+
+
+
 /*
  * XXX: do something better here
  */
@@ -895,6 +1006,7 @@
 static int
 pfx_is_sane(struct task_struct *task, pfarg_context_t *pfx)
 {
+	unsigned long smpl_pmds = pfx->ctx_smpl_regs[0];
 	int ctx_flags;
 	int cpu;
 
@@ -961,6 +1073,11 @@
 		}
 #endif
 	}
+	/* verify validity of smpl_regs */
+	if ((smpl_pmds & pmu_conf.impl_pmds[0]) != smpl_pmds) {
+		DBprintk(("invalid smpl_regs 0x%lx\n", smpl_pmds));
+		return -EINVAL;
+	}
 	/* probably more to add here */
 
 	return 0;
@@ -984,7 +1101,7 @@
 	 */
 	if (task != current) return -EINVAL;
 
-	if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+	if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
 	ret = pfx_is_sane(task, &tmp);
 	if (ret < 0) return ret;
@@ -993,38 +1110,8 @@
 
 	ret =  -EBUSY;
 
-	LOCK_PFS();
-
-	if (ctx_flags & PFM_FL_SYSTEM_WIDE) {
-
-		/* at this point, we know there is at least one bit set */
-		cpu = ffz(~tmp.ctx_cpu_mask);
-
-		DBprintk(("requesting CPU%d currently on CPU%d\n",cpu, smp_processor_id()));
-
-		if (pfm_sessions.pfs_task_sessions > 0) {
-			DBprintk(("system wide not possible, task_sessions=%ld\n", pfm_sessions.pfs_task_sessions));
-			goto abort;
-		}
-
-		if (pfm_sessions.pfs_sys_session[cpu]) {
-			DBprintk(("system wide not possible, conflicting session [%d] on CPU%d\n",pfm_sessions.pfs_sys_session[cpu]->pid, cpu));
-			goto abort;
-		}
-		pfm_sessions.pfs_sys_session[cpu] = task;
-		/*
-		 * count the number of system wide sessions
-		 */
-		pfm_sessions.pfs_sys_sessions++;
-
-	} else if (pfm_sessions.pfs_sys_sessions == 0) {
-		pfm_sessions.pfs_task_sessions++;
-	} else {
-		/* no per-process monitoring while there is a system wide session */
-		goto abort;
-	}
-
-	UNLOCK_PFS();
+	ret = pfm_reserve_session(task, ctx_flags & PFM_FL_SYSTEM_WIDE, tmp.ctx_cpu_mask);
+	if (ret) goto abort;
 
 	ret = -ENOMEM;
 
@@ -1040,8 +1127,8 @@
 
 	if (notify_pid == current->pid) {
 
-		ctx->ctx_notify_task = task = current;
-		current->thread.pfm_context = ctx;
+		ctx->ctx_notify_task = current;
+		task->thread.pfm_context = ctx;
 
 	} else if (notify_pid!=0) {
 		struct task_struct *notify_task;
@@ -1057,7 +1144,10 @@
 			/*
 			 * check if we can send this task a signal
 			 */
-			if (pfm_bad_permissions(notify_task)) goto buffer_error;
+			if (pfm_bad_permissions(notify_task)) {
+				read_unlock(&tasklist_lock);
+				goto buffer_error;
+			}
 
 			/* 
 		 	 * make visible
@@ -1067,7 +1157,7 @@
 		 	 * okay because child will do the scan for nothing which
 		 	 * won't hurt.
 		 	 */
-			current->thread.pfm_context = ctx;
+			task->thread.pfm_context = ctx;
 
 			/*
 			 * will cause task to check on exit for monitored
@@ -1124,7 +1214,7 @@
 
 	sema_init(&ctx->ctx_restart_sem, 0); /* init this semaphore to locked */
 
-	if (copy_to_user(req, &tmp, sizeof(tmp))) {
+	if (__copy_to_user(req, &tmp, sizeof(tmp))) {
 		ret = -EFAULT;
 		goto buffer_error;
 	}
@@ -1157,32 +1247,40 @@
 buffer_error:
 	pfm_context_free(ctx);
 error:
-	/*
-	 * undo session reservation
-	 */
-	LOCK_PFS();
-
-	if (ctx_flags & PFM_FL_SYSTEM_WIDE) {
-		pfm_sessions.pfs_sys_session[cpu] = NULL;
-		pfm_sessions.pfs_sys_sessions--;
-	} else {
-		pfm_sessions.pfs_task_sessions--;
-	}
+	pfm_unreserve_session(task, ctx_flags & PFM_FL_SYSTEM_WIDE , tmp.ctx_cpu_mask);
 abort:
-	UNLOCK_PFS();
+	/* make sure we don't leave anything behind */
+	task->thread.pfm_context = NULL;
 
 	return ret;
 }
 
+static inline unsigned long
+pfm_new_counter_value (pfm_counter_t *reg, int is_long_reset)
+{
+	unsigned long val = is_long_reset ? reg->long_reset : reg->short_reset;
+	unsigned long new_seed, old_seed = reg->seed, mask = reg->mask;
+	extern unsigned long carta_random32 (unsigned long seed);
+
+	if (reg->flags & PFM_REGFL_RANDOM) {
+		new_seed = carta_random32(old_seed);
+		val -= (old_seed & mask);	/* counter values are negative numbers! */
+		if ((mask >> 32) != 0)
+			/* construct a full 64-bit random value: */
+			new_seed |= carta_random32(old_seed >> 32) << 32;
+		reg->seed = new_seed;
+	}
+	reg->lval = val;
+	return val;
+}
+
 static void
 pfm_reset_regs(pfm_context_t *ctx, unsigned long *ovfl_regs, int flag)
 {
 	unsigned long mask = ovfl_regs[0];
 	unsigned long reset_others = 0UL;
 	unsigned long val;
-	int i;
-
-	DBprintk(("masks=0x%lx\n", mask));
+	int i, is_long_reset = (flag == PFM_PMD_LONG_RESET);
 
 	/*
 	 * now restore reset value on sampling overflowed counters
@@ -1190,15 +1288,11 @@
 	mask >>= PMU_FIRST_COUNTER;
 	for(i = PMU_FIRST_COUNTER; mask; i++, mask >>= 1) {
 		if (mask & 0x1) {
-			val  = flag == PFM_RELOAD_LONG_RESET ? 
-					ctx->ctx_soft_pmds[i].long_reset:
-					ctx->ctx_soft_pmds[i].short_reset;
-
+			val = pfm_new_counter_value(ctx->ctx_soft_pmds + i, is_long_reset);
 			reset_others |= ctx->ctx_soft_pmds[i].reset_pmds[0];
 
-			DBprintk(("[%d] %s reset soft_pmd[%d]=%lx\n", 
-			  	current->pid, 
-				flag == PFM_RELOAD_LONG_RESET ? "long" : "short", i, val));
+			DBprintk_ovfl(("[%d] %s reset soft_pmd[%d]=%lx\n", current->pid,
+				  is_long_reset ? "long" : "short", i, val));
 
 			/* upper part is ignored on rval */
 			pfm_write_soft_counter(ctx, i, val);
@@ -1212,23 +1306,17 @@
 
 		if ((reset_others & 0x1) == 0) continue;
 
-		val  = flag == PFM_RELOAD_LONG_RESET ? 
-					ctx->ctx_soft_pmds[i].long_reset:
-					ctx->ctx_soft_pmds[i].short_reset;
+		val = pfm_new_counter_value(ctx->ctx_soft_pmds + i, is_long_reset);
 
 		if (PMD_IS_COUNTING(i)) {
 			pfm_write_soft_counter(ctx, i, val);
 		} else {
 			ia64_set_pmd(i, val);
 		}
-
-		DBprintk(("[%d] %s reset_others pmd[%d]=%lx\n", 
-			  	current->pid, 
-				flag == PFM_RELOAD_LONG_RESET ? "long" : "short", i, val));
+		DBprintk_ovfl(("[%d] %s reset_others pmd[%d]=%lx\n", current->pid,
+			  is_long_reset ? "long" : "short", i, val));
 	}
 	ia64_srlz_d();
-	/* just in case ! */
-	ctx->ctx_ovfl_regs[0] = 0UL;
 }
 
 static int
@@ -1236,12 +1324,10 @@
 {
 	struct thread_struct *th = &task->thread;
 	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
-	unsigned int cnum;
+	unsigned long value, reset_pmds;
+	unsigned int cnum, reg_flags, flags;
 	int i;
-	int ret = 0, reg_retval = 0;
-
-	/* we don't quite support this right now */
-	if (task != current) return -EINVAL;
+	int ret = -EINVAL;
 
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
@@ -1249,10 +1335,13 @@
 
 	for (i = 0; i < count; i++, req++) {
 
+		if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
-		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
-
-		cnum = tmp.reg_num;
+		cnum       = tmp.reg_num;
+		reg_flags  = tmp.reg_flags;
+		value      = tmp.reg_value;
+		reset_pmds = tmp.reg_reset_pmds[0];
+		flags      = 0;
 
 		/* 
 		 * we reject all non implemented PMC as well
@@ -1261,8 +1350,7 @@
 		 */
 		if (!PMC_IS_IMPL(cnum) || cnum < 4) {
 			DBprintk(("pmc[%u] is unimplemented or invalid\n", cnum));
-			ret = -EINVAL;
-			goto abort_mission;
+			goto error;
 		}
 		/*
 		 * A PMC used to configure monitors must be:
@@ -1271,73 +1359,83 @@
 		 * any other configuration is rejected.
 		 */
 		if (PMC_IS_MONITOR(cnum) || PMC_IS_COUNTING(cnum)) {
-			DBprintk(("pmc[%u].pm=%ld\n", cnum, PMC_PM(cnum, tmp.reg_value))); 
+			DBprintk(("pmc[%u].pm=%ld\n", cnum, PMC_PM(cnum, value))); 
 
-			if (ctx->ctx_fl_system ^ PMC_PM(cnum, tmp.reg_value)) {
-				DBprintk(("pmc_pm=%ld fl_system=%d\n", PMC_PM(cnum, tmp.reg_value), ctx->ctx_fl_system));
-				ret = -EINVAL;
-				goto abort_mission;
+			if (ctx->ctx_fl_system ^ PMC_PM(cnum, value)) {
+				DBprintk(("pmc_pm=%ld fl_system=%d\n", PMC_PM(cnum, value), ctx->ctx_fl_system));
+				goto error;
 			}
 		}
 
 		if (PMC_IS_COUNTING(cnum)) {
-			pfm_monitor_t *p = (pfm_monitor_t *)&tmp.reg_value;
+			pfm_monitor_t *p = (pfm_monitor_t *)&value;
 			/*
 		 	 * enforce generation of overflow interrupt. Necessary on all
 		 	 * CPUs.
 		 	 */
 			p->pmc_oi = 1;
 
-			if (tmp.reg_flags & PFM_REGFL_OVFL_NOTIFY) {
+			if (reg_flags & PFM_REGFL_OVFL_NOTIFY) {
 				/*
-				 * must have a target for the signal
-				 */
+			 	 * must have a target for the signal
+			 	 */
 				if (ctx->ctx_notify_task == NULL) {
-					DBprintk(("no notify_task && PFM_REGFL_OVFL_NOTIFY\n"));
-					ret = -EINVAL;
-					goto abort_mission;
+					DBprintk(("cannot set ovfl_notify: no notify_task\n"));
+					goto error;
 				}
+				flags |= PFM_REGFL_OVFL_NOTIFY;
+			}
+
+			if (reg_flags & PFM_REGFL_RANDOM) flags |= PFM_REGFL_RANDOM;
 
-				ctx->ctx_soft_pmds[cnum].flags |= PFM_REGFL_OVFL_NOTIFY;
+			/* verify validity of reset_pmds */
+			if ((reset_pmds & pmu_conf.impl_pmds[0]) != reset_pmds) {
+				DBprintk(("invalid reset_pmds 0x%lx for pmc%u\n", reset_pmds, cnum));
+				goto error;
 			}
-			/*
-			 * copy reset vector
-			 */
-			ctx->ctx_soft_pmds[cnum].reset_pmds[0] = tmp.reg_reset_pmds[0];
-			ctx->ctx_soft_pmds[cnum].reset_pmds[1] = tmp.reg_reset_pmds[1];
-			ctx->ctx_soft_pmds[cnum].reset_pmds[2] = tmp.reg_reset_pmds[2];
-			ctx->ctx_soft_pmds[cnum].reset_pmds[3] = tmp.reg_reset_pmds[3];
+		} else if (reg_flags & (PFM_REGFL_OVFL_NOTIFY|PFM_REGFL_RANDOM)) {
+				DBprintk(("cannot set ovfl_notify or random on pmc%u\n", cnum));
+				goto error;
 		}
+
 		/*
 		 * execute write checker, if any
 		 */
-		if (PMC_WR_FUNC(cnum)) ret = PMC_WR_FUNC(cnum)(task, cnum, &tmp.reg_value, regs);
-abort_mission:
-		if (ret == -EINVAL) reg_retval = PFM_REG_RETFL_EINVAL;
+		if (PMC_WR_FUNC(cnum)) {
+			ret = PMC_WR_FUNC(cnum)(task, cnum, &value, regs);
+			if (ret) goto error;
+			ret = -EINVAL;
+		}
 
-		PFM_REG_RETFLAG_SET(tmp.reg_flags, reg_retval);
+		/*
+		 * no error on this register
+		 */
+		PFM_REG_RETFLAG_SET(tmp.reg_flags, 0);
 
 		/*
 		 * update register return value, abort all if problem during copy.
+		 * we only modify the reg_flags field. no check mode is fine because
+		 * access has been verified upfront in sys_perfmonctl().
+		 *
+		 * If this fails, then the software state is not modified
 		 */
-		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
+		if (__put_user(tmp.reg_flags, &req->reg_flags)) return -EFAULT;
 
 		/*
-		 * if there was something wrong on this register, don't touch
-		 * the hardware at all and abort write request for others.
-		 *
-		 * On error, the user mut sequentially scan the table and the first
-		 * entry which has a return flag set is the one that caused the error.
+		 * Now we commit the changes to the software state
 		 */
-		if (ret != 0) {
-			DBprintk(("[%d] pmc[%u]=0x%lx error %d\n",
-				  task->pid, cnum, tmp.reg_value, reg_retval));
-			break;
-		}
 
 		/* 
-		 * We can proceed with this register!
+		 * full flag update each time a register is programmed
 		 */
+		ctx->ctx_soft_pmds[cnum].flags = flags;
+
+		if (PMC_IS_COUNTING(cnum)) {
+			ctx->ctx_soft_pmds[cnum].reset_pmds[0] = reset_pmds;
+
+			/* mark all PMDS to be accessed as used */
+			CTX_USED_PMD(ctx, reset_pmds);
+		}
 
 		/*
 		 * Needed in case the user does not initialize the equivalent
@@ -1349,16 +1447,26 @@
 		/* 
 		 * keep copy the pmc, used for register reload
 		 */
-		th->pmc[cnum] = tmp.reg_value;
+		th->pmc[cnum] = value;
 
-		ia64_set_pmc(cnum, tmp.reg_value);
+		ia64_set_pmc(cnum, value);
 
 		DBprintk(("[%d] pmc[%u]=0x%lx flags=0x%x used_pmds=0x%lx\n", 
-			  task->pid, cnum, tmp.reg_value, 
+			  task->pid, cnum, value, 
 			  ctx->ctx_soft_pmds[cnum].flags, 
 			  ctx->ctx_used_pmds[0]));
 
 	}
+
+	return 0;
+
+error:
+	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);
+
+	if (__put_user(tmp.reg_flags, &req->reg_flags)) ret = -EFAULT;
+
+	DBprintk(("[%d] pmc[%u]=0x%lx error %d\n", task->pid, cnum, value, ret));
+
 	return ret;
 }
 
@@ -1366,85 +1474,110 @@
 pfm_write_pmds(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
 {
 	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
+	unsigned long value, hw_value;
 	unsigned int cnum;
 	int i;
-	int ret = 0, reg_retval = 0;
-
-	/* we don't quite support this right now */
-	if (task != current) return -EINVAL;
+	int ret = 0;
 
 	/* 
 	 * Cannot do anything before PMU is enabled 
 	 */
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
-
 	/* XXX: ctx locking may be required here */
 
+	ret = -EINVAL;
+
 	for (i = 0; i < count; i++, req++) {
 
-		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+		if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+
+		cnum  = tmp.reg_num;
+		value = tmp.reg_value;
 
-		cnum = tmp.reg_num;
 		if (!PMD_IS_IMPL(cnum)) {
-			ret = -EINVAL;
+			DBprintk(("pmd[%u] is unimplemented or invalid\n", cnum));
 			goto abort_mission;
 		}
 
-		/* update virtualized (64bits) counter */
-		if (PMD_IS_COUNTING(cnum)) {
-			ctx->ctx_soft_pmds[cnum].ival = tmp.reg_value;
-			ctx->ctx_soft_pmds[cnum].val  = tmp.reg_value & ~pmu_conf.perf_ovfl_val;
-			ctx->ctx_soft_pmds[cnum].long_reset = tmp.reg_long_reset;
-			ctx->ctx_soft_pmds[cnum].short_reset = tmp.reg_short_reset;
-
-		}
 		/*
 		 * execute write checker, if any
 		 */
-		if (PMD_WR_FUNC(cnum)) ret = PMD_WR_FUNC(cnum)(task, cnum, &tmp.reg_value, regs);
-abort_mission:
-		if (ret == -EINVAL) reg_retval = PFM_REG_RETFL_EINVAL;
-
-		PFM_REG_RETFLAG_SET(tmp.reg_flags, reg_retval);
+		if (PMD_WR_FUNC(cnum)) {
+			unsigned long v = value;
+			ret = PMD_WR_FUNC(cnum)(task, cnum, &v, regs);
+			if (ret) goto abort_mission;
+			value = v;
+			ret = -EINVAL;
+		}
+		hw_value = value;
+		/*
+		 * no error on this register
+		 */
+		PFM_REG_RETFLAG_SET(tmp.reg_flags, 0);
 
-		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
+		if (__put_user(tmp.reg_flags, &req->reg_flags)) return -EFAULT;
 
 		/*
-		 * if there was something wrong on this register, don't touch
-		 * the hardware at all and abort write request for others.
-		 *
-		 * On error, the user mut sequentially scan the table and the first
-		 * entry which has a return flag set is the one that caused the error.
+		 * now commit changes to software state
 		 */
-		if (ret != 0) {
-			DBprintk(("[%d] pmc[%u]=0x%lx error %d\n",
-				  task->pid, cnum, tmp.reg_value, reg_retval));
-			break;
+
+		/* update virtualized (64bits) counter */
+		if (PMD_IS_COUNTING(cnum)) {
+			ctx->ctx_soft_pmds[cnum].lval = value;
+			ctx->ctx_soft_pmds[cnum].val  = value & ~pmu_conf.ovfl_val;
+
+			hw_value = value & pmu_conf.ovfl_val;
+
+			ctx->ctx_soft_pmds[cnum].long_reset  = tmp.reg_long_reset;
+			ctx->ctx_soft_pmds[cnum].short_reset = tmp.reg_short_reset;
+
+			ctx->ctx_soft_pmds[cnum].seed = tmp.reg_random_seed;
+			ctx->ctx_soft_pmds[cnum].mask = tmp.reg_random_mask;
 		}
 
 		/* keep track of what we use */
 		CTX_USED_PMD(ctx, pmu_conf.pmd_desc[(cnum)].dep_pmd[0]);
+
 		/* mark this register as used as well */
 		CTX_USED_PMD(ctx, RDEP(cnum));
 
 		/* writes to unimplemented part is ignored, so this is safe */
-		ia64_set_pmd(cnum, tmp.reg_value & pmu_conf.perf_ovfl_val);
+		ia64_set_pmd(cnum, hw_value);
 
 		/* to go away */
 		ia64_srlz_d();
 
-		DBprintk(("[%d] pmd[%u]: soft_pmd=0x%lx  short_reset=0x%lx "
+		DBprintk(("[%d] pmd[%u]: value=0x%lx hw_value=0x%lx soft_pmd=0x%lx  short_reset=0x%lx "
 			  "long_reset=0x%lx hw_pmd=%lx notify=%c used_pmds=0x%lx reset_pmds=0x%lx\n",
 				task->pid, cnum,
+				value, hw_value,
 				ctx->ctx_soft_pmds[cnum].val,
 				ctx->ctx_soft_pmds[cnum].short_reset,
 				ctx->ctx_soft_pmds[cnum].long_reset,
-				ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val,
+				ia64_get_pmd(cnum) & pmu_conf.ovfl_val,
 				PMC_OVFL_NOTIFY(ctx, cnum) ? 'Y':'N',
 				ctx->ctx_used_pmds[0],
 				ctx->ctx_soft_pmds[cnum].reset_pmds[0]));
 	}
+
+	return 0;
+
+abort_mission:
+	/*
+	 * for now, we have only one possibility for error
+	 */
+	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);
+
+	/*
+	 * we change the return value to EFAULT in case we cannot write register return code.
+	 * The caller first must correct this error, then a resubmission of the request will
+	 * eventually yield the EINVAL.
+	 */
+	if (__put_user(tmp.reg_flags, &req->reg_flags)) ret = -EFAULT;
+
+	DBprintk(("[%d] pmc[%u]=0x%lx ret %d\n", task->pid, cnum, value, ret));
+
 	return ret;
 }
 
@@ -1452,10 +1585,13 @@
 pfm_read_pmds(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
 {
 	struct thread_struct *th = &task->thread;
-	unsigned long val=0;
-	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
-	unsigned int cnum;
+	unsigned long val, lval;
+	pfarg_reg_t *req = (pfarg_reg_t *)arg;
+	unsigned int cnum, reg_flags = 0;
 	int i, ret = 0;
+#if __GNUC__ < 3
+	int foo;
+#endif
 
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
@@ -1471,11 +1607,17 @@
 	DBprintk(("ctx_last_cpu=%d for [%d]\n", atomic_read(&ctx->ctx_last_cpu), task->pid));
 
 	for (i = 0; i < count; i++, req++) {
-		unsigned long ctx_val = ~0UL;
-
-		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
-		cnum = tmp.reg_num;
+#if __GNUC__ < 3
+		foo = __get_user(cnum, &req->reg_num);
+		if (foo) return -EFAULT;
+		foo = __get_user(reg_flags, &req->reg_flags);
+		if (foo) return -EFAULT;
+#else
+		if (__get_user(cnum, &req->reg_num)) return -EFAULT;
+		if (__get_user(reg_flags, &req->reg_flags)) return -EFAULT;
+#endif
+		lval = 0UL;
 
 		if (!PMD_IS_IMPL(cnum)) goto abort_mission;
 		/*
@@ -1523,36 +1665,47 @@
 			/*
 			 * XXX: need to check for overflow
 			 */
+			val &= pmu_conf.ovfl_val;
+			val += ctx->ctx_soft_pmds[cnum].val;
 
-			val &= pmu_conf.perf_ovfl_val;
-			val += ctx_val = ctx->ctx_soft_pmds[cnum].val;
+			lval = ctx->ctx_soft_pmds[cnum].lval;
 		} 
 
-		tmp.reg_value = val;
-
 		/*
 		 * execute read checker, if any
 		 */
 		if (PMD_RD_FUNC(cnum)) {
-			ret = PMD_RD_FUNC(cnum)(task, cnum, &tmp.reg_value, regs);
+			unsigned long v = val;
+			ret = PMD_RD_FUNC(cnum)(task, cnum, &v, regs);
+			val = v;
 		}
 
-		PFM_REG_RETFLAG_SET(tmp.reg_flags, ret);
+		PFM_REG_RETFLAG_SET(reg_flags, ret);
 
 		DBprintk(("read pmd[%u] ret=%d value=0x%lx pmc=0x%lx\n", 
 					cnum, ret, val, ia64_get_pmc(cnum)));
 
-		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
+		/*
+		 * update register return value, abort all if problem during copy.
+		 * we only modify the reg_flags field. no check mode is fine because
+		 * access has been verified upfront in sys_perfmonctl().
+		 */
+		if (__put_user(cnum, &req->reg_num)) return -EFAULT;
+		if (__put_user(val, &req->reg_value)) return -EFAULT;
+		if (__put_user(reg_flags, &req->reg_flags)) return -EFAULT;
+		if (__put_user(lval, &req->reg_last_reset_value)) return -EFAULT;
 	}
+
 	return 0;
+
 abort_mission:
-	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);
+	PFM_REG_RETFLAG_SET(reg_flags, PFM_REG_RETFL_EINVAL);
 	/* 
 	 * XXX: if this fails, we stick with the original failure, flag not updated!
 	 */
-	copy_to_user(req, &tmp, sizeof(tmp));
-	return -EINVAL;
+	__put_user(reg_flags, &req->reg_flags);
 
+	return -EINVAL;
 }
 
 #ifdef PFM_PMU_USES_DBR
@@ -1594,7 +1747,7 @@
 	else
 		pfm_sessions.pfs_ptrace_use_dbregs++;
 
-	DBprintk(("ptrace_use_dbregs=%lu  sys_use_dbregs=%lu by [%d] ret = %d\n", 
+	DBprintk(("ptrace_use_dbregs=%u  sys_use_dbregs=%u by [%d] ret = %d\n", 
 		  pfm_sessions.pfs_ptrace_use_dbregs, 
 		  pfm_sessions.pfs_sys_use_dbregs, 
 		  task->pid, ret));
@@ -1660,9 +1813,12 @@
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
 	if (task == current) {
-		DBprintk(("restarting self %d frozen=%d \n", current->pid, ctx->ctx_fl_frozen));
+		DBprintk(("restarting self %d frozen=%d ovfl_regs=0x%lx\n", 
+			task->pid, 
+			ctx->ctx_fl_frozen,
+			ctx->ctx_ovfl_regs[0]));
 
-		pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_RELOAD_LONG_RESET);
+		pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_PMD_LONG_RESET);
 
 		ctx->ctx_ovfl_regs[0] = 0UL;
 
@@ -1721,44 +1877,6 @@
 	return 0;
 }
 
-#ifndef CONFIG_SMP
-/*
- * On UP kernels, we do not need to constantly set the psr.pp bit
- * when a task is scheduled. The psr.pp bit can only be changed in
- * the kernel because of a user request. Given we are on a UP non preeemptive 
- * kernel we know that no other task is running, so we cna simply update their
- * psr.pp from their saved state. There is this no impact on the context switch
- * code compared to the SMP case.
- */
-static void
-pfm_tasklist_toggle_pp(unsigned int val)
-{
-	struct task_struct *p;
-	struct pt_regs *regs;
-
-	DBprintk(("invoked by [%d] pp=%u\n", current->pid, val));
-
-	read_lock(&tasklist_lock);
-
-	for_each_task(p) {
-       		regs = (struct pt_regs *)((unsigned long) p + IA64_STK_OFFSET);
-
-		/*
-		 * position on pt_regs saved on stack on 1st entry into the kernel
-		 */
-		regs--;
-
-		/*
-		 * update psr.pp
-		 */
-		ia64_psr(regs)->pp = val;
-	}
-	read_unlock(&tasklist_lock);
-}
-#endif
-
-
-
 static int
 pfm_stop(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, 
 	 struct pt_regs *regs)
@@ -1787,11 +1905,8 @@
 
 		ia64_srlz_i();
 
-#ifdef CONFIG_SMP
 		local_cpu_data->pfm_dcr_pp  = 0;
-#else
-		pfm_tasklist_toggle_pp(0);
-#endif
+
 		ia64_psr(regs)->pp = 0;
 
 	} else {
@@ -1960,14 +2075,9 @@
 	int i, ret = 0;
 
 	/*
-	 * for range restriction: psr.db must be cleared or the
-	 * the PMU will ignore the debug registers.
-	 *
-	 * XXX: may need more in system wide mode,
-	 * no task can have this bit set?
+	 * we do not need to check for ipsr.db because we do clear ibr.x, dbr.r, and dbr.w
+	 * ensuring that no real breakpoint can be installed via this call.
 	 */
-	if (ia64_psr(regs)->db == 1) return -EINVAL;
-
 
 	first_time = ctx->ctx_fl_using_dbreg == 0;
 
@@ -2036,9 +2146,8 @@
 	 * Now install the values into the registers
 	 */
 	for (i = 0; i < count; i++, req++) {
-
 		
-		if (copy_from_user(&tmp, req, sizeof(tmp))) goto abort_mission;
+		if (__copy_from_user(&tmp, req, sizeof(tmp))) goto abort_mission;
 		
 		rnum      = tmp.dbreg_num;
 		dbreg.val = tmp.dbreg_value;
@@ -2071,7 +2180,7 @@
 
 		PFM_REG_RETFLAG_SET(tmp.dbreg_flags, 0);
 
-		if (copy_to_user(req, &tmp, sizeof(tmp))) goto abort_mission;
+		if (__copy_to_user(req, &tmp, sizeof(tmp))) goto abort_mission;
 
 		/*
 		 * Debug registers, just like PMC, can only be modified
@@ -2126,7 +2235,7 @@
 		 * XXX: for now we can only come here on EINVAL
 		 */
 		PFM_REG_RETFLAG_SET(tmp.dbreg_flags, PFM_REG_RETFL_EINVAL);
-		copy_to_user(req, &tmp, sizeof(tmp));
+		if (__put_user(tmp.dbreg_flags, &req->dbreg_flags)) ret = -EFAULT;
 	}
 	return ret;
 }
@@ -2167,7 +2276,7 @@
 	tmp.ft_version      = PFM_VERSION;
 	tmp.ft_smpl_version = PFM_SMPL_VERSION;
 
-	if (copy_to_user(arg, &tmp, sizeof(tmp))) return -EFAULT;
+	if (__copy_to_user(arg, &tmp, sizeof(tmp))) return -EFAULT;
 
 	return 0;
 }
@@ -2196,11 +2305,8 @@
 
 	if (ctx->ctx_fl_system) {
 		
-#ifdef CONFIG_SMP
 		local_cpu_data->pfm_dcr_pp  = 1;
-#else
-		pfm_tasklist_toggle_pp(1);
-#endif
+
 		/* set user level psr.pp */
 		ia64_psr(regs)->pp = 1;
 
@@ -2240,7 +2346,7 @@
 		pfm_lazy_save_regs(PMU_OWNER());
 
 	/* reset all registers to stable quiet state */
-	ia64_reset_pmu(task);
+	pfm_reset_pmu(task);
 
 	/* make sure nothing starts */
 	if (ctx->ctx_fl_system) {
@@ -2251,10 +2357,8 @@
 		__asm__ __volatile__ ("rsm psr.pp;;"::: "memory");
 		ia64_srlz_i();
 
-#ifdef CONFIG_SMP
-		local_cpu_data->pfm_syst_wide = 1;
 		local_cpu_data->pfm_dcr_pp    = 0;
-#endif
+		local_cpu_data->pfm_syst_wide = 1;
 	} else {
 		/*
 		 * needed in case the task was a passive task during
@@ -2295,32 +2399,30 @@
 {
 	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
 	unsigned int cnum;
-	int i;
+	int i, ret = -EINVAL;
 
 	for (i = 0; i < count; i++, req++) {
 
-		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+		if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
 		cnum = tmp.reg_num;
 
 		if (!PMC_IS_IMPL(cnum)) goto abort_mission;
 
-		tmp.reg_value = reset_pmcs[cnum];
+		tmp.reg_value = PMC_DFL_VAL(cnum);
 
 		PFM_REG_RETFLAG_SET(tmp.reg_flags, 0);
 
 		DBprintk(("pmc_reset_val pmc[%u]=0x%lx\n", cnum, tmp.reg_value)); 
 
-		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
+		if (__copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
 	}
 	return 0;
 abort_mission:
 	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);
-	/* 
-	 * XXX: if this fails, we stick with the original failure, flag not updated!
-	 */
-	copy_to_user(req, &tmp, sizeof(tmp));
-	return -EINVAL;
+	if (__copy_to_user(req, &tmp, sizeof(tmp))) ret = -EFAULT;
+
+	return ret;
 }
 
 /*
@@ -2328,21 +2430,21 @@
  */
 static pfm_cmd_desc_t pfm_cmd_tab[]={
 /* 0  */{ NULL, 0, 0, 0}, /* not used */
-/* 1  */{ pfm_write_pmcs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, 
-/* 2  */{ pfm_write_pmds, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
-/* 3  */{ pfm_read_pmds,PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, 
+/* 1  */{ pfm_write_pmcs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, 
+/* 2  */{ pfm_write_pmds, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
+/* 3  */{ pfm_read_pmds,PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, 
 /* 4  */{ pfm_stop, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 5  */{ pfm_start, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 6  */{ pfm_enable, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 7  */{ pfm_disable, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
-/* 8  */{ pfm_context_create, PFM_CMD_PID|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, 1, sizeof(pfarg_context_t)},
+/* 8  */{ pfm_context_create, PFM_CMD_PID|PFM_CMD_ARG_RW, 1, sizeof(pfarg_context_t)},
 /* 9  */{ pfm_context_destroy, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 10 */{ pfm_restart, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_NOCHK, 0, 0},
 /* 11 */{ pfm_protect_context, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
-/* 12 */{ pfm_get_features, PFM_CMD_ARG_WRITE, 0, 0},
+/* 12 */{ pfm_get_features, PFM_CMD_ARG_RW, 0, 0},
 /* 13 */{ pfm_debug, 0, 1, sizeof(unsigned int)},
 /* 14 */{ pfm_context_unprotect, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
-/* 15 */{ pfm_get_pmc_reset, PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
+/* 15 */{ pfm_get_pmc_reset, PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
 /* 16 */{ NULL, 0, 0, 0}, /* not used */
 /* 17 */{ NULL, 0, 0, 0}, /* not used */
 /* 18 */{ NULL, 0, 0, 0}, /* not used */
@@ -2360,8 +2462,8 @@
 /* 30 */{ NULL, 0, 0, 0}, /* not used */
 /* 31 */{ NULL, 0, 0, 0}, /* not used */
 #ifdef PFM_PMU_USES_DBR
-/* 32 */{ pfm_write_ibrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)},
-/* 33 */{ pfm_write_dbrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)}
+/* 32 */{ pfm_write_ibrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)},
+/* 33 */{ pfm_write_dbrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)}
 #endif
 };
 #define PFM_CMD_COUNT	(sizeof(pfm_cmd_tab)/sizeof(pfm_cmd_desc_t))
@@ -2383,7 +2485,10 @@
 		task_unlock(task);
 
 		do {
-			if (task->state != TASK_ZOMBIE && task->state != TASK_STOPPED) return -EBUSY;
+			if (task->state != TASK_ZOMBIE && task->state != TASK_STOPPED) {
+				DBprintk(("warning [%d] not in stable state %ld\n", task->pid, task->state));
+				return -EBUSY;
+			}
 			barrier();
 			cpu_relax();
 		} while (task_has_cpu(task));
@@ -2426,7 +2531,7 @@
 
 	if (PFM_CMD_READ_ARG(cmd) && !access_ok(VERIFY_READ, arg, sz*count)) return -EFAULT;
 
-	if (PFM_CMD_WRITE_ARG(cmd) && !access_ok(VERIFY_WRITE, arg, sz*count)) return -EFAULT;
+	if (PFM_CMD_RW_ARG(cmd) && !access_ok(VERIFY_WRITE, arg, sz*count)) return -EFAULT;
 
 	if (PFM_CMD_USE_PID(cmd))  {
 		/* 
@@ -2484,15 +2589,9 @@
 	return ret;
 }
 
-#if __GNUC__ >= 3
-void asmlinkage
-pfm_ovfl_block_reset(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, 
-		      u64 arg6, u64 arg7, long info)
-#else
 void asmlinkage
 pfm_ovfl_block_reset(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, 
 		      u64 arg6, u64 arg7, long info)
-#endif
 {
 	struct thread_struct *th = &current->thread;
 	pfm_context_t *ctx = current->thread.pfm_context;
@@ -2537,7 +2636,7 @@
 		 * use the local reference
 		 */
 
-		pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_RELOAD_LONG_RESET);
+		pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_PMD_LONG_RESET);
 
 		ctx->ctx_ovfl_regs[0] = 0UL;
 
@@ -2596,8 +2695,8 @@
 	 */
 	h->pid  = current->pid;
 	h->cpu  = smp_processor_id();
-	h->rate = 0; /* XXX: add the sampling rate used here */
-	h->ip   = regs ? regs->cr_iip : 0x0;	/* where did the fault happened */
+	h->last_reset_value = ovfl_mask ? ctx->ctx_soft_pmds[ffz(~ovfl_mask)].lval : 0UL;
+	h->ip   = regs ? regs->cr_iip | ((regs->cr_ipsr >> 41) & 0x3): 0x0UL;
 	h->regs = ovfl_mask; 			/* which registers overflowed */
 
 	/* guaranteed to monotonically increase on each cpu */
@@ -2617,15 +2716,13 @@
 
 		if (PMD_IS_COUNTING(j)) {
 			*e  =  pfm_read_soft_counter(ctx, j);
-			/* check if this pmd overflowed as well */
-			*e +=  ovfl_mask & (1UL<<j) ? 1 + pmu_conf.perf_ovfl_val : 0;
 		} else {
 			*e = ia64_get_pmd(j); /* slow */
 		}
 		DBprintk_ovfl(("e=%p pmd%d =0x%lx\n", (void *)e, j, *e));
 		e++;
 	}
-	pfm_stats.pfm_recorded_samples_count++;
+	pfm_stats[smp_processor_id()].pfm_recorded_samples_count++;
 
 	/*
 	 * make the new entry visible to user, needs to be atomic
@@ -2642,7 +2739,7 @@
 		/*
 		 * XXX: must reset buffer in blocking mode and lost notified
 		 */
-		pfm_stats.pfm_full_smpl_buffer_count++;
+		pfm_stats[smp_processor_id()].pfm_full_smpl_buffer_count++;
 		return 1;
 	}
 	return 0;
@@ -2719,23 +2816,13 @@
 			  i, ia64_get_pmd(i), ctx->ctx_soft_pmds[i].val));
 
 		/*
-		 * Because we sometimes (EARS/BTB) reset to a specific value, we cannot simply use
-		 * val to count the number of times we overflowed. Otherwise we would loose the 
-		 * current value in the PMD (which can be >0). So to make sure we don't loose
-		 * the residual counts we set val to contain full 64bits value of the counter.
+		 * Note that the pmd is not necessarily 0 at this point as qualified events
+		 * may have happened before the PMU was frozen. The residual count is not
+		 * taken into consideration here but will be with any read of the pmd via
+		 * pfm_read_pmds().
 		 */
 		old_val = ctx->ctx_soft_pmds[i].val;
-		ctx->ctx_soft_pmds[i].val = 1 + pmu_conf.perf_ovfl_val + pfm_read_soft_counter(ctx, i);
-
-		DBprintk_ovfl(("soft_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx\n", 
-			  i, ctx->ctx_soft_pmds[i].val, old_val, 
-			  ia64_get_pmd(i) & pmu_conf.perf_ovfl_val));
-
-		/*
-		 * now that we have extracted the hardware counter, we can clear it to ensure
-		 * that a subsequent PFM_READ_PMDS will not include it again.
-		 */
-		ia64_set_pmd(i, 0UL);
+		ctx->ctx_soft_pmds[i].val += 1 + pmu_conf.ovfl_val;
 
 		/*
 		 * check for overflow condition
@@ -2744,12 +2831,13 @@
 
 			ovfl_pmds |= 1UL << i;
 
-			DBprintk_ovfl(("soft_pmd[%d] overflowed flags=0x%x, ovfl=0x%lx\n", i, ctx->ctx_soft_pmds[i].flags, ovfl_pmds));
-
 			if (PMC_OVFL_NOTIFY(ctx, i)) {
 				ovfl_notify |= 1UL << i;
 			}
 		}
+		DBprintk_ovfl(("soft_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx ovfl_pmds=0x%lx ovfl_notify=0x%lx\n", 
+			  i, ctx->ctx_soft_pmds[i].val, old_val, 
+			  ia64_get_pmd(i) & pmu_conf.ovfl_val, ovfl_pmds, ovfl_notify));
 	}
 
 	/*
@@ -2784,7 +2872,7 @@
 	 */
 	if (ovfl_notify == 0UL) {
 		if (ovfl_pmds) 
-			pfm_reset_regs(ctx, &ovfl_pmds, PFM_RELOAD_SHORT_RESET);
+			pfm_reset_regs(ctx, &ovfl_pmds, PFM_PMD_SHORT_RESET);
 		return 0x0;
 	}
 
@@ -2932,13 +3020,21 @@
 }
 
 static void
-perfmon_interrupt (int irq, void *arg, struct pt_regs *regs)
+pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs)
 {
 	u64 pmc0;
 	struct task_struct *task;
 	pfm_context_t *ctx;
 
-	pfm_stats.pfm_ovfl_intr_count++;
+	pfm_stats[smp_processor_id()].pfm_ovfl_intr_count++;
+
+	/*
+	 * if an alternate handler is registered, just bypass the default one
+	 */
+	if (pfm_alternate_intr_handler) {
+		(*pfm_alternate_intr_handler->handler)(irq, arg, regs);
+		return;
+	}
 
 	/* 
 	 * srlz.d done before arriving here
@@ -2996,42 +3092,37 @@
 		atomic_set(&ctx->ctx_is_busy, 0);
 #endif
 	} else {
-		pfm_stats.pfm_spurious_ovfl_intr_count++;
-
-		printk("perfmon: Spurious PMU overflow interrupt on CPU%d: pmc0=0x%lx owner=%p\n", 
-			smp_processor_id(), pmc0, (void *)PMU_OWNER());
+		pfm_stats[smp_processor_id()].pfm_spurious_ovfl_intr_count++;
 	}
 }
 
 /* for debug only */
 static int
-perfmon_proc_info(char *page)
+pfm_proc_info(char *page)
 {
 	char *p = page;
 	int i;
 
-	p += sprintf(p, "enabled          : %s\n", pmu_conf.pfm_is_disabled ? "No": "Yes");
-	p += sprintf(p, "fastctxsw        : %s\n", pfm_sysctl.fastctxsw > 0 ? "Yes": "No");
-	p += sprintf(p, "ovfl_mask        : 0x%lx\n", pmu_conf.perf_ovfl_val);
-	p += sprintf(p, "overflow intrs   : %lu\n", pfm_stats.pfm_ovfl_intr_count);
-	p += sprintf(p, "spurious intrs   : %lu\n", pfm_stats.pfm_spurious_ovfl_intr_count);
-	p += sprintf(p, "recorded samples : %lu\n", pfm_stats.pfm_recorded_samples_count);
-	p += sprintf(p, "smpl buffer full : %lu\n", pfm_stats.pfm_full_smpl_buffer_count);
+	p += sprintf(p, "fastctxsw              : %s\n", pfm_sysctl.fastctxsw > 0 ? "Yes": "No");
+	p += sprintf(p, "ovfl_mask              : 0x%lx\n", pmu_conf.ovfl_val);
 
-#ifdef CONFIG_SMP
-	p += sprintf(p, "CPU%d syst_wide   : %d\n"
-			"CPU%d dcr_pp      : %d\n", 
-			smp_processor_id(), 
-			local_cpu_data->pfm_syst_wide, 
-			smp_processor_id(), 
-			local_cpu_data->pfm_dcr_pp);
-#endif
+	for(i=0; i < NR_CPUS; i++) {
+		if (cpu_is_online(i) == 0) continue;
+		p += sprintf(p, "CPU%-2d overflow intrs   : %lu\n", i, pfm_stats[i].pfm_ovfl_intr_count);
+		p += sprintf(p, "CPU%-2d spurious intrs   : %lu\n", i, pfm_stats[i].pfm_spurious_ovfl_intr_count);
+		p += sprintf(p, "CPU%-2d recorded samples : %lu\n", i, pfm_stats[i].pfm_recorded_samples_count);
+		p += sprintf(p, "CPU%-2d smpl buffer full : %lu\n", i, pfm_stats[i].pfm_full_smpl_buffer_count);
+		p += sprintf(p, "CPU%-2d syst_wide        : %d\n", i, cpu_data(i)->pfm_syst_wide);
+		p += sprintf(p, "CPU%-2d dcr_pp           : %d\n", i, cpu_data(i)->pfm_dcr_pp);
+		p += sprintf(p, "CPU%-2d owner            : %d\n", i, pmu_owners[i].owner ? pmu_owners[i].owner->pid: -1);
+	}
 
 	LOCK_PFS();
-	p += sprintf(p, "proc_sessions    : %lu\n"
-			"sys_sessions     : %lu\n"
-			"sys_use_dbregs   : %lu\n"
-			"ptrace_use_dbregs: %lu\n", 
+
+	p += sprintf(p, "proc_sessions          : %u\n"
+			"sys_sessions           : %u\n"
+			"sys_use_dbregs         : %u\n"
+			"ptrace_use_dbregs      : %u\n", 
 			pfm_sessions.pfs_task_sessions, 
 			pfm_sessions.pfs_sys_sessions,
 			pfm_sessions.pfs_sys_use_dbregs,
@@ -3039,30 +3130,6 @@
 
 	UNLOCK_PFS();
 
-	for(i=0; i < NR_CPUS; i++) {
-		if (cpu_is_online(i)) {
-			p += sprintf(p, "CPU%d owner : %-6d\n",
-					i, 
-					pmu_owners[i].owner ? pmu_owners[i].owner->pid: -1);
-		}
-	}
-
-	for(i=0; pmd_desc[i].type != PFM_REG_NONE; i++) {
-		p += sprintf(p, "PMD%-2d: %d 0x%lx 0x%lx\n", 
-				i,
-				pmd_desc[i].type, 
-				pmd_desc[i].dep_pmd[0], 
-				pmd_desc[i].dep_pmc[0]); 
-	}
-
-	for(i=0; pmc_desc[i].type != PFM_REG_NONE; i++) {
-		p += sprintf(p, "PMC%-2d: %d 0x%lx 0x%lx\n", 
-				i, 
-				pmc_desc[i].type, 
-				pmc_desc[i].dep_pmd[0], 
-				pmc_desc[i].dep_pmc[0]); 
-	}
-
 	return p - page;
 }
 
@@ -3070,7 +3137,7 @@
 static int
 perfmon_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
-	int len = perfmon_proc_info(page);
+	int len = pfm_proc_info(page);
 
 	if (len <= off+count) *eof = 1;
 
@@ -3083,7 +3150,6 @@
 	return len;
 }
 
-#ifdef CONFIG_SMP
 void
 pfm_syst_wide_update_task(struct task_struct *task, int mode)
 {
@@ -3096,8 +3162,6 @@
 	 */
 	ia64_psr(regs)->pp = mode ? local_cpu_data->pfm_dcr_pp : 0;
 }
-#endif
-
 
 void
 pfm_save_regs (struct task_struct *task)
@@ -3409,7 +3473,7 @@
 	 */
 	mask = pfm_sysctl.fastctxsw || ctx->ctx_fl_protected ?  ctx->ctx_used_pmds[0] : ctx->ctx_reload_pmds[0];
 	for (i=0; mask; i++, mask>>=1) {
-		if (mask & 0x1) ia64_set_pmd(i, t->pmd[i] & pmu_conf.perf_ovfl_val);
+		if (mask & 0x1) ia64_set_pmd(i, t->pmd[i] & pmu_conf.ovfl_val);
 	}
 
 	/* 
@@ -3452,15 +3516,14 @@
  * XXX: make this routine able to work with non current context
  */
 static void
-ia64_reset_pmu(struct task_struct *task)
+pfm_reset_pmu(struct task_struct *task)
 {
 	struct thread_struct *t = &task->thread;
 	pfm_context_t *ctx = t->pfm_context;
-	unsigned long mask;
 	int i;
 
 	if (task != current) {
-		printk("perfmon: invalid task in ia64_reset_pmu()\n");
+		printk("perfmon: invalid task in pfm_reset_pmu()\n");
 		return;
 	}
 
@@ -3471,28 +3534,24 @@
 	 * install reset values for PMC. We skip PMC0 (done above)
 	 * XX: good up to 64 PMCS
 	 */
-	mask = pmu_conf.impl_regs[0] >> 1;
-	for(i=1; mask; mask>>=1, i++) {
-		if (mask & 0x1) {
-			ia64_set_pmc(i, reset_pmcs[i]);
-			/*
-			 * When restoring context, we must restore ALL pmcs, even the ones 
-			 * that the task does not use to avoid leaks and possibly corruption
-			 * of the sesion because of configuration conflicts. So here, we 
-			 * initialize the entire set used in the context switch restore routine.
-	 		 */
-			t->pmc[i] = reset_pmcs[i];
-			DBprintk((" pmc[%d]=0x%lx\n", i, reset_pmcs[i]));
-						 
-		}
+	for (i=1; (pmu_conf.pmc_desc[i].type & PFM_REG_END) == 0; i++) {
+		if ((pmu_conf.pmc_desc[i].type & PFM_REG_IMPL) == 0) continue;
+		ia64_set_pmc(i, PMC_DFL_VAL(i));
+		/*
+		 * When restoring context, we must restore ALL pmcs, even the ones 
+		 * that the task does not use to avoid leaks and possibly corruption
+		 * of the sesion because of configuration conflicts. So here, we 
+		 * initialize the entire set used in the context switch restore routine.
+	 	 */
+		t->pmc[i] = PMC_DFL_VAL(i);
+		DBprintk(("pmc[%d]=0x%lx\n", i, t->pmc[i]));
 	}
 	/*
 	 * clear reset values for PMD. 
-	 * XXX: good up to 64 PMDS. Suppose that zero is a valid value.
 	 */
-	mask = pmu_conf.impl_regs[4];
-	for(i=0; mask; mask>>=1, i++) {
-		if (mask & 0x1) ia64_set_pmd(i, 0UL);
+	for (i=0; (pmu_conf.pmd_desc[i].type & PFM_REG_END) == 0; i++) {
+		if ((pmu_conf.pmd_desc[i].type & PFM_REG_IMPL) == 0) continue;
+		ia64_set_pmd(i, 0UL);
 		t->pmd[i] = 0UL;
 	}
 
@@ -3521,13 +3580,13 @@
 	  *
 	  * We never directly restore PMC0 so we do not include it in the mask.
 	  */
-	ctx->ctx_reload_pmcs[0] = pmu_conf.impl_regs[0] & ~0x1;
+	ctx->ctx_reload_pmcs[0] = pmu_conf.impl_pmcs[0] & ~0x1;
 	/*
 	 * We must include all the PMD in this mask to avoid picking
 	 * up stale value and leak information, especially directly
 	 * at the user level when psr.sp=0
 	 */
-	ctx->ctx_reload_pmds[0] = pmu_conf.impl_regs[4];
+	ctx->ctx_reload_pmds[0] = pmu_conf.impl_pmds[0];
 
 	/* 
 	 * Keep track of the pmds we want to sample
@@ -3537,7 +3596,7 @@
 	 *
 	 * We ignore the unimplemented pmds specified by the user
 	 */
-	ctx->ctx_used_pmds[0] = ctx->ctx_smpl_regs[0] & pmu_conf.impl_regs[4];
+	ctx->ctx_used_pmds[0] = ctx->ctx_smpl_regs[0];
 	ctx->ctx_used_pmcs[0] = 1; /* always save/restore PMC[0] */
 
 	/*
@@ -3595,12 +3654,8 @@
 
 		ia64_srlz_i();
 
-#ifdef CONFIG_SMP
 		local_cpu_data->pfm_syst_wide = 0;
 		local_cpu_data->pfm_dcr_pp    = 0;
-#else
-		pfm_tasklist_toggle_pp(0);
-#endif
 	} else  {
 
 		/* stop monitoring */
@@ -3670,10 +3725,14 @@
 		val = ia64_get_pmd(i);
 
 		if (PMD_IS_COUNTING(i)) {
-			DBprintk(("[%d] pmd[%d] soft_pmd=0x%lx hw_pmd=0x%lx\n", task->pid, i, ctx->ctx_soft_pmds[i].val, val & pmu_conf.perf_ovfl_val));
+			DBprintk(("[%d] pmd[%d] soft_pmd=0x%lx hw_pmd=0x%lx\n", 
+				task->pid, 
+				i, 
+				ctx->ctx_soft_pmds[i].val, 
+				val & pmu_conf.ovfl_val));
 
 			/* collect latest results */
-			ctx->ctx_soft_pmds[i].val += val & pmu_conf.perf_ovfl_val;
+			ctx->ctx_soft_pmds[i].val += val & pmu_conf.ovfl_val;
 
 			/*
 			 * now everything is in ctx_soft_pmds[] and we need
@@ -3686,7 +3745,7 @@
 			 * take care of overflow inline
 			 */
 			if (pmc0 & (1UL << i)) {
-				ctx->ctx_soft_pmds[i].val += 1 + pmu_conf.perf_ovfl_val;
+				ctx->ctx_soft_pmds[i].val += 1 + pmu_conf.ovfl_val;
 				DBprintk(("[%d] pmd[%d] overflowed soft_pmd=0x%lx\n",
 					task->pid, i, ctx->ctx_soft_pmds[i].val));
 			}
@@ -3820,18 +3879,13 @@
 	m = nctx->ctx_used_pmds[0] >> PMU_FIRST_COUNTER;
 	for(i = PMU_FIRST_COUNTER ; m ; m>>=1, i++) {
 		if ((m & 0x1) && pmu_conf.pmd_desc[i].type == PFM_REG_COUNTING) {
-			nctx->ctx_soft_pmds[i].val = nctx->ctx_soft_pmds[i].ival & ~pmu_conf.perf_ovfl_val;
-			thread->pmd[i]	      	   = nctx->ctx_soft_pmds[i].ival & pmu_conf.perf_ovfl_val;
+			nctx->ctx_soft_pmds[i].val = nctx->ctx_soft_pmds[i].lval & ~pmu_conf.ovfl_val;
+			thread->pmd[i]	      	   = nctx->ctx_soft_pmds[i].lval & pmu_conf.ovfl_val;
+		} else {
+			thread->pmd[i]	      	   = 0UL; /* reset to initial state */
 		}
-		/* what about the other pmds? zero or keep as is */
 
 	}
-	/*
-	 * clear BTB index register
-	 * XXX: CPU-model specific knowledge!
-	 */
-	thread->pmd[16] = 0;
-
 
 	nctx->ctx_fl_frozen    = 0;
 	nctx->ctx_ovfl_regs[0] = 0UL;
@@ -3994,31 +4048,15 @@
 
 	UNLOCK_CTX(ctx);
 
-	LOCK_PFS();
+	pfm_unreserve_session(task, ctx->ctx_fl_system, 1UL << ctx->ctx_cpu);
 
 	if (ctx->ctx_fl_system) {
-
-		pfm_sessions.pfs_sys_session[ctx->ctx_cpu] = NULL;
-		pfm_sessions.pfs_sys_sessions--;
-		DBprintk(("freeing syswide session on CPU%ld\n", ctx->ctx_cpu));
-
-		/* update perfmon debug register usage counter */
-		if (ctx->ctx_fl_using_dbreg) {
-			if (pfm_sessions.pfs_sys_use_dbregs == 0) {
-				printk("perfmon: invalid release for [%d] sys_use_dbregs=0\n", task->pid);
-			} else
-				pfm_sessions.pfs_sys_use_dbregs--;
-		}
-
 		/*
 	 	 * remove any CPU pinning
 	 	 */
 		task->cpus_allowed = ctx->ctx_saved_cpus_allowed;
 		task->need_resched = 1;
-	} else {
-		pfm_sessions.pfs_task_sessions--;
-	}
-	UNLOCK_PFS();
+	} 
 
 	pfm_context_free(ctx);
 	/* 
@@ -4178,120 +4216,161 @@
 }
 
 static struct irqaction perfmon_irqaction = {
-	handler:	perfmon_interrupt,
+	handler:	pfm_interrupt_handler,
 	flags:		SA_INTERRUPT,
 	name:		"perfmon"
 };
 
-
-static void
-pfm_pmu_snapshot(void)
+int
+pfm_install_alternate_syswide_subsystem(pfm_intr_handler_desc_t *hdl)
 {
-	int i;
+	int ret;
 
-	for (i=0; i < IA64_NUM_PMC_REGS; i++) {
-		if (i >= pmu_conf.num_pmcs) break;
-		if (PMC_IS_IMPL(i)) reset_pmcs[i] = ia64_get_pmc(i);
+	/* some sanity checks */
+	if (hdl == NULL || hdl->handler == NULL) return -EINVAL;
+
+	/* do the easy test first */
+	if (pfm_alternate_intr_handler) return -EBUSY;
+
+	/* reserve our session */
+	ret = pfm_reserve_session(NULL, 1, cpu_online_map);
+	if (ret) return ret;
+
+	if (pfm_alternate_intr_handler) {
+		printk("perfmon: install_alternate, intr_handler not NULL after reserve\n");
+		return -EINVAL;
 	}
-#ifdef CONFIG_MCKINLEY
-	/*
-	 * set the 'stupid' enable bit to power the PMU!
+
+	pfm_alternate_intr_handler = hdl;
+
+	return 0;
+}
+
+int
+pfm_remove_alternate_syswide_subsystem(pfm_intr_handler_desc_t *hdl)
+{
+	if (hdl == NULL) return -EINVAL;
+
+	/* cannot remove someone else's handler! */
+	if (pfm_alternate_intr_handler != hdl) return -EINVAL;
+
+	pfm_alternate_intr_handler = NULL;
+
+	/* 
+	 * XXX: assume cpu_online_map has not changed since reservation 
 	 */
-	reset_pmcs[4] |= 1UL << 23;
-#endif
+	pfm_unreserve_session(NULL, 1, cpu_online_map);
+
+	return 0;
 }
 
 /*
  * perfmon initialization routine, called from the initcall() table
  */
 int __init
-perfmon_init (void)
+pfm_init(void)
 {
-	pal_perf_mon_info_u_t pm_info;
-	s64 status;
+	unsigned int n, n_counters, i;
 
-	pmu_conf.pfm_is_disabled = 1;
+	pmu_conf.disabled = 1;
 
-	printk("perfmon: version %u.%u (sampling format v%u.%u) IRQ %u\n", 
+	printk("perfmon: version %u.%u IRQ %u\n", 
 		PFM_VERSION_MAJ, 
 		PFM_VERSION_MIN, 
-		PFM_SMPL_VERSION_MAJ, 
-		PFM_SMPL_VERSION_MIN, 
 		IA64_PERFMON_VECTOR);
 
-	if ((status=ia64_pal_perf_mon_info(pmu_conf.impl_regs, &pm_info)) != 0) {
-		printk("perfmon: PAL call failed (%ld), perfmon disabled\n", status);
-		return -1;
-	}
-
-	pmu_conf.perf_ovfl_val = (1UL << pm_info.pal_perf_mon_info_s.width) - 1;
-	pmu_conf.max_counters  = pm_info.pal_perf_mon_info_s.generic;
-	pmu_conf.num_pmcs      = find_num_pm_regs(pmu_conf.impl_regs);
-	pmu_conf.num_pmds      = find_num_pm_regs(&pmu_conf.impl_regs[4]);
-
-	printk("perfmon: %u bits counters\n", pm_info.pal_perf_mon_info_s.width);
-
-	printk("perfmon: %lu PMC/PMD pairs, %lu PMCs, %lu PMDs\n", 
-	       pmu_conf.max_counters, pmu_conf.num_pmcs, pmu_conf.num_pmds);
+	/*
+	 * compute the number of implemented PMD/PMC from the
+	 * description tables
+	 */
+	n = 0;
+	for (i=0; PMC_IS_LAST(i) == 0;  i++) {
+		if (PMC_IS_IMPL(i) == 0) continue;
+		pmu_conf.impl_pmcs[i>>6] |= 1UL << (i&63);
+		n++;
+	}
+	pmu_conf.num_pmcs = n;
+
+	n = 0; n_counters = 0;
+	for (i=0; PMD_IS_LAST(i) == 0;  i++) {
+		if (PMD_IS_IMPL(i) == 0) continue;
+		pmu_conf.impl_pmds[i>>6] |= 1UL << (i&63);
+		n++;
+		if (PMD_IS_COUNTING(i)) n_counters++;
+	}
+	pmu_conf.num_pmds      = n;
+	pmu_conf.num_counters  = n_counters;
+
+	printk("perfmon: %u PMCs, %u PMDs, %u counters (%lu bits)\n", 
+	       pmu_conf.num_pmcs, 
+	       pmu_conf.num_pmds,
+	       pmu_conf.num_counters,
+	       ffz(pmu_conf.ovfl_val));
 
 	/* sanity check */
 	if (pmu_conf.num_pmds >= IA64_NUM_PMD_REGS || pmu_conf.num_pmcs >= IA64_NUM_PMC_REGS) {
-		printk(KERN_ERR "perfmon: not enough pmc/pmd, perfmon is DISABLED\n");
-		return -1; /* no need to continue anyway */
-	}
-
-	if (ia64_pal_debug_info(&pmu_conf.num_ibrs, &pmu_conf.num_dbrs)) {
-		printk(KERN_WARNING "perfmon: unable to get number of debug registers\n");
-		pmu_conf.num_ibrs = pmu_conf.num_dbrs = 0;
+		printk(KERN_ERR "perfmon: not enough pmc/pmd, perfmon disabled\n");
+		return -1;
 	}
-	/* PAL reports the number of pairs */
-	pmu_conf.num_ibrs <<=1;
-	pmu_conf.num_dbrs <<=1;
 
 	/*
-	 * take a snapshot of all PMU registers. PAL is supposed
-	 * to configure them with stable/safe values, i.e., not
-	 * capturing anything.
-	 * We take a snapshot now, before we make any modifications. This
-	 * will become our master copy. Then we will reuse the snapshot
-	 * to reset the PMU in pfm_enable(). Using this technique, perfmon
-	 * does NOT have to know about the specific values to program for
-	 * the PMC/PMD. The safe values may be different from one CPU model to
-	 * the other.
+	 * for now here for debug purposes
 	 */
-	pfm_pmu_snapshot();
+	perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL);
+	if (perfmon_dir == NULL) {
+		printk(KERN_ERR "perfmon: cannot create /proc entry, perfmon disabled\n");
+		return -1; 
+	}
 
 	/*
-	 * setup the register configuration descriptions for the CPU
+	 * create /proc/perfmon
 	 */
-	pmu_conf.pmc_desc = pmc_desc;
-	pmu_conf.pmd_desc = pmd_desc;
-
-	/* we are all set */
-	pmu_conf.pfm_is_disabled = 0;
+	pfm_sysctl_header = register_sysctl_table(pfm_sysctl_root, 0);
 
 	/*
-	 * for now here for debug purposes
+	 * initialize all our spinlocks
 	 */
-	perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL);
-
-	pfm_sysctl_header = register_sysctl_table(pfm_sysctl_root, 0);
-
 	spin_lock_init(&pfm_sessions.pfs_lock);
 
+	/* we are all set */
+	pmu_conf.disabled = 0;
+
 	return 0;
 }
 
-__initcall(perfmon_init);
+__initcall(pfm_init);
 
 void
-perfmon_init_percpu (void)
+pfm_init_percpu(void)
 {
+	int i;
+
 	if (smp_processor_id() == 0)
 		register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction);
 
 	ia64_set_pmv(IA64_PERFMON_VECTOR);
 	ia64_srlz_d();
+
+	/*
+	 * we first initialize the PMU to a stable state.
+	 * the values may have been changed from their power-up
+	 * values by software executed before the kernel took over.
+	 *
+	 * At this point, pmu_conf has not yet been initialized
+	 *
+	 * On McKinley, this code is ineffective until PMC4 is initialized.
+	 */
+	for (i=1; PMC_IS_LAST(i) == 0;  i++) {
+		if (PMC_IS_IMPL(i) == 0) continue;
+		ia64_set_pmc(i, PMC_DFL_VAL(i));
+	}
+
+	for (i=0; PMD_IS_LAST(i); i++) {
+		if (PMD_IS_IMPL(i) == 0) continue;
+		ia64_set_pmd(i, 0UL);
+	}
+	ia64_set_pmc(0,1UL);
+	ia64_srlz_d();
 }
 
 #else /* !CONFIG_PERFMON */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/perfmon_generic.h linux-2.4.21/arch/ia64/kernel/perfmon_generic.h
--- linux-2.4.20/arch/ia64/kernel/perfmon_generic.h	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/perfmon_generic.h	2002-12-18 18:58:02.000000000 +0000
@@ -1,29 +1,48 @@
+/*
+ * This file contains the architected PMU register description tables
+ * and pmc checker used by perfmon.c.
+ *
+ * Copyright (C) 2002  Hewlett Packard Co
+ *               Stephane Eranian <eranian@hpl.hp.com>
+ */
 #define RDEP(x)	(1UL<<(x))
 
-#ifdef CONFIG_ITANIUM
-#error "This file should not be used when CONFIG_ITANIUM is defined"
+#if defined(CONFIG_ITANIUM) || defined (CONFIG_MCKINLEY)
+#error "This file should not be used when CONFIG_ITANIUM or CONFIG_MCKINLEY is defined"
 #endif
 
-static pfm_reg_desc_t pmc_desc[256]={
-/* pmc0  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc1  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc2  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc3  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pmc_gen_desc[PMU_MAX_PMCS]={
+/* pmc0  */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc1  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc2  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc3  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc4  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc5  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc6  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc7  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
 };
 
-static pfm_reg_desc_t pmd_desc[256]={
-/* pmd0  */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}},
-/* pmd1  */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}},
-/* pmd2  */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}},
-/* pmd3  */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}},
-/* pmd4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
-/* pmd5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
-/* pmd6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
-/* pmd7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pmd_gen_desc[PMU_MAX_PMDS]={
+/* pmd0  */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
+/* pmd1  */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
+/* pmd2  */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
+/* pmd3  */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
+/* pmd4  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
+/* pmd5  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
+/* pmd6  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
+/* pmd7  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
+};
+
+/*
+ * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
+ */
+static pmu_config_t pmu_conf={
+	disabled:	1,
+	ovfl_val:	(1UL << 32) - 1,
+	num_ibrs:	8,
+	num_dbrs:	8,
+	pmd_desc:	pfm_gen_pmd_desc,
+	pmc_desc:	pfm_gen_pmc_desc
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/perfmon_itanium.h linux-2.4.21/arch/ia64/kernel/perfmon_itanium.h
--- linux-2.4.20/arch/ia64/kernel/perfmon_itanium.h	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/perfmon_itanium.h	2002-12-18 18:58:01.000000000 +0000
@@ -15,46 +15,59 @@
 static int pfm_ita_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 static int pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs);
 
-static pfm_reg_desc_t pmc_desc[256]={
-/* pmc0  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc1  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc2  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc3  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc4  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc5  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc6  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc7  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc8  */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc9  */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc10 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc11 */ { PFM_REG_MONITOR, 6, NULL, pfm_ita_pmc_check, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc12 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc13 */ { PFM_REG_CONFIG, 0, NULL, pfm_ita_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pfm_ita_pmc_desc[PMU_MAX_PMCS]={
+/* pmc0  */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc1  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc2  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc3  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc4  */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc5  */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc6  */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc7  */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc8  */ { PFM_REG_CONFIG  , 0, 0xf00000003ffffff8UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc9  */ { PFM_REG_CONFIG  , 0, 0xf00000003ffffff8UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc10 */ { PFM_REG_MONITOR , 6, 0x0UL, -1UL, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc11 */ { PFM_REG_MONITOR , 6, 0x0000000010000000UL, -1UL, NULL, pfm_ita_pmc_check, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc13 */ { PFM_REG_CONFIG  , 0, 0x0003ffff00000001UL, -1UL, NULL, pfm_ita_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
 };
 
-static pfm_reg_desc_t pmd_desc[256]={
-/* pmd0  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
-/* pmd1  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
-/* pmd2  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-/* pmd3  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-/* pmd4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
-/* pmd5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
-/* pmd6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
-/* pmd7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
-/* pmd8  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd9  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd10 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd11 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd12 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd13 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd14 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd15 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd16 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd17 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pfm_ita_pmd_desc[PMU_MAX_PMDS]={
+/* pmd0  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd1  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd2  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd3  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd4  */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
+/* pmd5  */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
+/* pmd6  */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
+/* pmd7  */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
+/* pmd8  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd9  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd10 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd11 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd12 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd13 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd14 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd15 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd16 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd17 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
 };
 
+/*
+ * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
+ */
+static pmu_config_t pmu_conf={
+	disabled:	1,
+	ovfl_val:	(1UL << 32) - 1,
+	num_ibrs:	8,
+	num_dbrs:	8,
+	pmd_desc:	pfm_ita_pmd_desc,
+	pmc_desc:	pfm_ita_pmc_desc
+};
+
+
 static int
 pfm_ita_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/perfmon_mckinley.h linux-2.4.21/arch/ia64/kernel/perfmon_mckinley.h
--- linux-2.4.20/arch/ia64/kernel/perfmon_mckinley.h	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/perfmon_mckinley.h	2002-12-18 18:58:05.000000000 +0000
@@ -12,51 +12,86 @@
 #error "This file is only valid when CONFIG_MCKINLEY is defined"
 #endif
 
+static int pfm_mck_reserved(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 static int pfm_mck_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 static int pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs);
 
-static pfm_reg_desc_t pmc_desc[256]={
-/* pmc0  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc1  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc2  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc3  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc4  */ { PFM_REG_COUNTING, 6, NULL, pfm_mck_pmc_check, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc5  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc6  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc7  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc8  */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc9  */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc10 */ { PFM_REG_MONITOR, 4, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc11 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc12 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc13 */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc14 */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc15 */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pfm_mck_pmc_desc[PMU_MAX_PMCS]={
+/* pmc0  */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc1  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc2  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc3  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc4  */ { PFM_REG_COUNTING, 6, 0x0000000000800000UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc5  */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL,  pfm_mck_reserved, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc6  */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL,  pfm_mck_reserved, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc7  */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL,  pfm_mck_reserved, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc8  */ { PFM_REG_CONFIG  , 0, 0xffffffff3fffffffUL, 0xffffffff9fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc9  */ { PFM_REG_CONFIG  , 0, 0xffffffff3ffffffcUL, 0xffffffff9fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc10 */ { PFM_REG_MONITOR , 4, 0x0UL, 0xffffUL, NULL, pfm_mck_reserved, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc11 */ { PFM_REG_MONITOR , 6, 0x0UL, 0x30f01cf, NULL,  pfm_mck_reserved, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, 0xffffUL, NULL,  pfm_mck_reserved, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc13 */ { PFM_REG_CONFIG  , 0, 0x00002078fefefefeUL, 0x1e00018181818UL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc14 */ { PFM_REG_CONFIG  , 0, 0x0db60db60db60db6UL, 0x2492UL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc15 */ { PFM_REG_CONFIG  , 0, 0x00000000fffffff0UL, 0xfUL, NULL, pfm_mck_reserved, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
 };
 
-static pfm_reg_desc_t pmd_desc[256]={
-/* pmd0  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
-/* pmd1  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
-/* pmd2  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-/* pmd3  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-/* pmd4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
-/* pmd5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
-/* pmd6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
-/* pmd7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
-/* pmd8  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd9  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd10 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd11 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd12 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd13 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd14 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd15 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd16 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd17 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pfm_mck_pmd_desc[PMU_MAX_PMDS]={
+/* pmd0  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd1  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd2  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd3  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd4  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
+/* pmd5  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
+/* pmd6  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
+/* pmd7  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
+/* pmd8  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd9  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd10 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd11 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd12 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd13 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd14 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd15 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd16 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd17 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
 };
 
+/*
+ * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
+ */
+static pmu_config_t pmu_conf={
+	disabled:	1,
+	ovfl_val:	(1UL << 47) - 1,
+	num_ibrs:	8,
+	num_dbrs:	8,
+	pmd_desc:	pfm_mck_pmd_desc,
+	pmc_desc:	pfm_mck_pmc_desc
+};
+
+
+/*
+ * PMC reserved fields must have their power-up values preserved
+ */
+static int
+pfm_mck_reserved(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs)
+{
+	unsigned long tmp1, tmp2, ival = *val;
+
+	/* remove reserved areas from user value */
+	tmp1 = ival & PMC_RSVD_MASK(cnum);
+
+	/* get reserved fields values */
+	tmp2 = PMC_DFL_VAL(cnum) & ~PMC_RSVD_MASK(cnum);
+
+	*val = tmp1 | tmp2;
+
+	DBprintk(("pmc[%d]=0x%lx, mask=0x%lx, reset=0x%lx, val=0x%lx\n", 
+		  cnum, ival, PMC_RSVD_MASK(cnum), PMC_DFL_VAL(cnum), *val)); 
+	return 0;
+}
+
 static int
 pfm_mck_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs)
 {
@@ -65,6 +100,9 @@
 	int ret = 0, check_case1 = 0;
 	unsigned long val8 = 0, val14 = 0, val13 = 0;
 
+	/* first preserve the reserved fields */
+	pfm_mck_reserved(task, cnum, val, regs);
+
 	/*
 	 * we must clear the debug registers if any pmc13.ena_dbrpX bit is enabled 
 	 * before they are written (fl_using_dbreg==0) to avoid picking up stale information. 
@@ -105,8 +143,11 @@
 		case  8: val8 = *val;
 			 val13 = th->pmc[13];
 			 val14 = th->pmc[14];
+			 *val |= 1UL << 2; /* bit 2 must always be 1 */
 			 check_case1 = 1;
 			 break;
+		case  9: *val |= 1UL << 2; /* bit 2 must always be 1 */
+			 break;
 		case 13: val8  = th->pmc[8];
 			 val13 = *val;
 			 val14 = th->pmc[14];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/process.c linux-2.4.21/arch/ia64/kernel/process.c
--- linux-2.4.20/arch/ia64/kernel/process.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/process.c	2002-12-18 18:58:08.000000000 +0000
@@ -168,10 +168,8 @@
 	if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0)
 		pfm_save_regs(task);
 
-# ifdef CONFIG_SMP
 	if (local_cpu_data->pfm_syst_wide)
 		pfm_syst_wide_update_task(task, 0);
-# endif
 #endif
 
 #ifdef CONFIG_IA32_SUPPORT
@@ -190,10 +188,8 @@
 	if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0)
 		pfm_load_regs(task);
 
-# ifdef CONFIG_SMP
 	if (local_cpu_data->pfm_syst_wide)
 		pfm_syst_wide_update_task(task, 1);
-# endif
 #endif
 
 #ifdef CONFIG_IA32_SUPPORT
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/ptrace.c linux-2.4.21/arch/ia64/kernel/ptrace.c
--- linux-2.4.20/arch/ia64/kernel/ptrace.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/ptrace.c	2002-12-18 18:58:08.000000000 +0000
@@ -10,6 +10,7 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
@@ -459,6 +460,60 @@
 	pt->loadrs = 0;
 }
 
+static inline void
+sync_user_rbs_one_thread (struct task_struct *p, int make_writable)
+{
+	struct switch_stack *sw;
+	unsigned long urbs_end;
+	struct pt_regs *pt;
+
+	sw = (struct switch_stack *) (p->thread.ksp + 16);
+	pt = ia64_task_regs(p);
+	urbs_end = ia64_get_user_rbs_end(p, pt, NULL);
+	ia64_sync_user_rbs(p, sw, pt->ar_bspstore, urbs_end);
+	if (make_writable)
+		user_flushrs(p, pt);
+}
+
+struct task_list {
+	struct task_list *next;
+	struct task_struct *task;
+};
+
+#ifdef CONFIG_SMP
+
+static inline void
+collect_task (struct task_list **listp, struct task_struct *p, int make_writable)
+{
+	struct task_list *e;
+
+	e = kmalloc(sizeof(*e), GFP_KERNEL);
+	if (!e)
+		/* oops, can't collect more: finish at least what we collected so far... */
+		return;
+
+	get_task_struct(p);
+	e->task = p;
+	e->next = *listp;
+	*listp = e;
+}
+
+static inline struct task_list *
+finish_task (struct task_list *list, int make_writable)
+{
+	struct task_list *next = list->next;
+
+	sync_user_rbs_one_thread(list->task, make_writable);
+	free_task_struct(list->task);
+	kfree(list);
+	return next;
+}
+
+#else
+# define collect_task(list, p, make_writable)	sync_user_rbs_one_thread(p, make_writable)
+# define finish_task(list, make_writable)	(NULL)
+#endif
+
 /*
  * Synchronize the RSE backing store of CHILD and all tasks that share the address space
  * with it.  CHILD_URBS_END is the address of the end of the register backing store of
@@ -472,7 +527,6 @@
 threads_sync_user_rbs (struct task_struct *child, unsigned long child_urbs_end, int make_writable)
 {
 	struct switch_stack *sw;
-	unsigned long urbs_end;
 	struct task_struct *p;
 	struct mm_struct *mm;
 	struct pt_regs *pt;
@@ -492,20 +546,27 @@
 		if (make_writable)
 			user_flushrs(child, pt);
 	} else {
+		/*
+		 * Note: we can't call ia64_sync_user_rbs() while holding the
+		 * tasklist_lock because that may cause a dead-lock: ia64_sync_user_rbs()
+		 * may indirectly call tlb_flush_all(), which triggers an IPI.
+		 * Furthermore, tasklist_lock is acquired by fork() with interrupts
+		 * disabled, so with the right timing, the IPI never completes, hence
+		 * tasklist_lock never gets released, hence fork() never completes...
+		 */
+		struct task_list *list = NULL;
+
 		read_lock(&tasklist_lock);
 		{
 			for_each_task(p) {
-				if (p->mm == mm && p->state != TASK_RUNNING) {
-					sw = (struct switch_stack *) (p->thread.ksp + 16);
-					pt = ia64_task_regs(p);
-					urbs_end = ia64_get_user_rbs_end(p, pt, NULL);
-					ia64_sync_user_rbs(p, sw, pt->ar_bspstore, urbs_end);
-					if (make_writable)
-						user_flushrs(p, pt);
-				}
+				if (p->mm == mm && p->state != TASK_RUNNING)
+					collect_task(&list, p, make_writable);
 			}
 		}
 		read_unlock(&tasklist_lock);
+
+		while (list)
+			list = finish_task(list, make_writable);
 	}
 	child->thread.flags |= IA64_THREAD_KRBS_SYNCED;	/* set the flag in the child thread only */
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/signal.c linux-2.4.21/arch/ia64/kernel/signal.c
--- linux-2.4.20/arch/ia64/kernel/signal.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/signal.c	2002-12-18 18:58:09.000000000 +0000
@@ -41,6 +41,16 @@
 
 extern long ia64_do_signal (sigset_t *, struct sigscratch *, long);	/* forward decl */
 
+register double f16 asm ("f16"); register double f17 asm ("f17");
+register double f18 asm ("f18"); register double f19 asm ("f19");
+register double f20 asm ("f20"); register double f21 asm ("f21");
+register double f22 asm ("f22"); register double f23 asm ("f23");
+
+register double f24 asm ("f24"); register double f25 asm ("f25");
+register double f26 asm ("f26"); register double f27 asm ("f27");
+register double f28 asm ("f28"); register double f29 asm ("f29");
+register double f30 asm ("f30"); register double f31 asm ("f31");
+
 long
 ia64_rt_sigsuspend (sigset_t *uset, size_t sigsetsize, struct sigscratch *scr)
 {
@@ -354,6 +364,15 @@
 	return err;
 }
 
+/*
+ * Check whether the register-backing store is already on the signal stack.
+ */
+static inline int
+rbs_on_sig_stack (unsigned long bsp)
+{
+	return (bsp - current->sas_ss_sp < current->sas_ss_size);
+}
+
 static long
 setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set,
 	     struct sigscratch *scr)
@@ -366,10 +385,16 @@
 
 	frame = (void *) scr->pt.r12;
 	tramp_addr = GATE_ADDR + (ia64_sigtramp - __start_gate_section);
-	if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && !on_sig_stack((unsigned long) frame)) {
-		new_rbs  = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1);
+	if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags((unsigned long) frame) == 0) {
 		frame = (void *) ((current->sas_ss_sp + current->sas_ss_size)
 				  & ~(STACK_ALIGN - 1));
+  		/*
+		 * We need to check for the register stack being on the signal stack
+		 * separately, because it's switched separately (memory stack is switched
+		 * in the kernel, register stack is switched in the signal trampoline).
+  		 */
+		if (!rbs_on_sig_stack(scr->pt.ar_bspstore))
+			new_rbs  = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1);
 	}
 	frame = (void *) frame - ((sizeof(*frame) + STACK_ALIGN - 1) & ~(STACK_ALIGN - 1));
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/smp.c linux-2.4.21/arch/ia64/kernel/smp.c
--- linux-2.4.20/arch/ia64/kernel/smp.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/smp.c	2002-12-18 18:58:12.000000000 +0000
@@ -188,8 +188,20 @@
 void
 smp_flush_tlb_all (void)
 {
-	smp_call_function ((void (*)(void *))__flush_tlb_all,0,1,1);
-	__flush_tlb_all();
+	smp_call_function((void (*)(void *))local_flush_tlb_all, 0, 1, 1);
+	local_flush_tlb_all();
+}
+
+void
+smp_flush_tlb_mm (struct mm_struct *mm)
+{
+	local_flush_tlb_mm(mm);
+
+	/* this happens for the common case of a single-threaded fork():  */
+	if (likely(mm == current->active_mm && atomic_read(&mm->mm_users) == 1))
+		return;
+
+	smp_call_function((void (*)(void *))local_flush_tlb_mm, mm, 1, 1);
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/smpboot.c linux-2.4.21/arch/ia64/kernel/smpboot.c
--- linux-2.4.20/arch/ia64/kernel/smpboot.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/smpboot.c	2002-12-18 18:58:05.000000000 +0000
@@ -321,7 +321,7 @@
 	extern void ia64_init_itm(void);
 
 #ifdef CONFIG_PERFMON
-	extern void perfmon_init_percpu(void);
+	extern void pfm_init_percpu(void);
 #endif
 
 	cpuid = smp_processor_id();
@@ -356,7 +356,7 @@
 #endif
 
 #ifdef CONFIG_PERFMON
-	perfmon_init_percpu();
+	pfm_init_percpu();
 #endif
 
 	local_irq_enable();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/sys_ia64.c linux-2.4.21/arch/ia64/kernel/sys_ia64.c
--- linux-2.4.20/arch/ia64/kernel/sys_ia64.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/sys_ia64.c	2002-12-18 18:58:01.000000000 +0000
@@ -253,6 +253,29 @@
 	return addr;
 }
 
+asmlinkage unsigned long
+ia64_mremap (unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags,
+	     unsigned long new_addr)
+{
+	extern unsigned long do_mremap (unsigned long addr,
+					unsigned long old_len,
+					unsigned long new_len,
+					unsigned long flags,
+					unsigned long new_addr);
+
+	down_write(&current->mm->mmap_sem);
+	{
+		addr = do_mremap(addr, old_len, new_len, flags, new_addr);
+	}
+	up_write(&current->mm->mmap_sem);
+
+	if (IS_ERR((void *) addr))
+		return addr;
+
+	force_successful_syscall_return();
+	return addr;
+}
+
 asmlinkage long
 sys_vm86 (long arg0, long arg1, long arg2, long arg3)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/traps.c linux-2.4.21/arch/ia64/kernel/traps.c
--- linux-2.4.20/arch/ia64/kernel/traps.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/traps.c	2002-12-18 18:58:11.000000000 +0000
@@ -142,7 +142,8 @@
 	siginfo.si_isr = 0;
 
 	switch (break_num) {
-	      case 0: /* unknown error */
+	      case 0: /* unknown error (used by GCC for __builtin_abort()) */
+		die_if_kernel("Bad break", regs, break_num);
 		sig = SIGILL; code = ILL_ILLOPC;
 		break;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/unaligned.c linux-2.4.21/arch/ia64/kernel/unaligned.c
--- linux-2.4.20/arch/ia64/kernel/unaligned.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/kernel/unaligned.c	2002-12-18 18:58:11.000000000 +0000
@@ -5,6 +5,10 @@
  *	Stephane Eranian <eranian@hpl.hp.com>
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
+ * 2002/12/09   Fix rotating register handling (off-by-1 error, missing fr-rotation).  Fix
+ *		get_rse_reg() to not leak kernel bits to user-level (reading an out-of-frame
+ *		stacked register returns an undefined value; it does NOT trigger a
+ *		"rsvd register fault").
  * 2001/10/11	Fix unaligned access to rotating registers in s/w pipelined loops.
  * 2001/08/13	Correct size of extended floats (float_fsz) from 16 to 10 bytes.
  * 2001/01/17	Add support emulation of unaligned kernel accesses.
@@ -275,6 +279,15 @@
 #	undef F
 }
 
+static inline unsigned long
+rotate_reg (unsigned long sor, unsigned long rrb, unsigned long reg)
+{
+	reg += rrb;
+	if (reg >= sor)
+		reg -= sor;
+	return reg;
+}
+
 static void
 set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, int nat)
 {
@@ -286,26 +299,22 @@
 	long sof = (regs->cr_ifs) & 0x7f;
 	long sor = 8 * ((regs->cr_ifs >> 14) & 0xf);
 	long rrb_gr = (regs->cr_ifs >> 18) & 0x7f;
-	long ridx;
-
-	if ((r1 - 32) > sor)
-		ridx = -sof + (r1 - 32);
-	else if ((r1 - 32) < (sor - rrb_gr))
-		ridx = -sof + (r1 - 32) + rrb_gr;
-	else
-		ridx = -sof + (r1 - 32) - (sor - rrb_gr);
-
-	DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n",
-	       r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx);
+	long ridx = r1 - 32;
 
-	if ((r1 - 32) >= sof) {
+	if (ridx >= sof) {
 		/* this should never happen, as the "rsvd register fault" has higher priority */
 		DPRINT("ignoring write to r%lu; only %lu registers are allocated!\n", r1, sof);
 		return;
 	}
 
+	if (ridx < sor)
+		ridx = rotate_reg(sor, rrb_gr, ridx);
+
+	DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n",
+	       r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx);
+
 	on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore);
-	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, ridx);
+	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + ridx);
 	if (addr >= kbs) {
 		/* the register is on the kernel backing store: easy... */
 		rnat_addr = ia64_rse_rnat_addr(addr);
@@ -333,7 +342,7 @@
 	bspstore = (unsigned long *)regs->ar_bspstore;
 	ubs_end = ia64_rse_skip_regs(bspstore, on_kbs);
 	bsp     = ia64_rse_skip_regs(ubs_end, -sof);
-	addr    = ia64_rse_skip_regs(bsp, ridx + sof);
+	addr    = ia64_rse_skip_regs(bsp, ridx);
 
 	DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr);
 
@@ -367,26 +376,22 @@
 	long sof = (regs->cr_ifs) & 0x7f;
 	long sor = 8 * ((regs->cr_ifs >> 14) & 0xf);
 	long rrb_gr = (regs->cr_ifs >> 18) & 0x7f;
-	long ridx;
+	long ridx = r1 - 32;
 
-	if ((r1 - 32) > sor)
-		ridx = -sof + (r1 - 32);
-	else if ((r1 - 32) < (sor - rrb_gr))
-		ridx = -sof + (r1 - 32) + rrb_gr;
-	else
-		ridx = -sof + (r1 - 32) - (sor - rrb_gr);
+	if (ridx >= sof) {
+		/* read of out-of-frame register returns an undefined value; 0 in our case.  */
+		DPRINT("ignoring read from r%lu; only %lu registers are allocated!\n", r1, sof);
+		goto fail;
+	}
+
+	if (ridx < sor)
+		ridx = rotate_reg(sor, rrb_gr, ridx);
 
 	DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n",
 	       r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx);
 
-	if ((r1 - 32) >= sof) {
-		/* this should never happen, as the "rsvd register fault" has higher priority */
-		DPRINT("ignoring read from r%lu; only %lu registers are allocated!\n", r1, sof);
-		return;
-	}
-
 	on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore);
-	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, ridx);
+	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + ridx);
 	if (addr >= kbs) {
 		/* the register is on the kernel backing store: easy... */
 		*val = *addr;
@@ -406,13 +411,13 @@
 	 */
 	if (regs->r12 >= TASK_SIZE) {
 		DPRINT("ignoring kernel read of r%lu; register isn't on the RBS!", r1);
-		return;
+		goto fail;
 	}
 
 	bspstore = (unsigned long *)regs->ar_bspstore;
 	ubs_end = ia64_rse_skip_regs(bspstore, on_kbs);
 	bsp     = ia64_rse_skip_regs(ubs_end, -sof);
-	addr    = ia64_rse_skip_regs(bsp, ridx + sof);
+	addr    = ia64_rse_skip_regs(bsp, ridx);
 
 	DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr);
 
@@ -427,6 +432,13 @@
 		ia64_peek(current, sw, (unsigned long) ubs_end, (unsigned long) rnat_addr, &rnats);
 		*nat = (rnats & nat_mask) != 0;
 	}
+	return;
+
+  fail:
+	*val = 0;
+	if (nat)
+		*nat = 0;
+	return;
 }
 
 
@@ -485,7 +497,16 @@
 	DPRINT("*0x%lx=0x%lx NaT=%d new unat: %p=%lx\n", addr, val, nat, (void *) unat,*unat);
 }
 
-#define IA64_FPH_OFFS(r) (r - IA64_FIRST_ROTATING_FR)
+/*
+ * Return the (rotated) index for floating point register REGNUM (REGNUM must be in the
+ * range from 32-127, result is in the range from 0-95.
+ */
+static inline unsigned long
+fph_index (struct pt_regs *regs, long regnum)
+{
+	unsigned long rrb_fr = (regs->cr_ifs >> 25) & 0x7f;
+	return rotate_reg(96, rrb_fr, (regnum - IA64_FIRST_ROTATING_FR));
+}
 
 static void
 setfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs)
@@ -506,7 +527,7 @@
 	 */
 	if (regnum >= IA64_FIRST_ROTATING_FR) {
 		ia64_sync_fph(current);
-		current->thread.fph[IA64_FPH_OFFS(regnum)] = *fpval;
+		current->thread.fph[fph_index(regs, regnum)] = *fpval;
 	} else {
 		/*
 		 * pt_regs or switch_stack ?
@@ -565,7 +586,7 @@
 	 */
 	if (regnum >= IA64_FIRST_ROTATING_FR) {
 		ia64_flush_fph(current);
-		*fpval = current->thread.fph[IA64_FPH_OFFS(regnum)];
+		*fpval = current->thread.fph[fph_index(regs, regnum)];
 	} else {
 		/*
 		 * f0 = 0.0, f1= 1.0. Those registers are constant and are thus
@@ -650,8 +671,8 @@
 	 * just in case.
 	 */
 	if (ld.x6_op == 1 || ld.x6_op == 3) {
-		printk("%s %s: register update on speculative load, error\n", KERN_ERR, __FUNCTION__);
-		die_if_kernel("unaligned reference on specualtive load with register update\n",
+		printk(KERN_ERR "%s: register update on speculative load, error\n", __FUNCTION__);
+		die_if_kernel("unaligned reference on speculative load with register update\n",
 			      regs, 30);
 	}
 
@@ -1080,8 +1101,8 @@
 		 * For this reason we keep this sanity check
 		 */
 		if (ld.x6_op == 1 || ld.x6_op == 3)
-			printk("%s %s: register update on speculative load pair, "
-			       "error\n",KERN_ERR, __FUNCTION__);
+			printk(KERN_ERR "%s: register update on speculative load pair, error\n",
+			       __FUNCTION__);
 
 		setreg(ld.r3, ifa, 0, regs);
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/lib/Makefile linux-2.4.21/arch/ia64/lib/Makefile
--- linux-2.4.20/arch/ia64/lib/Makefile	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/lib/Makefile	2002-12-18 18:58:07.000000000 +0000
@@ -11,7 +11,7 @@
 
 obj-y := __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o					\
 	__divdi3.o __udivdi3.o __moddi3.o __umoddi3.o					\
-	checksum.o clear_page.o csum_partial_copy.o					\
+	carta_random.o checksum.o clear_page.o csum_partial_copy.o					\
 	clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o			\
 	flush.o ip_fast_csum.o io.o do_csum.o						\
 	memset.o strlen.o swiotlb.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/lib/carta_random.S linux-2.4.21/arch/ia64/lib/carta_random.S
--- linux-2.4.20/arch/ia64/lib/carta_random.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/arch/ia64/lib/carta_random.S	2002-12-18 18:58:12.000000000 +0000
@@ -0,0 +1,54 @@
+/*
+ * Fast, simple, yet decent quality random number generator based on
+ * a paper by David G. Carta ("Two Fast Implementations of the
+ * `Minimal Standard' Random Number Generator," Communications of the
+ * ACM, January, 1990).
+ *
+ * Copyright (C) 2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ */
+
+#include <asm/asmmacro.h>
+
+#define a	r2
+#define m	r3
+#define lo	r8
+#define hi	r9
+#define t0	r16
+#define t1	r17
+#define	seed	r32
+
+GLOBAL_ENTRY(carta_random32)
+	movl	a = (16807 << 16) | 16807
+	;;
+	pmpyshr2.u t0 = a, seed, 0
+	pmpyshr2.u t1 = a, seed, 16
+	;;
+	unpack2.l t0 = t1, t0
+	dep	m = -1, r0, 0, 31
+	;;
+	zxt4	lo = t0
+	shr.u	hi = t0, 32
+	;;
+	dep	t0 = 0, hi, 15, 49	// t0 = (hi & 0x7fff)
+	;;
+	shl	t0 = t0, 16		// t0 = (hi & 0x7fff) << 16
+	shr	t1 = hi, 15		// t1 = (hi >> 15)
+	;;
+	add	lo = lo, t0
+	;;
+	cmp.gtu	p6, p0 = lo, m
+	;;
+(p6)	and	lo = lo, m
+	;;
+(p6)	add	lo = 1, lo
+	;;
+	add	lo = lo, t1
+	;;
+	cmp.gtu p6, p0 = lo, m
+	;;
+(p6)	and	lo = lo, m
+	;;
+(p6)	add	lo = 1, lo
+	br.ret.sptk.many rp
+END(carta_random32)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/lib/memcpy_mck.S linux-2.4.21/arch/ia64/lib/memcpy_mck.S
--- linux-2.4.20/arch/ia64/lib/memcpy_mck.S	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/lib/memcpy_mck.S	2002-12-18 18:58:05.000000000 +0000
@@ -6,7 +6,10 @@
  *	in1:	source address
  *	in2:	number of bytes to copy
  * Output:
- * 	0 if success, or number of byte NOT copied if error occurred.
+ *	for bcopy:     return nothing
+ *	for memcpy:    return dest
+ * 	for copy_user: 0 if success,
+ *		       or number of bytes NOT copied if error occurred.
  *
  * Copyright (C) 2002 Intel Corp.
  * Copyright (C) 2002 Ken Chen <kenneth.w.chen@intel.com>
@@ -21,15 +24,6 @@
 # define EK(y,x...)	x
 #endif
 
-GLOBAL_ENTRY(bcopy)
-	.regstk 3,0,0,0
-	mov r8=in0
-	mov in0=in1
-	;;
-	mov in1=r8
-	;;
-END(bcopy)
-
 /* McKinley specific optimization */
 
 #define retval		r8
@@ -82,10 +76,19 @@
 #define in1		r33
 #define in2		r34
 
+GLOBAL_ENTRY(bcopy)
+	.regstk 3,0,0,0
+	mov r8=in0		// swap the src and dest arguments
+	mov in0=in1
+	;;
+	mov in1=r8
+	;;
+END(bcopy)			// fall through to memcpy
 GLOBAL_ENTRY(memcpy)
 	and	r28=0x7,in0
 	and	r29=0x7,in1
 	mov	f6=f0
+	mov	retval=in0
 	br.cond.sptk .common_code
 	;;
 END(memcpy)
@@ -97,7 +100,7 @@
 	mov	f6=f1
 	mov	saved_in0=in0	// save dest pointer
 	mov	saved_in1=in1	// save src pointer
-	mov	saved_in2=in2	// save len
+	mov	retval=r0	// initialize return value
 	;;
 .common_code:
 	cmp.gt	p15,p0=8,in2	// check for small size
@@ -105,7 +108,7 @@
 	cmp.ne	p14,p0=0,r29	// check src alignment
 	add	src0=0,in1
 	sub	r30=8,r28	// for .align_dest
-	mov	retval=r0	// initialize return value
+	mov	saved_in2=in2	// save len
 	;;
 	add	dst0=0,in0
 	add	dst1=1,in0	// dest odd index
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/lib/swiotlb.c linux-2.4.21/arch/ia64/lib/swiotlb.c
--- linux-2.4.20/arch/ia64/lib/swiotlb.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/lib/swiotlb.c	2002-12-18 18:58:10.000000000 +0000
@@ -351,7 +351,7 @@
 	pg_addr = PAGE_ALIGN((unsigned long) addr);
 	end = (unsigned long) addr + size;
 	while (pg_addr + PAGE_SIZE <= end) {
-		struct page *page = virt_to_page(pg_addr);
+		struct page *page = virt_to_page((void *)pg_addr);
 		set_bit(PG_arch_1, &page->flags);
 		pg_addr += PAGE_SIZE;
 	}
@@ -417,23 +417,23 @@
 int
 swiotlb_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
 {
-	void *addr;
 	int i;
 
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++) {
-		sg->orig_address = SG_ENT_VIRT_ADDRESS(sg);
-		if ((SG_ENT_PHYS_ADDRESS(sg) & ~hwdev->dma_mask) != 0) {
-			addr = map_single(hwdev, sg->orig_address, sg->length, direction);
-			if (sg->address)
-				sg->address = addr;
-			else {
-				sg->page = virt_to_page(addr);
-				sg->offset = (u64) addr & ~PAGE_MASK;
-			}
-		}
+		void * virt_address = SG_ENT_VIRT_ADDRESS(sg);
+		unsigned long phys_address = virt_to_phys(virt_address);
+
+		sg->dma_length = sg->length;
+		if (phys_address & ~hwdev->dma_mask)
+			sg->dma_address = virt_to_phys(map_single(hwdev,
+			                                          virt_address,
+			                                          sg->length,
+			                                          direction));
+		else
+			sg->dma_address = phys_address;
 	}
 	return nelems;
 }
@@ -451,14 +451,9 @@
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++)
-		if (sg->orig_address != SG_ENT_VIRT_ADDRESS(sg)) {
-			unmap_single(hwdev, SG_ENT_VIRT_ADDRESS(sg), sg->length, direction);
-			if (sg->address)
-				sg->address = sg->orig_address;
-			else {
-				sg->page = virt_to_page(sg->orig_address);
-				sg->offset = (u64) sg->orig_address & ~PAGE_MASK;
-			}
+		if (sg->dma_address != virt_to_phys(SG_ENT_VIRT_ADDRESS(sg))) {
+			unmap_single(hwdev, phys_to_virt(sg->dma_address),
+			             sg->dma_length, direction);
 		} else if (direction == PCI_DMA_FROMDEVICE)
 			mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->length);
 }
@@ -479,14 +474,9 @@
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++)
-		if (sg->orig_address != SG_ENT_VIRT_ADDRESS(sg))
-			sync_single(hwdev, SG_ENT_VIRT_ADDRESS(sg), sg->length, direction);
-}
-
-unsigned long
-swiotlb_dma_address (struct scatterlist *sg)
-{
-	return SG_ENT_PHYS_ADDRESS(sg);
+		if (sg->dma_address != virt_to_phys(SG_ENT_VIRT_ADDRESS(sg)))
+			sync_single(hwdev, phys_to_virt(sg->dma_address),
+			            sg->dma_length, direction);
 }
 
 /*
@@ -507,7 +497,6 @@
 EXPORT_SYMBOL(swiotlb_unmap_sg);
 EXPORT_SYMBOL(swiotlb_sync_single);
 EXPORT_SYMBOL(swiotlb_sync_sg);
-EXPORT_SYMBOL(swiotlb_dma_address);
 EXPORT_SYMBOL(swiotlb_alloc_consistent);
 EXPORT_SYMBOL(swiotlb_free_consistent);
 EXPORT_SYMBOL(swiotlb_pci_dma_supported);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/mm/Makefile linux-2.4.21/arch/ia64/mm/Makefile
--- linux-2.4.20/arch/ia64/mm/Makefile	2001-01-04 20:50:17.000000000 +0000
+++ linux-2.4.21/arch/ia64/mm/Makefile	2002-12-18 18:58:06.000000000 +0000
@@ -9,6 +9,8 @@
 
 O_TARGET := mm.o
 
+export-objs := init.o
+
 obj-y	 := init.o fault.o tlb.o extable.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/mm/fault.c linux-2.4.21/arch/ia64/mm/fault.c
--- linux-2.4.20/arch/ia64/mm/fault.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/mm/fault.c	2002-12-18 18:58:11.000000000 +0000
@@ -58,7 +58,6 @@
 	if (in_interrupt() || !mm)
 		goto no_context;
 
-#ifdef CONFIG_VIRTUAL_MEM_MAP
 	/*
 	 * If fault is in region 5 and we are in the kernel, we may already
          * have the mmap_sem (VALID_PAGE macro is called during mmap). There
@@ -67,7 +66,6 @@
   	 */
 	if ((REGION_NUMBER(address) == 5) && !user_mode(regs))
 		goto bad_area_no_up;
-#endif
 
 	down_read(&mm->mmap_sem);
 
@@ -148,9 +146,7 @@
 
   bad_area:
 	up_read(&mm->mmap_sem);
-#ifdef CONFIG_VIRTUAL_MEM_MAP
   bad_area_no_up:
-#endif
 	if ((isr & IA64_ISR_SP)
 	    || ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH))
 	{
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/mm/init.c linux-2.4.21/arch/ia64/mm/init.c
--- linux-2.4.20/arch/ia64/mm/init.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/mm/init.c	2002-12-18 18:58:07.000000000 +0000
@@ -5,6 +5,7 @@
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 
@@ -35,15 +36,14 @@
 extern void ia64_tlb_init (void);
 
 unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL;
+#define LARGE_GAP 0x40000000 /* Use virtual mem map if a hole is > than this */
 
 static unsigned long totalram_pages;
 
-#ifdef CONFIG_VIRTUAL_MEM_MAP
 unsigned long vmalloc_end = VMALLOC_END_INIT;
 
 static struct page *vmem_map;
 static unsigned long num_dma_physpages;
-#endif
 
 int
 do_check_pgt_cache (int low, int high)
@@ -114,8 +114,8 @@
 
 	addr = (unsigned long) &__init_begin;
 	for (; addr < (unsigned long) &__init_end; addr += PAGE_SIZE) {
-		clear_bit(PG_reserved, &virt_to_page(addr)->flags);
-		set_page_count(virt_to_page(addr), 1);
+		clear_bit(PG_reserved, &virt_to_page((void *)addr)->flags);
+		set_page_count(virt_to_page((void *)addr), 1);
 		free_page(addr);
 		++totalram_pages;
 	}
@@ -164,10 +164,10 @@
 		printk(KERN_INFO "Freeing initrd memory: %ldkB freed\n", (end - start) >> 10);
 
 	for (; start < end; start += PAGE_SIZE) {
-		if (!VALID_PAGE(virt_to_page(start)))
+		if (!VALID_PAGE(virt_to_page((void *)start)))
 			continue;
-		clear_bit(PG_reserved, &virt_to_page(start)->flags);
-		set_page_count(virt_to_page(start), 1);
+		clear_bit(PG_reserved, &virt_to_page((void *)start)->flags);
+		set_page_count(virt_to_page((void *)start), 1);
 		free_page(start);
 		++totalram_pages;
 	}
@@ -357,10 +357,6 @@
 	ia64_tlb_init();
 }
 
-#ifdef CONFIG_VIRTUAL_MEM_MAP
-
-#include <asm/pgtable.h>
-
 static int
 create_mem_map_page_table (u64 start, u64 end, void *arg)
 {
@@ -413,8 +409,8 @@
 
 	/* Should we use platform_map_nr here? */
 
-	map_start = vmem_map + MAP_NR_DENSE(start);
-	map_end   = vmem_map + MAP_NR_DENSE(end);
+	map_start = mem_map + MAP_NR_DENSE(start);
+	map_end   = mem_map + MAP_NR_DENSE(end);
 
 	if (map_start < args->start)
 		map_start = args->start;
@@ -444,15 +440,19 @@
 arch_memmap_init (memmap_init_callback_t *memmap_init, struct page *start,
 	struct page *end, int zone, unsigned long start_paddr, int highmem)
 {
-	struct memmap_init_callback_data args;
+	if (!vmem_map) 
+		memmap_init(start,end,zone,page_to_phys(start),highmem);
+	else {
+		struct memmap_init_callback_data args;
 
-	args.memmap_init = memmap_init;
-	args.start = start;
-	args.end = end;
-	args.zone = zone;
-	args.highmem = highmem;
+		args.memmap_init = memmap_init;
+		args.start = start;
+		args.end = end;
+		args.zone = zone;
+		args.highmem = highmem;
 
-	efi_memmap_walk(virtual_memmap_init, &args);
+		efi_memmap_walk(virtual_memmap_init, &args);
+	}
 
 	return page_to_phys(end);
 }
@@ -475,8 +475,6 @@
 	return __get_user(byte, (char *) page) == 0;
 }
 
-#endif /* CONFIG_VIRTUAL_MEM_MAP */
-
 static int
 count_pages (u64 start, u64 end, void *arg)
 {
@@ -486,47 +484,75 @@
 	return 0;
 }
 
+#ifndef CONFIG_DISCONTIGMEM
+static int
+find_largest_hole(u64 start, u64 end, void *arg)
+{
+	u64 *max_gap = arg;
+	static u64 last_end = PAGE_OFFSET;
+
+	/* NOTE: this algorithm assumes efi memmap table is ordered */
+
+	if (*max_gap < (start - last_end))
+		*max_gap = start - last_end;
+	last_end = end;
+	return 0;
+}
+#endif
+
 /*
  * Set up the page tables.
  */
 void
 paging_init (void)
 {
-	unsigned long max_dma, zones_size[MAX_NR_ZONES];
+	unsigned long max_dma;
+	unsigned long zones_size[MAX_NR_ZONES];
+	unsigned long zholes_size[MAX_NR_ZONES];
+#ifndef CONFIG_DISCONTIGMEM
+	unsigned long max_gap;
+#endif
 
 	/* initialize mem_map[] */
 
 	memset(zones_size, 0, sizeof(zones_size));
+	memset(zholes_size, 0, sizeof(zholes_size));
 
 	num_physpages = 0;
 	efi_memmap_walk(count_pages, &num_physpages);
 
-	max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+	num_dma_physpages = 0;
+	efi_memmap_walk(count_dma_pages, &num_dma_physpages);
 
-#ifdef CONFIG_VIRTUAL_MEM_MAP
-	{
-		unsigned long zholes_size[MAX_NR_ZONES];
-		unsigned long map_size;
+	max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
 
-		memset(zholes_size, 0, sizeof(zholes_size));
+	if (max_low_pfn < max_dma) {
+		zones_size[ZONE_DMA] = max_low_pfn;
+		zholes_size[ZONE_DMA] = max_low_pfn - num_dma_physpages;
+	} else {
+		zones_size[ZONE_DMA] = max_dma;
+		zholes_size[ZONE_DMA] = max_dma - num_dma_physpages;
+		if (num_physpages > num_dma_physpages) {
+			zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
+			zholes_size[ZONE_NORMAL] = (max_low_pfn - max_dma)
+					- (num_physpages - num_dma_physpages);
+		}
+	}
 
-		num_dma_physpages = 0;
-		efi_memmap_walk(count_dma_pages, &num_dma_physpages);
+#ifdef CONFIG_DISCONTIGMEM
+	free_area_init_node(0, NULL, NULL, zones_size, 0, zholes_size);
+#else
+	max_gap = 0;
+	efi_memmap_walk(find_largest_hole, (u64 *)&max_gap);
 
-		if (max_low_pfn < max_dma) {
-			zones_size[ZONE_DMA] = max_low_pfn;
-			zholes_size[ZONE_DMA] = max_low_pfn - num_dma_physpages;
-		} else {
-			zones_size[ZONE_DMA] = max_dma;
-			zholes_size[ZONE_DMA] = max_dma - num_dma_physpages;
-			if (num_physpages > num_dma_physpages) {
-				zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
-				zholes_size[ZONE_NORMAL] = ((max_low_pfn - max_dma)
-							    - (num_physpages - num_dma_physpages));
-			}
-		}
+	if (max_gap < LARGE_GAP) {
+		vmem_map = (struct page *)0;
+		free_area_init_node(0, NULL, NULL, zones_size, 0, zholes_size);
+	}
+	else {
+		unsigned long map_size;
 
-		/* allocate virtual mem_map: */
+		/* allocate virtual mem_map */
 
 		map_size = PAGE_ALIGN(max_low_pfn*sizeof(struct page));
 		vmalloc_end -= map_size;
@@ -536,15 +562,7 @@
 		free_area_init_node(0, NULL, vmem_map, zones_size, 0, zholes_size);
 		printk("Virtual mem_map starts at 0x%p\n", mem_map);
 	}
-#else /* !CONFIG_VIRTUAL_MEM_MAP */
-	if (max_low_pfn < max_dma)
-		zones_size[ZONE_DMA] = max_low_pfn;
-	else {
-		zones_size[ZONE_DMA] = max_dma;
-		zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
-	}
-	free_area_init(zones_size);
-#endif /* !CONFIG_VIRTUAL_MEM_MAP */
+#endif
 }
 
 static int
@@ -554,7 +572,7 @@
 	unsigned long *count = arg;
 	struct page *pg;
 
-	for (pg = virt_to_page(start); pg < virt_to_page(end); ++pg)
+	for (pg = virt_to_page((void *)start); pg < virt_to_page((void *)end); ++pg)
 		if (PageReserved(pg))
 			++num_reserved;
 	*count += num_reserved;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/mm/tlb.c linux-2.4.21/arch/ia64/mm/tlb.c
--- linux-2.4.20/arch/ia64/mm/tlb.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/mm/tlb.c	2002-12-18 18:58:10.000000000 +0000
@@ -100,7 +100,7 @@
 }
 
 void
-__flush_tlb_all (void)
+local_flush_tlb_all (void)
 {
 	unsigned long i, j, flags, count0, count1, stride0, stride1, addr;
 
@@ -185,5 +185,5 @@
 	local_cpu_data->ptce_stride[0] = ptce_info.stride[0];
 	local_cpu_data->ptce_stride[1] = ptce_info.stride[1];
 
-	__flush_tlb_all();		/* nuke left overs from bootstrapping... */
+	local_flush_tlb_all();		/* nuke left overs from bootstrapping... */
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/pci_dma.c linux-2.4.21/arch/ia64/sn/io/pci_dma.c
--- linux-2.4.20/arch/ia64/sn/io/pci_dma.c	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/sn/io/pci_dma.c	2002-12-18 18:58:05.000000000 +0000
@@ -309,7 +309,6 @@
 
 	int i;
 	devfs_handle_t vhdl;
-	dma_addr_t dma_addr;
 	unsigned long phys_addr;
 	struct sn_device_sysdata *device_sysdata;
 	pciio_dmamap_t dma_map;
@@ -333,34 +332,28 @@
                    attempt to map scatterlists that they have
                    previously mapped.  we print a warning and
                    continue, but the driver should be fixed */
-		switch (((u64)sg->address) >> 60) {
-		case 0xa:
-		case 0xb:
 #ifdef DEBUG
+		if (sg->dma_address) {
 /* This needs to be cleaned up at some point. */
 			NAG("A PCI driver (for device at%8s) has attempted to "
 			    "map a scatterlist that was previously mapped at "
 			    "%p - this is currently being worked around.\n",
-			    hwdev->slot_name, (void *)sg->address);
+			    hwdev->slot_name, (void *)sg->dma_address);
+			phys_addr = (u64)sg->dma_address & TO_PHYS_MASK;
+		} else
 #endif
-			phys_addr = (u64)sg->address & TO_PHYS_MASK;
-			break;
-		default: /* not previously mapped, get the phys. addr */
-			phys_addr = __pa(sg->address);
-			break;
-		}
-		sg->page = NULL;
-		dma_addr = 0;
+			phys_addr = __pa(sg->address ? sg->address :
+					page_address(sg->page) + offset);
 
 		/*
 		 * Handle the most common case: 64 bit cards.  This
 		 * call should always succeed.
 		 */
 		if (IS_PCIA64(hwdev)) {
-			dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr,
+			sg->dma_address = pciio_dmatrans_addr(vhdl, NULL, phys_addr,
 						       sg->length,
 						       DMA_DATA_FLAGS | PCIIO_DMA_A64 );
-			sg->address = (char *)dma_addr;
+			sg->dma_length = sg->length;
 			continue;
 		}
 
@@ -368,16 +361,14 @@
 		 * Handle 32-63 bit cards via direct mapping
 		 */
 		if (IS_PCI32G(hwdev)) {
-			dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr,
-						       sg->length,
-						       DMA_DATA_FLAGS);
-			/*
-			 * See if we got a direct map entry
-			 */
-			if (dma_addr) {
-				sg->address = (char *)dma_addr;
+			sg->dma_address = pciio_dmatrans_addr(vhdl, NULL,
+								phys_addr,
+								sg->length,
+								DMA_DATA_FLAGS);
+			sg->dma_length = sg->length;
+
+			if (sg->dma_address)
 				continue;
-			}
 
 		}
 
@@ -393,10 +384,10 @@
 			       "anymore 32 bit page map entries.\n");
 			BUG();
 		}
-		dma_addr = pciio_dmamap_addr(dma_map, phys_addr, sg->length);
-		sg->address = (char *)dma_addr;
+		sg->dma_address = pciio_dmamap_addr(dma_map, phys_addr, sg->length);
+		sg->dma_length = sg->length;
+#warning BADBADBAD scsi retries will die since sglist is unmapped and reused.
 		sg->page = (char *)dma_map;
-		
 	}
 
 	return nents;
@@ -418,19 +409,20 @@
 sn_pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
 {
 	int i;
-	struct sn_dma_maps_s *sn_dma_map;
 
 	/* can't go anywhere w/o a direction in life */
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
 	for (i = 0; i < nents; i++, sg++)
+#warning need to derive sn_dma_map from sg->dma_address instead
 		if (sg->page) {
+			struct sn_dma_maps_s *sn_dma_map;
 			/*
 			 * We maintain the DMA Map pointer in sg->page if 
 			 * it is ever allocated.
 			 */
-			sg->address = 0;
+			sg->dma_address = 0;
 			sn_dma_map = (struct sn_dma_maps_s *)sg->page;
 			pciio_dmamap_done((pciio_dmamap_t)sn_dma_map);
 			pciio_dmamap_free((pciio_dmamap_t)sn_dma_map);
@@ -607,19 +599,6 @@
 }
 
 /**
- * sn_dma_address - get the DMA address for the first entry of a scatterlist
- * @sg: sg to look at
- *
- * Gets the DMA address for the scatterlist @sg.  Also known as
- * platform_dma_address() by the IA64 machvec code.
- */
-unsigned long
-sn_dma_address(struct scatterlist *sg)
-{
-	return ((unsigned long)sg->address);
-}
-
-/**
  * sn_dma_supported - test a DMA mask
  * @hwdev: device to test
  * @mask: DMA mask to test
@@ -645,6 +624,5 @@
 EXPORT_SYMBOL(sn_pci_unmap_sg);
 EXPORT_SYMBOL(sn_pci_alloc_consistent);
 EXPORT_SYMBOL(sn_pci_free_consistent);
-EXPORT_SYMBOL(sn_dma_address);
 EXPORT_SYMBOL(sn_pci_dma_supported);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c linux-2.4.21/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c	2002-12-18 18:58:01.000000000 +0000
@@ -41,7 +41,7 @@
 #ifdef LITTLE_ENDIAN
 #ifdef CONFIG_IA64_SGI_SN1
 /*
- * on sn-ia we need to twiddle the the addresses going out
+ * on sn-ia we need to twiddle the addresses going out
  * the pci bus because we use the unswizzled synergy space
  * (the alternative is to use the swizzled synergy space
  * and byte swap the data)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/setup.c linux-2.4.21/arch/ia64/sn/kernel/setup.c
--- linux-2.4.20/arch/ia64/sn/kernel/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/arch/ia64/sn/kernel/setup.c	2002-12-18 18:58:06.000000000 +0000
@@ -137,7 +137,7 @@
  * virt_to_page() (asm-ia64/page.h), among other things.
  */
 unsigned long
-sn_map_nr (unsigned long addr)
+sn_map_nr (void *addr)
 {
 	return MAP_NR_DISCONTIG(addr);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/vmlinux.lds.S linux-2.4.21/arch/ia64/vmlinux.lds.S
--- linux-2.4.20/arch/ia64/vmlinux.lds.S	2002-12-18 18:27:05.000000000 +0000
+++ linux-2.4.21/arch/ia64/vmlinux.lds.S	2002-12-18 18:58:05.000000000 +0000
@@ -13,6 +13,8 @@
   /DISCARD/ : {
 	*(.text.exit)
 	*(.data.exit)
+	*(*.text.exit)
+	*(*.data.exit)
 	*(.exitcall.exit)
 	*(.IA_64.unwind.text.exit)
 	*(.IA_64.unwind_info.text.exit)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/setup.c linux-2.4.21/arch/ppc/kernel/setup.c
--- linux-2.4.20/arch/ppc/kernel/setup.c	2002-12-18 18:27:06.000000000 +0000
+++ linux-2.4.21/arch/ppc/kernel/setup.c	2002-12-18 18:58:07.000000000 +0000
@@ -671,14 +671,16 @@
 	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
 	id->csf_default    = __le16_to_cpu(id->csf_default);
 	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-	id->word89         = __le16_to_cpu(id->word89);
-	id->word90         = __le16_to_cpu(id->word90);
+	id->trseuc         = __le16_to_cpu(id->trseuc);
+	id->trsEuc         = __le16_to_cpu(id->trsEuc);
 	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-	id->word92         = __le16_to_cpu(id->word92);
+	id->mprc           = __le16_to_cpu(id->mprc);
 	id->hw_config      = __le16_to_cpu(id->hw_config);
 	id->acoustic       = __le16_to_cpu(id->acoustic);
-	for (i = 0; i < 5; i++)
-		id->words95_99[i]  = __le16_to_cpu(id->words95_99[i]);
+	id->msrqs          = __le16_to_cpu(id->msrqs);
+	id->sxfert         = __le16_to_cpu(id->sxfert);
+	id->sal            = __le16_to_cpu(id->sal);
+	id->spg            = __le32_to_cpu(id->spg);
 	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
 	for (i = 0; i < 22; i++)
 		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/tlb.c linux-2.4.21/arch/ppc/mm/tlb.c
--- linux-2.4.20/arch/ppc/mm/tlb.c	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.21/arch/ppc/mm/tlb.c	2002-12-18 18:58:10.000000000 +0000
@@ -4,7 +4,7 @@
 /*
  * This file contains the routines for TLB flushing.
  * On machines where the MMU uses a hash table to store virtual to
- * physical translations, these routines flush entries from the the
+ * physical translations, these routines flush entries from the 
  * hash table also.
  *  -- paulus
  * 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/chrp_setup.c linux-2.4.21/arch/ppc/platforms/chrp_setup.c
--- linux-2.4.20/arch/ppc/platforms/chrp_setup.c	2002-12-18 18:27:06.000000000 +0000
+++ linux-2.4.21/arch/ppc/platforms/chrp_setup.c	2002-12-18 18:58:05.000000000 +0000
@@ -533,31 +533,6 @@
 }
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/*
- * IDE stuff.
- */
-
-static int __chrp
-chrp_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-        return check_region(from, extent);
-}
-
-static void __chrp
-chrp_ide_request_region(ide_ioreg_t from,
-			unsigned int extent,
-			const char *name)
-{
-        request_region(from, extent, name);
-}
-
-static void __chrp
-chrp_ide_release_region(ide_ioreg_t from,
-			unsigned int extent)
-{
-        release_region(from, extent);
-}
-
 static void __chrp
 chrp_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
@@ -657,9 +632,6 @@
 #endif /* CONFIG_SMP */
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-        ppc_ide_md.ide_check_region = chrp_ide_check_region;
-        ppc_ide_md.ide_request_region = chrp_ide_request_region;
-        ppc_ide_md.ide_release_region = chrp_ide_release_region;
         ppc_ide_md.ide_init_hwif = chrp_ide_init_hwif_ports;
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_setup.c linux-2.4.21/arch/ppc/platforms/pmac_setup.c
--- linux-2.4.20/arch/ppc/platforms/pmac_setup.c	2002-12-18 18:27:06.000000000 +0000
+++ linux-2.4.21/arch/ppc/platforms/pmac_setup.c	2002-12-18 18:58:03.000000000 +0000
@@ -708,44 +708,7 @@
    pmac_power_off();
 }
 
-
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/*
- * IDE stuff.
- */
-static int __pmac
-pmac_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	if (pmac_ide_check_base(from) >= 0)
-		return 0;
-#endif
-	return check_region(from, extent);
-}
-
-static void __pmac
-pmac_ide_request_region(ide_ioreg_t from,
-			unsigned int extent,
-			const char *name)
-{
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	if (pmac_ide_check_base(from) >= 0)
-		return;
-#endif
-	request_region(from, extent, name);
-}
-
-static void __pmac
-pmac_ide_release_region(ide_ioreg_t from,
-			unsigned int extent)
-{
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	if (pmac_ide_check_base(from) >= 0)
-		return;
-#endif
-	release_region(from, extent);
-}
-
 #ifndef CONFIG_BLK_DEV_IDE_PMAC
 /*
  * This is only used if we have a PCI IDE controller, not
@@ -926,9 +889,6 @@
 	select_adb_keyboard();
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-        ppc_ide_md.ide_check_region	= pmac_ide_check_region;
-        ppc_ide_md.ide_request_region	= pmac_ide_request_region;
-        ppc_ide_md.ide_release_region	= pmac_ide_release_region;
 #ifdef CONFIG_BLK_DEV_IDE_PMAC
         ppc_ide_md.ide_init_hwif	= pmac_ide_init_hwif_ports;
         ppc_ide_md.default_io_base	= pmac_ide_get_base;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/prep_setup.c linux-2.4.21/arch/ppc/platforms/prep_setup.c
--- linux-2.4.20/arch/ppc/platforms/prep_setup.c	2002-12-18 18:27:06.000000000 +0000
+++ linux-2.4.21/arch/ppc/platforms/prep_setup.c	2002-12-18 18:58:11.000000000 +0000
@@ -660,27 +660,6 @@
 	}
 }
 
-static int __prep
-prep_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-	return check_region(from, extent);
-}
-
-static void __prep
-prep_ide_request_region(ide_ioreg_t from,
-			unsigned int extent,
-			const char *name)
-{
-	request_region(from, extent, name);
-}
-
-static void __prep
-prep_ide_release_region(ide_ioreg_t from,
-			unsigned int extent)
-{
-	release_region(from, extent);
-}
-
 static void __init
 prep_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
@@ -865,9 +844,6 @@
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 	ppc_ide_md.default_irq = prep_ide_default_irq;
 	ppc_ide_md.default_io_base = prep_ide_default_io_base;
-	ppc_ide_md.ide_check_region = prep_ide_check_region;
-	ppc_ide_md.ide_request_region = prep_ide_request_region;
-	ppc_ide_md.ide_release_region = prep_ide_release_region;
 	ppc_ide_md.ide_init_hwif = prep_ide_init_hwif_ports;
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/setup.c linux-2.4.21/arch/ppc64/kernel/setup.c
--- linux-2.4.20/arch/ppc64/kernel/setup.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/arch/ppc64/kernel/setup.c	2002-12-18 18:58:05.000000000 +0000
@@ -585,17 +585,19 @@
 	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
 	id->csf_default    = __le16_to_cpu(id->csf_default);
 	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-	id->word89         = __le16_to_cpu(id->word89);
-	id->word90         = __le16_to_cpu(id->word90);
+	id->trseuc         = __le16_to_cpu(id->trseuc);
+	id->trsEuc         = __le16_to_cpu(id->trsEuc);
 	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-	id->word92         = __le16_to_cpu(id->word92);
+	id->mprc           = __le16_to_cpu(id->mprc);
 	id->hw_config      = __le16_to_cpu(id->hw_config);
 	id->acoustic       = __le16_to_cpu(id->acoustic);
-	for (i = 0; i < 5; i++)
-		id->words95_99[i]  = __le16_to_cpu(id->words95_99[i]);
+	id->msrqs          = __le16_to_cpu(id->msrqs);
+	id->sxfert         = __le16_to_cpu(id->sxfert);
+	id->sal            = __le16_to_cpu(id->sal);
+	id->spg            = __le32_to_cpu(id->spg);
 	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
-	for (i = 0; i < 21; i++)
-		id->words104_125[i]  = __le16_to_cpu(id->words104_125[i]);
+	for (i = 0; i < 22; i++)
+		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
 	id->last_lun       = __le16_to_cpu(id->last_lun);
 	id->word127        = __le16_to_cpu(id->word127);
 	id->dlf            = __le16_to_cpu(id->dlf);
@@ -605,14 +607,14 @@
 	id->word156        = __le16_to_cpu(id->word156);
 	for (i = 0; i < 3; i++)
 		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
-	id->cfa_power=__le16_to_cpu(id->cfa_power);
-	for (i = 0; i < 15; i++)
+	id->cfa_power      = __le16_to_cpu(id->cfa_power);
+	for (i = 0; i < 14; i++)
 		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
-	for (i = 0; i < 29; i++)
+	for (i = 0; i < 31; i++)
 		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
 	for (i = 0; i < 48; i++)
 		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
-	id->integrity_word=__le16_to_cpu(id->integrity_word);
+	id->integrity_word  = __le16_to_cpu(id->integrity_word);
 }
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sh/config.in linux-2.4.21/arch/sh/config.in
--- linux-2.4.20/arch/sh/config.in	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/arch/sh/config.in	2002-12-18 18:58:09.000000000 +0000
@@ -189,7 +189,7 @@
    if [ "$CONFIG_PCI_GODIRECT" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
       define_bool CONFIG_PCI_DIRECT y
    fi
-   bool 'Cache and PCI noncoherent' CONFIG_SH_PCIDMA_NONCOHERENT n
+   bool 'Cache and PCI noncoherent' CONFIG_SH_PCIDMA_NONCOHERENT
 fi
 
 source drivers/pci/Config.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sh/kernel/irq_intc2.c linux-2.4.21/arch/sh/kernel/irq_intc2.c
--- linux-2.4.20/arch/sh/kernel/irq_intc2.c	2001-09-08 19:29:09.000000000 +0000
+++ linux-2.4.21/arch/sh/kernel/irq_intc2.c	2002-12-18 18:58:10.000000000 +0000
@@ -107,7 +107,7 @@
 	}
 
 	disable_irq_nosync(irq);
-	/* Fill the the data we need */
+	/* Fill the data we need */
 	intc2_data[offset].addr=addr;
 	intc2_data[offset].mask=1<<pos;
 		
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/apc.c linux-2.4.21/arch/sparc/kernel/apc.c
--- linux-2.4.20/arch/sparc/kernel/apc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/arch/sparc/kernel/apc.c	2002-12-18 18:58:09.000000000 +0000
@@ -22,7 +22,6 @@
 /* Debugging
  * 
  * #define APC_DEBUG_LED
- * #define APC_NO_IDLE
  */
 
 #define APC_MINOR	MISC_DYNAMIC_MINOR
@@ -31,10 +30,27 @@
 
 volatile static u8 *regs; 
 static int apc_regsize;
+static int apc_no_idle __initdata = 0;
 
 #define apc_readb(offs)			(sbus_readb(regs+offs))
 #define apc_writeb(val, offs) 	(sbus_writeb(val, regs+offs))
 
+/* Specify "apc=noidle" on the kernel command line to 
+ * disable APC CPU standby support.  Certain prototype
+ * systems (SPARCstation-Fox) do not play well with APC
+ * CPU idle, so disable this if your system has APC and 
+ * crashes randomly.
+ */
+static int __init apc_setup(char *str) 
+{
+	if(!strncmp(str, "noidle", strlen("noidle"))) {
+		apc_no_idle = 1;
+		return 1;
+	}
+	return 0;
+}
+__setup("apc=", apc_setup);
+
 /* 
  * CPU idle callback function
  * See .../arch/sparc/kernel/process.c
@@ -127,6 +143,7 @@
 	struct sbus_bus *sbus = NULL;
 	struct sbus_dev *sdev = NULL;
 	int iTmp = 0;
+
 	for_each_sbus(sbus) {
 		for_each_sbusdev(sdev, sbus) {
 			if (!strcmp(sdev->prom_name, APC_OBPNAME)) {
@@ -155,12 +172,12 @@
 		return -ENODEV;
 	}
 
-#ifndef APC_NO_IDLE	
 	/* Assign power management IDLE handler */
-	pm_idle = apc_swift_idle;	
-#endif
+	if(!apc_no_idle)
+		pm_idle = apc_swift_idle;	
 
-	printk(KERN_INFO "%s: power management initialized\n", APC_DEVNAME);
+	printk(KERN_INFO "%s: power management initialized%s\n", 
+		APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : "");
 	return 0;
 }
 
@@ -169,3 +186,4 @@
  * initialized, so we install ourselves thusly:
  */
 __initcall(apc_probe);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/irq.c linux-2.4.21/arch/sparc/kernel/irq.c
--- linux-2.4.20/arch/sparc/kernel/irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/arch/sparc/kernel/irq.c	2002-12-18 18:58:02.000000000 +0000
@@ -92,7 +92,7 @@
 struct irqaction static_irqaction[MAX_STATIC_ALLOC];
 int static_irq_count;
 
-struct irqaction *irq_action[NR_IRQS+1] = {
+struct irqaction *irq_action[NR_IRQS] = {
 	  NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
 	  NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
 };
@@ -110,7 +110,7 @@
 		
 		return sun4d_get_irq_list(buf);
 	}
-	for (i = 0 ; i < (NR_IRQS+1) ; i++) {
+	for (i = 0 ; i < NR_IRQS ; i++) {
 	        action = *(i + irq_action);
 		if (!action) 
 		        continue;
@@ -147,7 +147,7 @@
 		
 		return sun4d_free_irq(irq, dev_id);
 	}
-	cpu_irq = irq & NR_IRQS;
+	cpu_irq = irq & (NR_IRQS - 1);
 	action = *(cpu_irq + irq_action);
         if (cpu_irq > 14) {  /* 14 irq levels on the sparc */
                 printk("Trying to free bogus IRQ %d\n", irq);
@@ -382,7 +382,7 @@
 	struct irqaction * action;
 	unsigned int cpu_irq;
 	
-	cpu_irq = irq & NR_IRQS;
+	cpu_irq = irq & (NR_IRQS - 1);
 	action = *(cpu_irq + irq_action);
 
         printk("IO device interrupt, irq = %d\n", irq);
@@ -461,7 +461,7 @@
 	extern struct tt_entry trapbase_cpu1, trapbase_cpu2, trapbase_cpu3;
 #endif
 	
-	cpu_irq = irq & NR_IRQS;
+	cpu_irq = irq & (NR_IRQS - 1);
 	if(cpu_irq > 14)
 		return -EINVAL;
 	if(!handler)
@@ -551,7 +551,7 @@
 					     unsigned long, const char *, void *);
 		return sun4d_request_irq(irq, handler, irqflags, devname, dev_id);
 	}
-	cpu_irq = irq & NR_IRQS;
+	cpu_irq = irq & (NR_IRQS - 1);
 	if(cpu_irq > 14)
 		return -EINVAL;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/signal.c linux-2.4.21/arch/sparc/kernel/signal.c
--- linux-2.4.20/arch/sparc/kernel/signal.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/arch/sparc/kernel/signal.c	2002-12-18 18:58:10.000000000 +0000
@@ -1241,7 +1241,7 @@
 			if (current->pid == 1)
 				continue;
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/sun4c_irq.c linux-2.4.21/arch/sparc/kernel/sun4c_irq.c
--- linux-2.4.20/arch/sparc/kernel/sun4c_irq.c	2001-04-27 05:17:26.000000000 +0000
+++ linux-2.4.21/arch/sparc/kernel/sun4c_irq.c	2002-12-18 18:58:02.000000000 +0000
@@ -57,7 +57,7 @@
 	unsigned char current_mask, new_mask;
     
 	save_and_cli(flags);
-	irq_nr &= NR_IRQS;
+	irq_nr &= (NR_IRQS - 1);
 	current_mask = *interrupt_enable;
 	switch(irq_nr) {
 	case 1:
@@ -86,7 +86,7 @@
 	unsigned char current_mask, new_mask;
     
 	save_and_cli(flags);
-	irq_nr &= NR_IRQS;
+	irq_nr &= (NR_IRQS - 1);
 	current_mask = *interrupt_enable;
 	switch(irq_nr) {
 	case 1:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/mm/iommu.c linux-2.4.21/arch/sparc/mm/iommu.c
--- linux-2.4.20/arch/sparc/mm/iommu.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/arch/sparc/mm/iommu.c	2002-12-18 18:58:08.000000000 +0000
@@ -188,7 +188,7 @@
 {
 	unsigned long page, oldpage = 0;
 
-	while(sz >= 0) {
+	while(sz != 0) {
 		sz--;
 		page = ((unsigned long) sg[sz].address) & PAGE_MASK;
 		if (oldpage == page)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/Makefile linux-2.4.21/arch/sparc64/Makefile
--- linux-2.4.20/arch/sparc64/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/arch/sparc64/Makefile	2002-12-18 18:58:12.000000000 +0000
@@ -17,6 +17,7 @@
 NEW_GCC := $(shell if $(CC) -m64 -mcmodel=medlow -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; )
 NEW_GAS := $(shell if $(LD) -V 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi)
 UNDECLARED_REGS := $(shell if $(CC) -c -x assembler /dev/null -Wa,--help | grep undeclared-regs > /dev/null; then echo y; else echo n; fi; )
+INLINE_LIMIT := $(shell if $(CC) -m64 -finline-limit=100000 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; )
 
 export NEW_GCC
 
@@ -48,6 +49,10 @@
   AFLAGS += -m64 -mcpu=ultrasparc $(CC_UNDECL)
 endif
 
+ifeq ($(INLINE_LIMIT),y)
+  CFLAGS := $(CFLAGS) -finline-limit=100000
+endif
+
 ifeq ($(CONFIG_MCOUNT),y)
   CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS))
   CFLAGS := $(CFLAGS) -pg
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/defconfig linux-2.4.21/arch/sparc64/defconfig
--- linux-2.4.20/arch/sparc64/defconfig	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/arch/sparc64/defconfig	2002-12-18 18:58:06.000000000 +0000
@@ -269,21 +269,13 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # CONFIG_IDEDISK_STROKE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 CONFIG_BLK_DEV_IDETAPE=m
 CONFIG_BLK_DEV_IDEFLOPPY=m
 # CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_TASKFILE_IO=y
 
 #
 # IDE chipset support/bugfixes
@@ -291,8 +283,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_GENERIC=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -301,36 +293,39 @@
 # CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
-# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
-# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 CONFIG_BLK_DEV_ADMA=y
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_AEC62XX_TUNING is not set
+CONFIG_BLK_DEV_AEC62XX=m
 CONFIG_BLK_DEV_ALI15X3=y
 # CONFIG_WDC_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
+CONFIG_BLK_DEV_AMD74XX=m
 # CONFIG_AMD74XX_OVERRIDE is not set
 CONFIG_BLK_DEV_CMD64X=y
-# CONFIG_BLK_DEV_CMD680 is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
+CONFIG_BLK_DEV_CY82C693=m
+CONFIG_BLK_DEV_CS5530=m
+CONFIG_BLK_DEV_HPT34X=m
 # CONFIG_HPT34X_AUTODMA is not set
-# CONFIG_BLK_DEV_HPT366 is not set
+CONFIG_BLK_DEV_HPT366=m
+CONFIG_BLK_DEV_PIIX=m
+CONFIG_BLK_DEV_NFORCE=m
 CONFIG_BLK_DEV_NS87415=y
-# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+CONFIG_BLK_DEV_OPTI621=m
+CONFIG_BLK_DEV_PDC202XX_OLD=m
 # CONFIG_PDC202XX_BURST is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=m
 # CONFIG_PDC202XX_FORCE is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIS5513 is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_BLK_DEV_RZ1000=m
+CONFIG_BLK_DEV_SC1200=m
+CONFIG_BLK_DEV_SVWKS=m
+CONFIG_BLK_DEV_SIIMAGE=m
+CONFIG_BLK_DEV_SIS5513=m
+CONFIG_BLK_DEV_SLC90E66=m
+CONFIG_BLK_DEV_TRM290=m
+CONFIG_BLK_DEV_VIA82CXXX=m
 # CONFIG_IDE_CHIPSETS is not set
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_PDC202XX=y
 CONFIG_BLK_DEV_IDE_MODES=y
 CONFIG_BLK_DEV_ATARAID=m
 CONFIG_BLK_DEV_ATARAID_PDC=m
@@ -405,6 +400,7 @@
 #
 CONFIG_FUSION=m
 # CONFIG_FUSION_BOOT is not set
+CONFIG_FUSION_MAX_SGE=40
 CONFIG_FUSION_ISENSE=m
 CONFIG_FUSION_CTL=m
 CONFIG_FUSION_LAN=m
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/signal.c linux-2.4.21/arch/sparc64/kernel/signal.c
--- linux-2.4.20/arch/sparc64/kernel/signal.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/arch/sparc64/kernel/signal.c	2002-12-18 18:58:01.000000000 +0000
@@ -783,7 +783,7 @@
 			if (current->pid == 1)
 				continue;
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/signal32.c linux-2.4.21/arch/sparc64/kernel/signal32.c
--- linux-2.4.20/arch/sparc64/kernel/signal32.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/arch/sparc64/kernel/signal32.c	2002-12-18 18:58:01.000000000 +0000
@@ -1444,7 +1444,7 @@
 			if (current->pid == 1)
 				continue;
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/sparc64_ksyms.c linux-2.4.21/arch/sparc64/kernel/sparc64_ksyms.c
--- linux-2.4.20/arch/sparc64/kernel/sparc64_ksyms.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/arch/sparc64/kernel/sparc64_ksyms.c	2002-12-18 18:58:05.000000000 +0000
@@ -195,6 +195,7 @@
 EXPORT_SYMBOL(get_fb_unmapped_area);
 EXPORT_SYMBOL(flush_icache_range);
 EXPORT_SYMBOL(flush_dcache_page);
+EXPORT_SYMBOL(__flush_dcache_range);
 
 EXPORT_SYMBOL(mostek_lock);
 EXPORT_SYMBOL(mstk48t02_regs);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/sys_sparc32.c linux-2.4.21/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.4.20/arch/sparc64/kernel/sys_sparc32.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/arch/sparc64/kernel/sys_sparc32.c	2002-12-18 18:58:10.000000000 +0000
@@ -1150,7 +1150,7 @@
 	/* VERIFY_WRITE actually means a read, as we write to user space */
 	if ((retval + (type == VERIFY_WRITE)) > 0)
 		dnotify_parent(file->f_dentry,
-			(type == VERIFY_WRITE) ? DN_MODIFY : DN_ACCESS);
+			(type == VERIFY_WRITE) ? DN_ACCESS : DN_MODIFY);
 
 	return retval;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/solaris/ioctl.c linux-2.4.21/arch/sparc64/solaris/ioctl.c
--- linux-2.4.20/arch/sparc64/solaris/ioctl.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/arch/sparc64/solaris/ioctl.c	2002-12-18 18:58:09.000000000 +0000
@@ -367,6 +367,7 @@
 	case 106: /* SI_GETINTRANSIT */
 	case 107: /* SI_TCL_LINK */
 	case 108: /* SI_TCL_UNLINK */
+		;
 	}
 	return TNOTSUPPORT;
 }
@@ -454,6 +455,7 @@
 	case 145: /* TI_GETPEERNAME */
 	case 146: /* TI_SETMYNAME */
 	case 147: /* TI_SETPEERNAME */
+		;
 	}
 	return TNOTSUPPORT;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/cciss.c linux-2.4.21/drivers/block/cciss.c
--- linux-2.4.20/drivers/block/cciss.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/block/cciss.c	2002-12-18 18:58:11.000000000 +0000
@@ -1,6 +1,6 @@
 /*
- *    Disk Array driver for Compaq SMART2 Controllers
- *    Copyright 2000 Compaq Computer Corporation
+ *    Disk Array driver for HP SA 5xxx and 6xxx Controllers
+ *    Copyright 2000, 2002 Hewlett-Packard Development Company, L.P. 
  *
  *    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
@@ -16,7 +16,7 @@
  *    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
+ *    Questions/Comments/Bugfixes to Cciss-discuss@lists.sourceforge.net
  *
  */
 
@@ -44,12 +44,13 @@
 #include <linux/genhd.h>
 
 #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "Compaq CISS Driver (v 2.4.5)"
-#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,5)
+#define DRIVER_NAME "HP CISS Driver (v 2.4.42)"
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,42)
 
 /* Embedded module documentation macros - see modules.h */
-MODULE_AUTHOR("Charles M. White III - Compaq Computer Corporation");
-MODULE_DESCRIPTION("Driver for Compaq Smart Array Controller 5300");
+MODULE_AUTHOR("Charles M. White III - Hewlett-Packard Company");
+MODULE_DESCRIPTION("Driver for HP SA5xxx SA6xxx Controllers version 2.4.42");
+MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"); 
 MODULE_LICENSE("GPL");
 
 #include "cciss_cmd.h"
@@ -66,6 +67,12 @@
                         0x0E11, 0x4082, 0, 0, 0},
 	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
                         0x0E11, 0x4083, 0, 0, 0},
+	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
+                        0x0E11, 0x409A, 0, 0, 0},
+	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
+                        0x0E11, 0x409B, 0, 0, 0},
+	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
+                        0x0E11, 0x409C, 0, 0, 0},
 	{0,}
 };
 MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
@@ -77,15 +84,21 @@
  *  access = Address of the struct of function pointers 
  */
 static struct board_type products[] = {
-	{ 0x40700E11, "Smart Array 5300",	&SA5_access },
+	{ 0x40700E11, "Smart Array 5300", &SA5_access},
 	{ 0x40800E11, "Smart Array 5i", &SA5B_access},
 	{ 0x40820E11, "Smart Array 532", &SA5B_access},
 	{ 0x40830E11, "Smart Array 5312", &SA5B_access},
+	{ 0x409A0E11, "Smart Array 641", &SA5_access},
+	{ 0x409B0E11, "Smart Array 642", &SA5_access},
+	{ 0x409C0E11, "Smart Array 6400", &SA5_access},
 };
 
 /* How long to wait (in millesconds) for board to go into simple mode */
 #define MAX_CONFIG_WAIT 1000 
 
+/*define how many times we will try a command because of bus resets */
+#define MAX_CMD_RETRIES 3
+
 #define READ_AHEAD 	 128
 #define NR_CMDS		 128 /* #commands that can be outstanding */
 #define MAX_CTLR 8
@@ -104,6 +117,9 @@
 
 static int revalidate_logvol(kdev_t dev, int maxusage);
 static int frevalidate_logvol(kdev_t dev);
+static int deregister_disk(int ctlr, int logvol);
+static int register_new_disk(int cltr, int opened_vol, __u64 requested_lun);
+static int cciss_rescan_disk(int cltr, int logvol);
 
 static void cciss_getgeometry(int cntl_num);
 
@@ -130,6 +146,11 @@
 
 #include "cciss_scsi.c"		/* For SCSI tape support */
 
+#define ENG_GIG	1048576000
+#define ENG_GIG_FACTOR (ENG_GIG/512)
+#define	RAID_UNKNOWN 6
+static const char *raid_label[] = {"0","4","1(0+1)","5","5+1","ADG",
+				   "UNKNOWN"};
 /*
  * Report information about this controller.
  */
@@ -137,53 +158,67 @@
 static int cciss_proc_get_info(char *buffer, char **start, off_t offset, 
 		int length, int *eof, void *data)
 {
-        off_t pos = 0;
-        off_t len = 0;
-        int size, i, ctlr;
-        ctlr_info_t *h = (ctlr_info_t*)data;
-        drive_info_struct *drv;
-
-        ctlr = h->ctlr;
-        size = sprintf(buffer, "%s:  Compaq %s Controller\n"
-                "       Board ID: 0x%08lx\n"
-		"       Firmware Version: %c%c%c%c\n"
-                "       Memory Address: 0x%08lx\n"
-                "       IRQ: %d\n"
-                "       Logical drives: %d\n"
-                "       Current Q depth: %d\n"
-		"       Current # commands on controller %d\n"
-                "       Max Q depth since init: %d\n"
-		"       Max # commands on controller since init: %d\n"
-		"       Max SG entries since init: %d\n\n",
-                h->devname,
-                h->product_name,
-                (unsigned long)h->board_id,
-		h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3],
-                (unsigned long)h->vaddr,
-                (unsigned int)h->intr,
-                h->num_luns, 
-                h->Qdepth, h->commands_outstanding,
-		h->maxQsinceinit, h->max_outstanding, h->maxSG);
+	off_t pos = 0;
+	off_t len = 0;
+	int size, i, ctlr;
+	ctlr_info_t *h = (ctlr_info_t*)data;
+	drive_info_struct *drv;
+	unsigned long flags;
+	unsigned int vol_sz, vol_sz_frac;
 
-        pos += size; len += size;
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (h->busy_configuring) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return -EBUSY;
+	}
+	h->busy_configuring = 1;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+		
+	ctlr = h->ctlr;
+	size = sprintf(buffer, "%s: HP %s Controller\n"
+ 		"Board ID: 0x%08lx\n"
+		"Firmware Version: %c%c%c%c\n"
+ 		"IRQ: %d\n"
+ 		"Logical drives: %d\n"
+ 		"Current Q depth: %d\n"
+ 		"Current # commands on controller: %d\n"
+ 		"Max Q depth since init: %d\n"
+		"Max # commands on controller since init: %d\n"
+		"Max SG entries since init: %d\n\n",
+  		h->devname,
+  		h->product_name,
+  		(unsigned long)h->board_id,
+  		h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3],
+  		(unsigned int)h->intr,
+  		h->num_luns, 
+  		h->Qdepth, h->commands_outstanding,
+  		h->maxQsinceinit, h->max_outstanding, h->maxSG);
+  
+	pos += size; len += size;
 	cciss_proc_tape_report(ctlr, buffer, &pos, &len);
-	for(i=0; i<h->num_luns; i++) {
-                drv = &h->drv[i];
-                size = sprintf(buffer+len, "cciss/c%dd%d: blksz=%d nr_blocks=%d\n",
-                                ctlr, i, drv->block_size, drv->nr_blocks);
-                pos += size; len += size;
-        }
-
-	size = sprintf(buffer+len, "nr_allocs = %d\nnr_frees = %d\n",
-                        h->nr_allocs, h->nr_frees);
-        pos += size; len += size;
-
-        *eof = 1;
-        *start = buffer+offset;
-        len -= offset;
-        if (len>length)
-                len = length;
-        return len;
+	for(i=0; i<=h->highest_lun; i++) {
+		drv = &h->drv[i];
+		if (drv->nr_blocks == 0)
+			continue;
+		vol_sz = drv->nr_blocks/ENG_GIG_FACTOR; 
+		vol_sz_frac = (drv->nr_blocks%ENG_GIG_FACTOR)*100/ENG_GIG_FACTOR;
+
+		if (drv->raid_level > 5)
+			drv->raid_level = RAID_UNKNOWN;
+		size = sprintf(buffer+len, "cciss/c%dd%d:"
+				"\t%4d.%02dGB\tRAID %s\n",
+		       		 ctlr, i, vol_sz,vol_sz_frac,
+				 raid_label[drv->raid_level]);
+		pos += size, len += size;
+        }
+
+	*eof = 1;
+	*start = buffer+offset;
+	len -= offset;
+	if (len>length)
+		len = length;
+	h->busy_configuring = 0;
+	return len;
 }
 
 static int
@@ -197,16 +232,19 @@
 	int rc;
 #endif
 
-	if (count > sizeof(cmd)-1) return -EINVAL;
-	if (copy_from_user(cmd, buffer, count)) return -EFAULT;
+	if (count > sizeof(cmd)-1) 
+		return -EINVAL;
+	if (copy_from_user(cmd, buffer, count)) 
+		return -EFAULT;
 	cmd[count] = '\0';
-	len = strlen(cmd);	// safe???
+	len = strlen(cmd);	
 	if (cmd[len-1] == '\n')
 		cmd[--len] = '\0';
 #	ifdef CONFIG_CISS_SCSI_TAPE
 		if (strcmp("engage scsi", cmd)==0) {
 			rc = cciss_engage_scsi(h->ctlr);
-			if (rc != 0) return -rc;
+			if (rc != 0) 
+				return -rc;
 			return count;
 		}
 		/* might be nice to have "disengage" too, but it's not
@@ -225,8 +263,10 @@
 
 	if (proc_cciss == NULL) {
 		proc_cciss = proc_mkdir("cciss", proc_root_driver);
-		if (!proc_cciss)
+		if (!proc_cciss) {
+			printk("cciss:  proc_mkdir failed\n");
 			return;
+		}
 	}
 
 	pde = create_proc_read_entry(hba[i]->devname,
@@ -250,11 +290,10 @@
 	u64bit temp64;
 	dma_addr_t cmd_dma_handle, err_dma_handle;
 
-	if (!get_from_pool)
-	{
+	if (!get_from_pool) {
 		c = (CommandList_struct *) pci_alloc_consistent(
 			h->pdev, sizeof(CommandList_struct), &cmd_dma_handle); 
-        	if(c==NULL)
+        	if (c==NULL)
                  	return NULL;
 		memset(c, 0, sizeof(CommandList_struct));
 
@@ -310,8 +349,7 @@
 	int i;
 	u64bit temp64;
 
-	if( !got_from_pool)
-	{ 
+	if (!got_from_pool) { 
 		temp64.val32.lower = c->ErrDesc.Addr.lower;
 		temp64.val32.upper = c->ErrDesc.Addr.upper;
 		pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct), 
@@ -336,24 +374,22 @@
 	
 	/* Loop through each real device */ 
 	hba[ctlr]->gendisk.nr_real = 0; 
-	for(i=0; i< NWD; i++)
-	{
+	for(i=0; i< NWD; i++) {
 		drv = &(hba[ctlr]->drv[i]);
-		if( !(drv->nr_blocks))
+		if (!(drv->nr_blocks))
 			continue;
 		hba[ctlr]->hd[i << NWD_SHIFT].nr_sects = 
 		hba[ctlr]->sizes[i << NWD_SHIFT] = drv->nr_blocks;
 
 		/* for each partition */ 
-		for(j=0; j<MAX_PART; j++)
-		{
+		for(j=0; j<MAX_PART; j++) {
 			hba[ctlr]->blocksizes[(i<<NWD_SHIFT) + j] = 1024; 
 
 			hba[ctlr]->hardsizes[ (i<<NWD_SHIFT) + j] = 
 				drv->block_size;
 		}
-		hba[ctlr]->gendisk.nr_real++;
 	}
+	hba[ctlr]->gendisk.nr_real = hba[ctlr]->highest_lun+1;
 }
 /*
  * Open.  Make sure the device is really there.
@@ -371,13 +407,23 @@
 		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,
+	 * so array config can still work. Root is also allowed to open any
+	 * volume that has a LUN ID, so it can issue IOCTL to reread the
+	 * disk information.  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 (hba[ctlr]->sizes[MINOR(inode->i_rdev)] == 0) { /* not online? */
-		if (MINOR(inode->i_rdev) != 0)	 /* not node 0? */
-			return -ENXIO;
+		if (MINOR(inode->i_rdev) != 0) {	 /* not node 0? */
+			/* if not node 0 make sure it is a partition = 0 */
+			if (MINOR(inode->i_rdev) & 0x0f) {
+				return -ENXIO;
+				/* if it is, make sure we have a LUN ID */
+			} else if (hba[ctlr]->drv[MINOR(inode->i_rdev)
+					>> NWD_SHIFT].LunID == 0) {
+				return -ENXIO;
+			}
+		}
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 	}
@@ -419,8 +465,8 @@
 #endif /* CCISS_DEBUG */ 
 	
 	switch(cmd) {
-	case HDIO_GETGEO:
-	{
+	   case HDIO_GETGEO:
+	   {
 		struct hd_geometry driver_geo;
 		if (hba[ctlr]->drv[dsk].cylinders) {
 			driver_geo.heads = hba[ctlr]->drv[dsk].heads;
@@ -437,8 +483,8 @@
 		if (copy_to_user((void *) arg, &driver_geo,
 				sizeof( struct hd_geometry)))
 			return  -EFAULT;
-		return(0);
-	}
+		return 0;
+	   }
 	case HDIO_GETGEO_BIG:
 	{
 		struct hd_big_geometry driver_geo;
@@ -457,7 +503,7 @@
 		if (copy_to_user((void *) arg, &driver_geo,  
 				sizeof( struct hd_big_geometry)))
 			return  -EFAULT;
-		return(0);
+		return 0;
 	}
 	case BLKGETSIZE:
 		put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects, (unsigned long *)arg);
@@ -466,7 +512,7 @@
 		put_user((u64)hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects << 9, (u64*)arg);
 		return 0;
 	case BLKRRPART:
-		if(!capable(CAP_SYS_ADMIN))
+		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 		return revalidate_logvol(inode->i_rdev, 1);
 	case BLKFLSBUF:
@@ -479,30 +525,32 @@
 	case BLKPG:
 	case BLKELVGET:
 	case BLKELVSET:
-		return( blk_ioctl(inode->i_rdev, cmd, arg));
+		return blk_ioctl(inode->i_rdev, cmd, arg);
 	case CCISS_GETPCIINFO:
 	{
 		cciss_pci_info_struct pciinfo;
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		pciinfo.bus = hba[ctlr]->pdev->bus->number;
 		pciinfo.dev_fn = hba[ctlr]->pdev->devfn;
 		pciinfo.board_id = hba[ctlr]->board_id;
 		if (copy_to_user((void *) arg, &pciinfo,  sizeof( cciss_pci_info_struct )))
 			return  -EFAULT;
-		return(0);
+		return 0;
 	}	
 	case CCISS_GETINTINFO:
 	{
 		cciss_coalint_struct intinfo;
 		ctlr_info_t *c = hba[ctlr];
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		intinfo.delay = readl(&c->cfgtable->HostWrite.CoalIntDelay);
 		intinfo.count = readl(&c->cfgtable->HostWrite.CoalIntCount);
 		if (copy_to_user((void *) arg, &intinfo, sizeof( cciss_coalint_struct )))
 			return -EFAULT;
-                return(0);
+                return 0;
         }
 	case CCISS_SETINTINFO:
         {
@@ -511,25 +559,21 @@
 		unsigned long flags;
 		int i;
 
-		if (!arg) return -EINVAL;	
-		if (!capable(CAP_SYS_ADMIN)) return -EPERM;
+		if (!arg) 
+			return -EINVAL;	
+		if (!capable(CAP_SYS_ADMIN)) 
+			return -EPERM;
 		if (copy_from_user(&intinfo, (void *) arg, sizeof( cciss_coalint_struct)))
 			return -EFAULT;
-		if ( (intinfo.delay == 0 ) && (intinfo.count == 0))
-
-		{
-//			printk("cciss_ioctl: delay and count cannot be 0\n");
-			return( -EINVAL);
+		if ( (intinfo.delay == 0 ) && (intinfo.count == 0)) {
+			return -EINVAL;
 		}
+
 		spin_lock_irqsave(&io_request_lock, flags);
 		/* Can only safely update if no commands outstanding */ 
-		if (c->commands_outstanding > 0 )
-		{
-//			printk("cciss_ioctl: cannot change coalasing "
-//				"%d commands outstanding on controller\n", 
-//					c->commands_outstanding);
+		if (c->commands_outstanding > 0 ) {
 			spin_unlock_irqrestore(&io_request_lock, flags);
-			return(-EINVAL);
+			return -EINVAL;
 		}
 		/* Update the field, and then ring the doorbell */ 
 		writel( intinfo.delay, 
@@ -538,8 +582,7 @@
                         &(c->cfgtable->HostWrite.CoalIntCount));
 		writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
 
-		for(i=0;i<MAX_CONFIG_WAIT;i++)
-		{
+		for(i=0;i<MAX_CONFIG_WAIT;i++) {
 			if (!(readl(c->vaddr + SA5_DOORBELL) 
 					& CFGTBL_ChangeReq))
 				break;
@@ -548,8 +591,8 @@
 		}	
 		spin_unlock_irqrestore(&io_request_lock, flags);
 		if (i >= MAX_CONFIG_WAIT)
-			return( -EFAULT);
-                return(0);
+			return -EFAULT;
+                return 0;
         }
 	case CCISS_GETNODENAME:
         {
@@ -557,12 +600,13 @@
                 ctlr_info_t *c = hba[ctlr];
 		int i; 
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		for(i=0;i<16;i++)
 			NodeName[i] = readb(&c->cfgtable->ServerName[i]);
                 if (copy_to_user((void *) arg, NodeName, sizeof( NodeName_type)))
                 	return  -EFAULT;
-                return(0);
+                return 0;
         }
 	case CCISS_SETNODENAME:
 	{
@@ -571,8 +615,10 @@
 		unsigned long flags;
 		int i;
 
-		if (!arg) return -EINVAL;
-		if (!capable(CAP_SYS_ADMIN)) return -EPERM;
+		if (!arg) 
+			return -EINVAL;
+		if (!capable(CAP_SYS_ADMIN)) 
+			return -EPERM;
 		
 		if (copy_from_user(NodeName, (void *) arg, sizeof( NodeName_type)))
 			return -EFAULT;
@@ -585,8 +631,7 @@
 			
 		writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
 
-		for(i=0;i<MAX_CONFIG_WAIT;i++)
-		{
+		for(i=0;i<MAX_CONFIG_WAIT;i++) {
 			if (!(readl(c->vaddr + SA5_DOORBELL) 
 					& CFGTBL_ChangeReq))
 				break;
@@ -595,8 +640,8 @@
 		}	
 		spin_unlock_irqrestore(&io_request_lock, flags);
 		if (i >= MAX_CONFIG_WAIT)
-			return( -EFAULT);
-                return(0);
+			return -EFAULT;
+                return 0;
         }
 
 	case CCISS_GETHEARTBEAT:
@@ -604,45 +649,68 @@
                 Heartbeat_type heartbeat;
                 ctlr_info_t *c = hba[ctlr];
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
                 heartbeat = readl(&c->cfgtable->HeartBeat);
                 if (copy_to_user((void *) arg, &heartbeat, sizeof( Heartbeat_type)))
                 	return -EFAULT;
-                return(0);
+                return 0;
         }
 	case CCISS_GETBUSTYPES:
         {
                 BusTypes_type BusTypes;
                 ctlr_info_t *c = hba[ctlr];
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
                 BusTypes = readl(&c->cfgtable->BusTypes);
                 if (copy_to_user((void *) arg, &BusTypes, sizeof( BusTypes_type) ))
                 	return  -EFAULT;
-                return(0);
+                return 0;
         }
 	case CCISS_GETFIRMVER:
         {
 		FirmwareVer_type firmware;
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		memcpy(firmware, hba[ctlr]->firm_ver, 4);
 
                 if (copy_to_user((void *) arg, firmware, sizeof( FirmwareVer_type)))
                 	return -EFAULT;
-                return(0);
+                return 0;
         }
         case CCISS_GETDRIVVER:
         {
 		DriverVer_type DriverVer = DRIVER_VERSION;
 
-                if (!arg) return -EINVAL;
+                if (!arg) 
+			return -EINVAL;
 
                 if (copy_to_user((void *) arg, &DriverVer, sizeof( DriverVer_type) ))
                 	return -EFAULT;
-                return(0);
+                return 0;
         }
+	case CCISS_RESCANDISK:
+	{
+		return cciss_rescan_disk(ctlr, dsk);
+	}
+	case CCISS_DEREGDISK:
+		return deregister_disk(ctlr,dsk);
 
+	case CCISS_REGNEWD:
+		return register_new_disk(ctlr, dsk, 0);
+	case CCISS_REGNEWDISK:
+	{
+		__u64 new_logvol;
+
+		if (!arg) 
+			return -EINVAL;
+		if (copy_from_user(&new_logvol, (void *) arg, 
+			sizeof( __u64)))
+			return -EFAULT;
+		return register_new_disk(ctlr, dsk, new_logvol);
+	}
 	case CCISS_GETLUNINFO:
 	{
 		LogvolInfo_struct luninfo;
@@ -656,14 +724,14 @@
   		start = (dsk << NWD_SHIFT);
 		for(i=1; i <MAX_PART; i++) {
 			int minor = start+i;
-			if(hba[ctlr]->sizes[minor] != 0)
+			if (hba[ctlr]->sizes[minor] != 0)
 				num_parts++;
 		}
 		luninfo.num_parts = num_parts;
 		if (copy_to_user((void *) arg, &luninfo,
 				sizeof( LogvolInfo_struct) ))
 			return -EFAULT;
-		return(0);
+		return 0;
 	}
 	case CCISS_PASSTHRU:
 	{
@@ -675,28 +743,28 @@
 		unsigned long flags;
 		DECLARE_COMPLETION(wait);
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 	
-		if (!capable(CAP_SYS_RAWIO)) return -EPERM;
+		if (!capable(CAP_SYS_RAWIO)) 
+			return -EPERM;
 
 		if (copy_from_user(&iocommand, (void *) arg, sizeof( IOCTL_Command_struct) ))
 			return -EFAULT;
-		if((iocommand.buf_size < 1) && 
-				(iocommand.Request.Type.Direction != XFER_NONE))
-		{	
+		if ((iocommand.buf_size < 1) && 
+				(iocommand.Request.Type.Direction 
+				 	!= XFER_NONE)) {	
 			return -EINVAL;
 		} 
 		/* Check kmalloc limits */
-		if(iocommand.buf_size > 128000)
+		if (iocommand.buf_size > 128000)
 			return -EINVAL;
-		if(iocommand.buf_size > 0)
-		{
+		if (iocommand.buf_size > 0) {
 			buff =  kmalloc(iocommand.buf_size, GFP_KERNEL);
-			if( buff == NULL) 
-				return -EFAULT;
+			if (buff == NULL) 
+				return -ENOMEM;
 		}
-		if (iocommand.Request.Type.Direction == XFER_WRITE)
-		{
+		if (iocommand.Request.Type.Direction == XFER_WRITE) {
 			/* Copy the data into the buffer we created */ 
 			if (copy_from_user(buff, iocommand.buf, iocommand.buf_size))
 			{
@@ -704,40 +772,37 @@
 				return -EFAULT;
 			}
 		}
-		if ((c = cmd_alloc(h , 0)) == NULL)
-		{
+		if ((c = cmd_alloc(h , 0)) == NULL) {
 			kfree(buff);
 			return -ENOMEM;
 		}
-			// Fill in the command type 
+			/* Fill in the command type */
 		c->cmd_type = CMD_IOCTL_PEND;
-			// Fill in Command Header 
-		c->Header.ReplyQueue = 0;  // unused in simple mode
-		if( iocommand.buf_size > 0) 	// buffer to fill 
-		{
+			/* Fill in Command Header */
+		c->Header.ReplyQueue = 0;  /* unused in simple mode */
+		if (iocommand.buf_size > 0) { 	/* buffer to fill */
 			c->Header.SGList = 1;
 			c->Header.SGTotal= 1;
-		} else	// no buffers to fill  
-		{
+		} else	{  /* no buffers to fill  */
 			c->Header.SGList = 0;
                 	c->Header.SGTotal= 0;
 		}
 		c->Header.LUN = iocommand.LUN_info;
-		c->Header.Tag.lower = c->busaddr;  // use the kernel address the cmd block for tag
+		c->Header.Tag.lower = c->busaddr;  /* use the kernel address */
+						/* the cmd block for tag */
 		
-		// Fill in Request block 
+		/* Fill in Request block */
 		c->Request = iocommand.Request; 
 	
-		// Fill in the scatter gather information
-		if (iocommand.buf_size > 0 ) 
-		{
+		/* Fill in the scatter gather information */
+		if (iocommand.buf_size > 0 ) {
 			temp64.val = pci_map_single( h->pdev, buff,
                                         iocommand.buf_size, 
                                 PCI_DMA_BIDIRECTIONAL);	
 			c->SG[0].Addr.lower = temp64.val32.lower;
 			c->SG[0].Addr.upper = temp64.val32.upper;
 			c->SG[0].Len = iocommand.buf_size;
-			c->SG[0].Ext = 0;  // we are not chaining
+			c->SG[0].Ext = 0;  /* we are not chaining */
 		}
 		c->waiting = &wait;
 
@@ -758,18 +823,17 @@
 
 		/* Copy the error information out */ 
 		iocommand.error_info = *(c->err_info);
-		if ( copy_to_user((void *) arg, &iocommand, sizeof( IOCTL_Command_struct) ) )
-		{
+		if (copy_to_user((void *) arg, &iocommand, 
+				sizeof( IOCTL_Command_struct) ) ) {
 			kfree(buff);
 			cmd_free(h, c, 0);
-			return( -EFAULT);	
+			return( -EFAULT);
 		} 	
 
-		if (iocommand.Request.Type.Direction == XFER_READ)
-                {
+		if (iocommand.Request.Type.Direction == XFER_READ) {
                         /* Copy the data out of the buffer we created */
-                        if (copy_to_user(iocommand.buf, buff, iocommand.buf_size))
-			{
+                        if (copy_to_user(iocommand.buf, buff, 
+						iocommand.buf_size)) {
                         	kfree(buff);
 				cmd_free(h, c, 0);
 				return -EFAULT;
@@ -777,9 +841,149 @@
                 }
                 kfree(buff);
 		cmd_free(h, c, 0);
-                return(0);
+                return 0;
 	} 
+	case CCISS_BIG_PASSTHRU:
+	{
+		BIG_IOCTL_Command_struct iocommand;
+		ctlr_info_t *h = hba[ctlr];
+		CommandList_struct *c;
+		char 	*buff[MAXSGENTRIES] = {NULL,};
+		int	buff_size[MAXSGENTRIES] = {0,};
+		u64bit	temp64;
+		unsigned long flags;
+		BYTE sg_used = 0;
+		int status = 0;
+		int i;
+		DECLARE_COMPLETION(wait);
+
+		if (!arg) 
+			return -EINVAL;
+		
+		if (!capable(CAP_SYS_RAWIO)) 
+			return -EPERM;
+
+		if (copy_from_user(&iocommand, (void *) arg, sizeof( BIG_IOCTL_Command_struct) ))
+			return -EFAULT;
+		if ((iocommand.buf_size < 1) && 
+			(iocommand.Request.Type.Direction != XFER_NONE)) {
+			return -EINVAL;
+		} 
+		/* Check kmalloc limits  using all SGs */
+		if (iocommand.malloc_size > MAX_KMALLOC_SIZE)
+			return -EINVAL;
+		if (iocommand.buf_size > iocommand.malloc_size * MAXSGENTRIES)
+			return -EINVAL;
+		if (iocommand.buf_size > 0) {
+			__u32   size_left_alloc = iocommand.buf_size;
+			BYTE    *data_ptr = (BYTE *) iocommand.buf;
+			while (size_left_alloc > 0) {
+				buff_size[sg_used] = (size_left_alloc 
+							> iocommand.malloc_size)
+					? iocommand.malloc_size : size_left_alloc;
+				buff[sg_used] = kmalloc( buff_size[sg_used], 
+						GFP_KERNEL);
+				if (buff[sg_used] == NULL) {
+					status = -ENOMEM;
+					goto cleanup1;
+				}
+				if (iocommand.Request.Type.Direction == 
+						XFER_WRITE)
+				   /* Copy the data into the buffer created */
+				   if (copy_from_user(buff[sg_used], data_ptr, 
+						buff_size[sg_used])) {
+					status = -ENOMEM;
+					goto cleanup1;			
+				   }
+				size_left_alloc -= buff_size[sg_used];
+				data_ptr += buff_size[sg_used];
+				sg_used++;
+			}
+			
+		}
+		if ((c = cmd_alloc(h , 0)) == NULL) {
+			status = -ENOMEM;
+			goto cleanup1;	
+		}
+		/* Fill in the command type */
+		c->cmd_type = CMD_IOCTL_PEND;
+		/* Fill in Command Header */
+		c->Header.ReplyQueue = 0;  /* unused in simple mode */
+		
+		if (iocommand.buf_size > 0) { 	/* buffer to fill */
+			c->Header.SGList = sg_used;
+			c->Header.SGTotal= sg_used;
+		} else	{	/* no buffers to fill */
+			c->Header.SGList = 0;
+			c->Header.SGTotal= 0;
+		}
+		c->Header.LUN = iocommand.LUN_info;
+		c->Header.Tag.lower = c->busaddr;  /* use the kernel address */
+						/* the cmd block for tag */
+		
+	/* Fill in Request block */
+	c->Request = iocommand.Request; 
+	/* Fill in the scatter gather information */
+	if (iocommand.buf_size > 0 ) {
+		int i;
+		for(i=0; i< sg_used; i++) {
+			temp64.val = pci_map_single( h->pdev, buff[i], 
+					buff_size[i], 
+					PCI_DMA_BIDIRECTIONAL);
+
+			c->SG[i].Addr.lower = temp64.val32.lower;
+			c->SG[i].Addr.upper = temp64.val32.upper;
+			c->SG[i].Len = buff_size[i];
+			c->SG[i].Ext = 0;  /* we are not chaining */
+		}
+	}
+	c->waiting = &wait;
+	/* Put the request on the tail of the request queue */
+	spin_lock_irqsave(&io_request_lock, flags);
+	addQ(&h->reqQ, c);
+	h->Qdepth++;
+	start_io(h);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	wait_for_completion(&wait);
+	/* unlock the buffers from DMA */
+	for(i=0; i< sg_used; i++) {
+		temp64.val32.lower = c->SG[i].Addr.lower;
+		temp64.val32.upper = c->SG[i].Addr.upper;
+		pci_unmap_single( h->pdev, (dma_addr_t) temp64.val,
+				buff_size[i], PCI_DMA_BIDIRECTIONAL);
+	}
+	/* Copy the error information out */
+		iocommand.error_info = *(c->err_info);
+		if (copy_to_user((void *) arg, &iocommand, 
+					sizeof( IOCTL_Command_struct) ) ) {
+				cmd_free(h, c, 0);
+				status = -EFAULT;
+				goto cleanup1;
+		}
+		if (iocommand.Request.Type.Direction == XFER_READ) {
+		/* Copy the data out of the buffer we created */
+			BYTE *ptr = (BYTE  *) iocommand.buf;
+	        	for(i=0; i< sg_used; i++) {
+				if (copy_to_user(ptr, buff[i], buff_size[i])) {
+					cmd_free(h, c, 0);
+					status = -EFAULT;
+					goto cleanup1;
+
+				}
+				ptr += buff_size[i];
+			}
+		}
+		cmd_free(h, c, 0);
+		status = 0;
+		
 
+cleanup1:
+		for(i=0; i< sg_used; i++) {
+			if (buff[i] != NULL)
+				kfree(buff[i]);
+		}
+		return status;
+	}
 	default:
 		return -EBADRQC;
 	}
@@ -837,6 +1041,642 @@
 #endif /* CCISS_DEBUG */ 
 	return revalidate_logvol(dev, 0);
 }
+static int deregister_disk(int ctlr, int logvol)
+{
+	unsigned long flags;
+	struct gendisk *gdev = &(hba[ctlr]->gendisk);
+	ctlr_info_t  *h = hba[ctlr];
+	int start, max_p, i;
+
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	/* make sure logical volume is NOT is use */
+	if (h->drv[logvol].usage_count > 1 || h->busy_configuring) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return -EBUSY;
+	}
+	h->busy_configuring = 1;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	/* invalidate the devices and deregister the disk */
+	max_p = gdev->max_p;
+	start = logvol << gdev->minor_shift;
+	for (i=max_p-1; i>=0; i--) {
+		int minor = start+i;
+		/* printk("invalidating( %d %d)\n", ctlr, minor); */
+		invalidate_device(MKDEV(MAJOR_NR+ctlr, minor), 1);
+		/* so open will now fail */
+		h->sizes[minor] = 0;
+		/* so it will no longer appear in /proc/partitions */
+		gdev->part[minor].start_sect = 0;
+		gdev->part[minor].nr_sects = 0;
+	}
+	/* check to see if it was the last disk */
+	if (logvol == h->highest_lun) {
+		/* if so, find the new hightest lun */
+		int i, newhighest =-1;
+		for(i=0; i<h->highest_lun; i++) {
+			/* if the disk has size > 0, it is available */
+			if (h->sizes[i << gdev->minor_shift] != 0)
+				newhighest = i;
+		}
+		h->highest_lun = newhighest;
+
+	}
+	--h->num_luns;
+	gdev->nr_real = h->highest_lun+1;
+	/* zero out the disk size info */
+	h->drv[logvol].nr_blocks = 0;
+	h->drv[logvol].block_size = 0;
+	h->drv[logvol].cylinders = 0;
+	h->drv[logvol].LunID = 0;
+	h->busy_configuring = 0;
+	return 0;
+}
+static int sendcmd_withirq(__u8	cmd,
+	int	ctlr,
+	void	*buff,
+	size_t	size,
+	unsigned int use_unit_num,
+	unsigned int log_unit,
+	__u8	page_code )
+{
+	ctlr_info_t *h = hba[ctlr];
+	CommandList_struct *c;
+	u64bit	buff_dma_handle;
+	unsigned long flags;
+	int return_status = IO_OK;
+	DECLARE_COMPLETION(wait);
+
+	if ((c = cmd_alloc(h , 0)) == NULL)
+		return -ENOMEM;
+	c->cmd_type = CMD_IOCTL_PEND;
+	/* Fill in Command Header */
+	c->Header.ReplyQueue = 0;  /* unused in simple mode */
+	if (buff != NULL) { 	/* buffer to fill */
+		c->Header.SGList = 1;
+		c->Header.SGTotal= 1;
+	} else {
+		/* no buffers to fill */
+		c->Header.SGList = 0;
+		c->Header.SGTotal= 0;
+	}
+	c->Header.Tag.lower = c->busaddr;  /* tag is phys addr of cmd */
+	/* Fill in Request block */
+	switch (cmd) {
+		case  CISS_INQUIRY:
+			/* If the logical unit number is 0 then, this is going
+				to controller so It's a physical command
+				mode = 0 target = 0.
+				So we have nothing to write.
+				Otherwise
+				mode = 1  target = LUNID
+			*/
+			if (use_unit_num != 0) {
+				c->Header.LUN.LogDev.VolId =
+					hba[ctlr]->drv[log_unit].LunID;
+				c->Header.LUN.LogDev.Mode = 1;
+			}
+			if (page_code != 0) {
+				c->Request.CDB[1] = 0x01;
+				c->Request.CDB[2] = page_code;
+			}
+			c->Request.CDBLen = 6;
+			c->Request.Type.Type =  TYPE_CMD;
+			c->Request.Type.Attribute = ATTR_SIMPLE;
+			c->Request.Type.Direction = XFER_READ; /* Read */
+			c->Request.Timeout = 0; /* Don't time out */
+			c->Request.CDB[0] =  CISS_INQUIRY;
+			c->Request.CDB[4] = size  & 0xFF;
+		break;
+		case CISS_REPORT_LOG:
+			/* Talking to controller so It's a physical command
+				mode = 00 target = 0.
+				So we have nothing to write.
+			*/
+			c->Request.CDBLen = 12;
+			c->Request.Type.Type =  TYPE_CMD;
+			c->Request.Type.Attribute = ATTR_SIMPLE;
+			c->Request.Type.Direction = XFER_READ; /* Read */
+			c->Request.Timeout = 0; /* Don't time out */
+			c->Request.CDB[0] = CISS_REPORT_LOG;
+			c->Request.CDB[6] = (size >> 24) & 0xFF;  /* MSB */
+			c->Request.CDB[7] = (size >> 16) & 0xFF;
+			c->Request.CDB[8] = (size >> 8) & 0xFF;
+			c->Request.CDB[9] = size & 0xFF;
+		break;
+		case CCISS_READ_CAPACITY:
+			c->Header.LUN.LogDev.VolId=
+				hba[ctlr]->drv[log_unit].LunID;
+			c->Header.LUN.LogDev.Mode = 1;
+			c->Request.CDBLen = 10;
+			c->Request.Type.Type =  TYPE_CMD; /* It is a command. */
+			c->Request.Type.Attribute = ATTR_SIMPLE;
+			c->Request.Type.Direction = XFER_READ; /* Read */
+			c->Request.Timeout = 0; /* Don't time out */
+			c->Request.CDB[0] = CCISS_READ_CAPACITY;
+		break;
+		default:
+			printk(KERN_WARNING
+				"cciss:  Unknown Command 0x%x sent attempted\n",				cmd);
+			cmd_free(h, c, 1);
+			return IO_ERROR;
+	};
+
+	/* Fill in the scatter gather information */
+	if (size > 0) {
+		buff_dma_handle.val = (__u64) pci_map_single( h->pdev,
+			buff, size, PCI_DMA_BIDIRECTIONAL);
+		c->SG[0].Addr.lower = buff_dma_handle.val32.lower;
+		c->SG[0].Addr.upper = buff_dma_handle.val32.upper;
+		c->SG[0].Len = size;
+		c->SG[0].Ext = 0;  /* we are not chaining */
+	}
+
+resend_cmd2:
+	c->waiting = &wait;
+	/* Put the request on the tail of the queue and send it */
+	spin_lock_irqsave(&io_request_lock, flags);
+	addQ(&h->reqQ, c);
+	h->Qdepth++;
+	start_io(h);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	wait_for_completion(&wait);
+
+
+	if (c->err_info->CommandStatus != 0) {
+		/* an error has occurred */
+		switch (c->err_info->CommandStatus) {
+			case CMD_TARGET_STATUS:
+				printk(KERN_WARNING "cciss: cmd %p has "
+					" completed with errors\n", c);
+				if (c->err_info->ScsiStatus) {
+					printk(KERN_WARNING "cciss: cmd %p "
+					"has SCSI Status = %x\n", c,
+						c->err_info->ScsiStatus);
+				}
+			break;
+			case CMD_DATA_UNDERRUN:
+			case CMD_DATA_OVERRUN:
+			/* expected for inquire and report lun commands */
+			break;
+			case CMD_INVALID:
+				printk(KERN_WARNING "cciss: cmd %p is "
+					"reported invalid\n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_PROTOCOL_ERR:
+				printk(KERN_WARNING "cciss: cmd %p has "
+					"protocol error \n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_HARDWARE_ERR:
+				printk(KERN_WARNING "cciss: cmd %p had "
+					" hardware error\n", c);
+				return_status = IO_ERROR;
+				break;
+			case CMD_CONNECTION_LOST:
+				printk(KERN_WARNING "cciss: cmd %p had "
+					"connection lost\n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_ABORTED:
+				printk(KERN_WARNING "cciss: cmd %p was "
+					"aborted\n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_ABORT_FAILED:
+				printk(KERN_WARNING "cciss: cmd %p reports "
+					"abort failed\n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_UNSOLICITED_ABORT:
+				printk(KERN_WARNING "cciss: cmd %p aborted "
+					"do to an unsolicited abort\n", c);
+				if (c->retry_count < MAX_CMD_RETRIES) 
+				{ 
+					printk(KERN_WARNING "retrying cmd\n"); 
+					c->retry_count++; 
+					/* erase the old error */ 
+					/* information */ 
+					memset(c->err_info, 0, 
+						sizeof(ErrorInfo_struct)); 
+					return_status = IO_OK;
+					INIT_COMPLETION(wait);
+					goto resend_cmd2;
+					
+				}
+				return_status = IO_ERROR;
+			break;
+			default:
+				printk(KERN_WARNING "cciss: cmd %p returned "
+					"unknown status %x\n", c,
+						c->err_info->CommandStatus);
+				return_status = IO_ERROR;
+		}
+	}
+
+	/* unlock the buffers from DMA */
+	pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val,
+			size, PCI_DMA_BIDIRECTIONAL);
+	cmd_free(h, c, 0);
+	return return_status;
+}
+static int register_new_disk(int ctlr, int opened_vol, __u64 requested_lun)
+{
+	struct gendisk *gdev = &(hba[ctlr]->gendisk);
+	ctlr_info_t  *h = hba[ctlr];
+	int start, max_p, i;
+	int num_luns;
+	int logvol;
+	int new_lun_found = 0;
+	int new_lun_index = 0;
+	int free_index_found = 0;
+	int free_index = 0;
+	ReportLunData_struct *ld_buff;
+	ReadCapdata_struct *size_buff;
+	InquiryData_struct *inq_buff;
+	int return_code;
+	int listlength = 0;
+	__u32 lunid = 0;
+	unsigned int block_size;
+	unsigned int total_size;
+	unsigned long flags;
+	int req_lunid = (int) (requested_lun & (__u64) 0xffffffff);
+
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+	/* if we have no space in our disk array left to add anything */
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (h->num_luns >= CISS_MAX_LUN) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return -EINVAL;
+	}
+	if (h->busy_configuring) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return -EBUSY;
+	}
+	h->busy_configuring = 1;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
+	if (ld_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		h->busy_configuring = 0;
+		return -ENOMEM;
+	}
+	memset(ld_buff, 0, sizeof(ReportLunData_struct));
+	size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
+	if (size_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		kfree(ld_buff);
+		h->busy_configuring = 0;
+		return -ENOMEM;
+	}
+	inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+	if (inq_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		kfree(ld_buff);
+		kfree(size_buff);
+		h->busy_configuring = 0;
+		return -ENOMEM;
+	}
+
+	return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff,
+			sizeof(ReportLunData_struct), 0, 0, 0 );
+
+	if (return_code == IO_OK) {
+		/* printk("LUN Data\n--------------------------\n"); */
+		listlength |= (0xff &
+			(unsigned int)(ld_buff->LUNListLength[0])) << 24;
+		listlength |= (0xff &
+			(unsigned int)(ld_buff->LUNListLength[1])) << 16;
+		listlength |= (0xff &
+			(unsigned int)(ld_buff->LUNListLength[2])) << 8;
+		listlength |= 0xff &
+			(unsigned int)(ld_buff->LUNListLength[3]);
+	} else {
+		/* reading number of logical volumes failed */
+		printk(KERN_WARNING "cciss: report logical volume"
+			" command failed\n");
+		listlength = 0;
+		h->busy_configuring = 0;
+		return -1;
+	}
+	num_luns = listlength / 8; /* 8 bytes pre entry */
+	if (num_luns > CISS_MAX_LUN)
+		num_luns = CISS_MAX_LUN;
+
+#ifdef CCISS_DEBUG
+	printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0],
+		ld_buff->LUNListLength[1], ld_buff->LUNListLength[2],
+		ld_buff->LUNListLength[3],  num_luns);
+#endif
+	for(i=0; i<  num_luns; i++) {
+		int j;
+		int lunID_found = 0;
+
+		lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24;
+		lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16;
+		lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8;
+		lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
+
+		/* check to see if this is a new lun */
+		for(j=0; j <= h->highest_lun; j++) {
+#ifdef CCISS_DEBUG
+			printk("Checking %d %x against %x\n", j,h->drv[j].LunID,
+						lunid);
+#endif /* CCISS_DEBUG */
+			if (h->drv[j].LunID == lunid) {
+				lunID_found = 1;
+				break;
+			}
+
+		}
+		if (lunID_found == 1)
+			continue;
+		else {	/* new lun found */
+			
+#ifdef CCISS_DEBUG
+			printk("new lun found at %d\n", i);
+#endif /* CCISS_DEBUG */
+			if (req_lunid)  /* we are looking for a specific lun */
+			{
+				if (lunid != req_lunid)
+				{
+#ifdef CCISS_DEBUG
+					printk("new lun %x is not %x\n",
+							lunid, req_lunid);
+#endif /* CCISS_DEBUG */
+					continue;
+				}
+			}
+			new_lun_index = i;
+			new_lun_found = 1;
+			break;
+		}
+	}
+	if (!new_lun_found) {
+		printk(KERN_DEBUG "cciss:  New Logical Volume not found\n");
+		h->busy_configuring = 0;
+		return -1;
+	}
+	/* Now find the free index 	*/
+	for(i=0; i <CISS_MAX_LUN; i++) {
+#ifdef CCISS_DEBUG
+		printk("Checking Index %d\n", i);
+#endif /* CCISS_DEBUG */
+		if (hba[ctlr]->drv[i].LunID == 0) {
+#ifdef CCISS_DEBUG
+			printk("free index found at %d\n", i);
+#endif /* CCISS_DEBUG */
+			free_index_found = 1;
+			free_index = i;
+			break;
+		}
+	}
+	if (!free_index_found) {
+		printk(KERN_WARNING "cciss: unable to find free slot for disk\n");
+		h->busy_configuring = 0;
+		return -1;
+	}
+
+	logvol = free_index;
+	hba[ctlr]->drv[logvol].LunID = lunid;
+		/* there could be gaps in lun numbers, track hightest */
+	if (hba[ctlr]->highest_lun < logvol)
+		hba[ctlr]->highest_lun = logvol;
+
+	memset(size_buff, 0, sizeof(ReadCapdata_struct));
+	return_code = sendcmd_withirq(CCISS_READ_CAPACITY, ctlr,
+			size_buff, sizeof(ReadCapdata_struct), 1,
+			logvol, 0 );
+	if (return_code == IO_OK) {
+		total_size = (0xff &
+			(unsigned int) size_buff->total_size[0]) << 24;
+		total_size |= (0xff &
+			(unsigned int) size_buff->total_size[1]) << 16;
+		total_size |= (0xff &
+			(unsigned int) size_buff->total_size[2]) << 8;
+		total_size |= (0xff &
+			(unsigned int) size_buff->total_size[3]);
+		total_size++; /* command returns highest block address */
+
+		block_size = (0xff &
+			(unsigned int) size_buff->block_size[0]) << 24;
+		block_size |= (0xff &
+			(unsigned int) size_buff->block_size[1]) << 16;
+		block_size |= (0xff &
+			(unsigned int) size_buff->block_size[2]) << 8;
+		block_size |= (0xff &
+			(unsigned int) size_buff->block_size[3]);
+	} else {
+		/* read capacity command failed */
+		printk(KERN_WARNING "cciss: read capacity failed\n");
+		total_size = 0;
+		block_size = BLOCK_SIZE;
+	}
+	printk(KERN_INFO "      blocks= %d block_size= %d\n",
+					total_size, block_size);
+	/* Execute the command to read the disk geometry */
+	memset(inq_buff, 0, sizeof(InquiryData_struct));
+	return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buff,
+		sizeof(InquiryData_struct), 1, logvol ,0xC1 );
+	if (return_code == IO_OK) {
+		if (inq_buff->data_byte[8] == 0xFF) {
+			printk(KERN_WARNING
+			"cciss: reading geometry failed, "
+			"volume does not support reading geometry\n");
+
+			hba[ctlr]->drv[logvol].block_size = block_size;
+			hba[ctlr]->drv[logvol].nr_blocks = total_size;
+			hba[ctlr]->drv[logvol].heads = 255;
+			hba[ctlr]->drv[logvol].sectors = 32; /* secs/trk */
+			hba[ctlr]->drv[logvol].cylinders = total_size / 255 /32;
+			hba[ctlr]->drv[logvol].raid_level = RAID_UNKNOWN;
+		} else {
+			hba[ctlr]->drv[logvol].block_size = block_size;
+			hba[ctlr]->drv[logvol].nr_blocks = total_size;
+			hba[ctlr]->drv[logvol].heads = inq_buff->data_byte[6];
+			hba[ctlr]->drv[logvol].sectors = inq_buff->data_byte[7];
+			hba[ctlr]->drv[logvol].cylinders =
+				(inq_buff->data_byte[4] & 0xff) << 8;
+			hba[ctlr]->drv[logvol].cylinders +=
+				inq_buff->data_byte[5];
+			hba[ctlr]->drv[logvol].raid_level = 
+				inq_buff->data_byte[8];
+		}
+	} else {
+		/* Get geometry failed */
+		printk(KERN_WARNING "cciss: reading geometry failed, "
+			"continuing with default geometry\n");
+
+		hba[ctlr]->drv[logvol].block_size = block_size;
+		hba[ctlr]->drv[logvol].nr_blocks = total_size;
+		hba[ctlr]->drv[logvol].heads = 255;
+		hba[ctlr]->drv[logvol].sectors = 32; /* Sectors per track */
+		hba[ctlr]->drv[logvol].cylinders = total_size / 255 / 32;
+	}
+	if (hba[ctlr]->drv[logvol].raid_level > 5)
+		hba[ctlr]->drv[logvol].raid_level = RAID_UNKNOWN;
+	printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d RAID %s\n\n",
+		hba[ctlr]->drv[logvol].heads,
+		hba[ctlr]->drv[logvol].sectors,
+		hba[ctlr]->drv[logvol].cylinders, 
+		raid_label[hba[ctlr]->drv[logvol].raid_level]);
+
+	/* special case for c?d0, which may be opened even when
+	   it does not "exist".  In that case, don't mess with usage count.
+	   Also, /dev/c1d1 could be used to re-add c0d0 so we can't just 
+	   check whether logvol == 0, must check logvol != opened_vol */
+	if (logvol != opened_vol)
+		hba[ctlr]->drv[logvol].usage_count = 0;
+
+	max_p = gdev->max_p;
+	start = logvol<< gdev->minor_shift;
+	hba[ctlr]->hd[start].nr_sects = total_size;
+	hba[ctlr]->sizes[start] = total_size;
+
+	for(i=max_p-1; i>=0; i--) {
+		int minor = start+i;
+		invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 1);
+		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] = block_size;
+		hba[ctlr]->hardsizes[minor] = block_size;
+	}
+
+	++hba[ctlr]->num_luns;
+	gdev->nr_real = hba[ctlr]->highest_lun + 1;
+	/* setup partitions per disk */
+	grok_partitions(gdev, logvol, MAX_PART,
+			hba[ctlr]->drv[logvol].nr_blocks);
+	kfree(ld_buff);
+	kfree(size_buff);
+	kfree(inq_buff);
+	h->busy_configuring = 0;
+	return logvol;
+}
+
+static int cciss_rescan_disk(int ctlr, int logvol)
+{
+	struct gendisk *gdev = &(hba[ctlr]->gendisk);
+	int start, max_p, i;
+	ReadCapdata_struct *size_buff;
+	InquiryData_struct *inq_buff;
+	int return_code;
+	unsigned int block_size;
+	unsigned int total_size;
+
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+	if (hba[ctlr]->sizes[logvol << NWD_SHIFT] != 0) {
+		/* disk is possible on line, return just a warning */
+		return 1;
+	}
+	size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
+	if (size_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		return -1;
+	}
+	inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+	if (inq_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		kfree(size_buff);
+		return -1;
+	}
+	memset(size_buff, 0, sizeof(ReadCapdata_struct));
+	return_code = sendcmd_withirq(CCISS_READ_CAPACITY, ctlr, size_buff,
+				sizeof( ReadCapdata_struct), 1, logvol, 0 );
+	if (return_code == IO_OK) {
+		total_size = (0xff &
+			(unsigned int)(size_buff->total_size[0])) << 24;
+		total_size |= (0xff &
+				(unsigned int)(size_buff->total_size[1])) << 16;
+		total_size |= (0xff &
+				(unsigned int)(size_buff->total_size[2])) << 8;
+		total_size |= (0xff & (unsigned int)
+				(size_buff->total_size[3]));
+		total_size++; /* command returns highest block address */
+
+		block_size = (0xff &
+				(unsigned int)(size_buff->block_size[0])) << 24;
+		block_size |= (0xff &
+				(unsigned int)(size_buff->block_size[1])) << 16;
+		block_size |= (0xff &
+				(unsigned int)(size_buff->block_size[2])) << 8;
+		block_size |= (0xff &
+				(unsigned int)(size_buff->block_size[3]));
+	} else { /* read capacity command failed */
+		printk(KERN_WARNING "cciss: read capacity failed\n");
+		total_size = block_size = 0;
+	}
+	printk(KERN_INFO "      blocks= %d block_size= %d\n",
+					total_size, block_size);
+	/* Execute the command to read the disk geometry */
+	memset(inq_buff, 0, sizeof(InquiryData_struct));
+	return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buff,
+			sizeof(InquiryData_struct), 1, logvol ,0xC1 );
+	if (return_code == IO_OK) {
+		if (inq_buff->data_byte[8] == 0xFF) {
+			printk(KERN_WARNING "cciss: reading geometry failed, "
+				"volume does not support reading geometry\n");
+
+			hba[ctlr]->drv[logvol].nr_blocks = total_size;
+			hba[ctlr]->drv[logvol].heads = 255;
+			hba[ctlr]->drv[logvol].sectors = 32; /* Sectors/track */
+			hba[ctlr]->drv[logvol].cylinders = total_size / 255 /32;
+		} else {
+			hba[ctlr]->drv[logvol].nr_blocks = total_size;
+			hba[ctlr]->drv[logvol].heads = inq_buff->data_byte[6];
+			hba[ctlr]->drv[logvol].sectors = inq_buff->data_byte[7];
+			hba[ctlr]->drv[logvol].cylinders =
+				(inq_buff->data_byte[4] & 0xff) << 8;
+			hba[ctlr]->drv[logvol].cylinders +=
+				inq_buff->data_byte[5];
+		}
+	} else { /* Get geometry failed */
+		printk(KERN_WARNING "cciss: reading geometry failed, "
+				"continuing with default geometry\n");
+
+		hba[ctlr]->drv[logvol].nr_blocks = total_size;
+		hba[ctlr]->drv[logvol].heads = 255;
+		hba[ctlr]->drv[logvol].sectors = 32; /* Sectors / track */
+		hba[ctlr]->drv[logvol].cylinders = total_size / 255 /32;
+	}
+
+	printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d \n\n", 
+		hba[ctlr]->drv[logvol].heads,
+		hba[ctlr]->drv[logvol].sectors,
+		hba[ctlr]->drv[logvol].cylinders);
+	max_p = gdev->max_p;
+	start = logvol<< gdev->minor_shift;
+	hba[ctlr]->hd[start].nr_sects = hba[ctlr]->sizes[start]= total_size;
+
+	for (i=max_p-1; i>=0; i--) {
+		int minor = start+i;
+		invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 1);
+		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;
+		hba[ctlr]->hardsizes[minor] = block_size;
+	}
+
+	/* setup partitions per disk */
+	grok_partitions(gdev, logvol, MAX_PART,
+			hba[ctlr]->drv[logvol].nr_blocks );
+
+	kfree(size_buff);
+	kfree(inq_buff);
+	return 0;
+}
 /*
  *   Wait polling for a command to complete.
  *   The memory mapped FIFO is polled for the completion.
@@ -844,20 +1684,21 @@
  */
 static unsigned long pollcomplete(int ctlr)
 {
-        unsigned long done;
-        int i;
+	unsigned long done;
+	int i;
 
-        /* Wait (up to 2 seconds) for a command to complete */
+	/* Wait (up to 20 seconds) for a command to complete */
 
-        for (i = 200000; i > 0; i--) {
-                done = hba[ctlr]->access.command_completed(hba[ctlr]);
-                if (done == FIFO_EMPTY) {
-                        udelay(10);     /* a short fixed delay */
-                } else
-                        return (done);
-        }
-        /* Invalid address to tell caller we ran out of time */
-        return 1;
+        for (i = 20 * HZ; i > 0; i--) {
+		done = hba[ctlr]->access.command_completed(hba[ctlr]);
+		if (done == FIFO_EMPTY) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(1);
+		} else
+			return done;
+	}
+	/* Invalid address to tell caller we ran out of time */
+	return 1;
 }
 /*
  * Send a command to the controller, and wait for it to complete.  
@@ -880,28 +1721,26 @@
 	unsigned long complete;
 	ctlr_info_t *info_p= hba[ctlr];
 	u64bit buff_dma_handle;
+	int status = IO_OK;
 
 	c = cmd_alloc(info_p, 1);
-	if (c == NULL)
-	{
+	if (c == NULL) {
 		printk(KERN_WARNING "cciss: unable to get memory");
-		return(IO_ERROR);
+		return IO_ERROR;
 	}
-	// Fill in Command Header 
-	c->Header.ReplyQueue = 0;  // unused in simple mode
-	if( buff != NULL) 	// buffer to fill 
-	{
+	/* Fill in Command Header */
+	c->Header.ReplyQueue = 0;  /* unused in simple mode */
+	if (buff != NULL) { 	/* buffer to fill */
 		c->Header.SGList = 1;
 		c->Header.SGTotal= 1;
-	} else	// no buffers to fill  
-	{
+	} else	{	/* no buffers to fill  */
 		c->Header.SGList = 0;
                 c->Header.SGTotal= 0;
 	}
-	c->Header.Tag.lower = c->busaddr;  // use the kernel address the cmd block for tag
-	// Fill in Request block 	
-	switch(cmd)
-	{
+	c->Header.Tag.lower = c->busaddr;  /* use the kernel address */
+					   /* the cmd block for tag */
+	/* Fill in Request block */
+	switch (cmd) {
 		case  CISS_INQUIRY:
 			/* If the logical unit number is 0 then, this is going
 				to controller so It's a physical command
@@ -912,29 +1751,27 @@
 				otherwise, if use_unit_num == 2,
 				mode = 0(periph dev addr) target = scsi3addr
 			*/
-			if(use_unit_num == 1)
-			{
+			if (use_unit_num == 1) {
 				c->Header.LUN.LogDev.VolId=
                                 	hba[ctlr]->drv[log_unit].LunID;
                         	c->Header.LUN.LogDev.Mode = 1;
 			}
-			else if (use_unit_num == 2)
-			{
+			else if (use_unit_num == 2) {
 				memcpy(c->Header.LUN.LunAddrBytes,scsi3addr,8);
-				c->Header.LUN.LogDev.Mode = 0; // phys dev addr
+				c->Header.LUN.LogDev.Mode = 0; 
+							/* phys dev addr */
 			}
 
 			/* are we trying to read a vital product page */
-			if(page_code != 0)
-			{
+			if (page_code != 0) {
 				c->Request.CDB[1] = 0x01;
 				c->Request.CDB[2] = page_code;
 			}
 			c->Request.CDBLen = 6;
-			c->Request.Type.Type =  TYPE_CMD; // It is a command. 
+			c->Request.Type.Type =  TYPE_CMD; /* It is a command. */
 			c->Request.Type.Attribute = ATTR_SIMPLE;  
-			c->Request.Type.Direction = XFER_READ; // Read 
-			c->Request.Timeout = 0; // Don't time out 
+			c->Request.Type.Direction = XFER_READ; /* Read */
+			c->Request.Timeout = 0; /* Don't time out */
 			c->Request.CDB[0] =  CISS_INQUIRY;
 			c->Request.CDB[4] = size  & 0xFF;  
 		break;
@@ -945,12 +1782,12 @@
                                 So we have nothing to write.
                         */
                         c->Request.CDBLen = 12;
-                        c->Request.Type.Type =  TYPE_CMD; // It is a command.
+                        c->Request.Type.Type =  TYPE_CMD; /* It is a command. */
                         c->Request.Type.Attribute = ATTR_SIMPLE; 
-                        c->Request.Type.Direction = XFER_READ; // Read
-                        c->Request.Timeout = 0; // Don't time out
+                        c->Request.Type.Direction = XFER_READ; /* Read */
+                        c->Request.Timeout = 0; /* Don't time out */
 			c->Request.CDB[0] = cmd;
-                        c->Request.CDB[6] = (size >> 24) & 0xFF;  //MSB
+                        c->Request.CDB[6] = (size >> 24) & 0xFF;  /* MSB */
                         c->Request.CDB[7] = (size >> 16) & 0xFF;
                         c->Request.CDB[8] = (size >> 8) & 0xFF;
                         c->Request.CDB[9] = size & 0xFF;
@@ -961,38 +1798,38 @@
 				hba[ctlr]->drv[log_unit].LunID;
 			c->Header.LUN.LogDev.Mode = 1;
 			c->Request.CDBLen = 10;
-                        c->Request.Type.Type =  TYPE_CMD; // It is a command.
+                        c->Request.Type.Type =  TYPE_CMD; /* It is a command. */
                         c->Request.Type.Attribute = ATTR_SIMPLE; 
-                        c->Request.Type.Direction = XFER_READ; // Read
-                        c->Request.Timeout = 0; // Don't time out
+                        c->Request.Type.Direction = XFER_READ; /* Read */
+                        c->Request.Timeout = 0; /* Don't time out */
                         c->Request.CDB[0] = CCISS_READ_CAPACITY;
 		break;
 		case CCISS_CACHE_FLUSH:
 			c->Request.CDBLen = 12;
-			c->Request.Type.Type =  TYPE_CMD; // It is a command.
+			c->Request.Type.Type =  TYPE_CMD; /* It is a command. */
 			c->Request.Type.Attribute = ATTR_SIMPLE;
-			c->Request.Type.Direction = XFER_WRITE; // No data
-			c->Request.Timeout = 0; // Don't time out
-			c->Request.CDB[0] = BMIC_WRITE;  // BMIC Passthru
+			c->Request.Type.Direction = XFER_WRITE; /* No data */
+			c->Request.Timeout = 0; /* Don't time out */
+			c->Request.CDB[0] = BMIC_WRITE;  /* BMIC Passthru */
 			c->Request.CDB[6] = BMIC_CACHE_FLUSH;
 		break;
 		default:
 			printk(KERN_WARNING
-				"cciss:  Unknown Command 0x%c sent attempted\n",
+				"cciss:  Unknown Command 0x%x sent attempted\n",
 				  cmd);
 			cmd_free(info_p, c, 1);
-			return(IO_ERROR);
+			return IO_ERROR;
 	};
-	// Fill in the scatter gather information
-	if (size > 0 ) 
-	{
+	/* Fill in the scatter gather information */
+	if (size > 0) {
 		buff_dma_handle.val = (__u64) pci_map_single( info_p->pdev, 
 			buff, size, PCI_DMA_BIDIRECTIONAL);
 		c->SG[0].Addr.lower = buff_dma_handle.val32.lower;
 		c->SG[0].Addr.upper = buff_dma_handle.val32.upper;
 		c->SG[0].Len = size;
-		c->SG[0].Ext = 0;  // we are not chaining
+		c->SG[0].Ext = 0;  /* we are not chaining */
 	}
+resend_cmd1:
 	/*
          * Disable interrupt
          */
@@ -1003,11 +1840,9 @@
 	
 	/* Make sure there is room in the command FIFO */
         /* Actually it should be completely empty at this time. */
-        for (i = 200000; i > 0; i--) 
-	{
+        for (i = 200000; i > 0; i--) {
 		/* if fifo isn't full go */
-                if (!(info_p->access.fifo_full(info_p))) 
-		{
+                if (!(info_p->access.fifo_full(info_p))) {
 			
                         break;
                 }
@@ -1025,13 +1860,9 @@
 	printk(KERN_DEBUG "cciss: command completed\n");
 #endif /* CCISS_DEBUG */
 
-	/* unlock the data buffer from DMA */
-	pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
-                                size, PCI_DMA_BIDIRECTIONAL);
 	if (complete != 1) {
 		if ( (complete & CISS_ERROR_BIT)
-		     && (complete & ~CISS_ERROR_BIT) == c->busaddr)
-		     {
+		     && (complete & ~CISS_ERROR_BIT) == c->busaddr) {
 			/* if data overrun or underun on Report command 
 				ignore it 
 			*/
@@ -1042,41 +1873,64 @@
 					CMD_DATA_OVERRUN) || 
 				 (c->err_info->CommandStatus == 
 					CMD_DATA_UNDERRUN)
-			 	))
-			{
+			 	)) {
 				complete = c->busaddr;
-			} else
-			{
-				printk(KERN_WARNING "ciss ciss%d: sendcmd"
+			} else {
+				if (c->err_info->CommandStatus == 
+						CMD_UNSOLICITED_ABORT) {
+					printk(KERN_WARNING "cciss: "
+						"cmd %p aborted do "
+					"to an unsolicited abort \n", c); 
+					if (c->retry_count < MAX_CMD_RETRIES) {
+						printk(KERN_WARNING
+						   "retrying cmd\n");
+						c->retry_count++;
+						/* erase the old error */
+						/* information */
+						memset(c->err_info, 0, 
+						   sizeof(ErrorInfo_struct));
+						goto resend_cmd1;
+					} else {
+						printk(KERN_WARNING
+						   "retried to many times\n");
+						status = IO_ERROR;
+						goto cleanup1;
+					}
+				}
+				printk(KERN_WARNING "cciss cciss%d: sendcmd"
 				" Error %x \n", ctlr, 
 					c->err_info->CommandStatus); 
-				printk(KERN_WARNING "ciss ciss%d: sendcmd"
+				printk(KERN_WARNING "cciss cciss%d: sendcmd"
 				" offensive info\n"
 				"  size %x\n   num %x   value %x\n", ctlr,
 				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_size,
 				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_num,
 				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_value);
-				cmd_free(info_p,c, 1);
-				return(IO_ERROR);
+				status = IO_ERROR;
+				goto cleanup1;
 			}
 		}
                 if (complete != c->busaddr) {
                         printk( KERN_WARNING "cciss cciss%d: SendCmd "
                       "Invalid command list address returned! (%lx)\n",
                                 ctlr, complete);
-                        cmd_free(info_p, c, 1);
-                        return (IO_ERROR);
+                        status = IO_ERROR;
+			goto cleanup1;
                 }
         } else {
                 printk( KERN_WARNING
                         "cciss cciss%d: SendCmd Timeout out, "
                         "No command list address returned!\n",
                         ctlr);
-                cmd_free(info_p, c, 1);
-                return (IO_ERROR);
+                status = IO_ERROR;
         }
+		
+cleanup1:	
+	/* unlock the data buffer from DMA */
+	pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
+                                size, PCI_DMA_BIDIRECTIONAL);
 	cmd_free(info_p, c, 1);
-        return (IO_OK);
+        return status;
 } 
 /*
  * Map (physical) PCI mem into (virtual) kernel space
@@ -1127,11 +1981,9 @@
 {
 	CommandList_struct *c;
 	
-	while(( c = h->reqQ) != NULL )
-	{
+	while(( c = h->reqQ) != NULL ) {
 		/* can't do anything if fifo is full */
-		if ((h->access.fifo_full(h)))
-		{
+		if ((h->access.fifo_full(h))) {
 			printk(KERN_WARNING "cciss: fifo full \n");
 			return;
 		}
@@ -1151,8 +2003,7 @@
 {
 	struct buffer_head *xbh;
 	
-	while(bh)
-	{
+	while(bh) {
 		xbh = bh->b_reqnext; 
 		bh->b_reqnext = NULL; 
 		blk_finished_io(bh->b_size >> 9);
@@ -1160,39 +2011,44 @@
 		bh = xbh;
 	}
 } 
+/* This code assumes io_request_lock is already held */
+/* Zeros out the error record and then resends the command back */
+/* to the controller */ 
+static inline void resend_cciss_cmd( ctlr_info_t *h, CommandList_struct *c)
+{
+	/* erase the old error information */
+	memset(c->err_info, 0, sizeof(ErrorInfo_struct));
+
+	/* add it to software queue and then send it to the controller */
+	addQ(&(h->reqQ),c);
+	h->Qdepth++;
+	if (h->Qdepth > h->maxQsinceinit)
+		h->maxQsinceinit = h->Qdepth; 
+
+	start_io(h);
+}
 /* checks the status of the job and calls complete buffers to mark all 
  * buffers for the completed job. 
  */ 
-static inline void complete_command( CommandList_struct *cmd, int timeout)
+static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd, 
+		int timeout)
 {
 	int status = 1;
+	int retry_cmd = 0;
 	int i, ddir;
 	u64bit temp64;
 		
 	if (timeout)
 		status = 0; 
-	/* unmap the DMA mapping for all the scatter gather elements */
-	if (cmd->Request.Type.Direction == XFER_READ)
-		ddir = PCI_DMA_FROMDEVICE;
-	else
-		ddir = PCI_DMA_TODEVICE;
-	for(i=0; i<cmd->Header.SGList; i++)
-	{
-		temp64.val32.lower = cmd->SG[i].Addr.lower;
-		temp64.val32.upper = cmd->SG[i].Addr.upper;
-		pci_unmap_page(hba[cmd->ctlr]->pdev,
-			temp64.val, cmd->SG[i].Len, ddir);
-	}
 
-	if(cmd->err_info->CommandStatus != 0) 
-	{ /* an error has occurred */ 
-		switch(cmd->err_info->CommandStatus)
-		{
+	if (cmd->err_info->CommandStatus != 0) { 
+		/* an error has occurred */ 
+		switch (cmd->err_info->CommandStatus) {
 			unsigned char sense_key;
 			case CMD_TARGET_STATUS:
 				status = 0;
 			
-				if( cmd->err_info->ScsiStatus == 0x02) {
+				if (cmd->err_info->ScsiStatus == 0x02) {
 					printk(KERN_WARNING "cciss: cmd %p "
 						"has CHECK CONDITION,"
 						" sense key = 0x%x\n", cmd,
@@ -1200,10 +2056,9 @@
 					/* check the sense key */
 					sense_key = 0xf & 
 						cmd->err_info->SenseInfo[2];
-					/* no status or recovered error */
-					if ((sense_key == 0x0) ||
-						(sense_key == 0x1))
-							status = 1;
+					/* recovered error */
+					if ( sense_key == 0x1)
+						status = 1;
 				} else {
 					printk(KERN_WARNING "cciss: cmd %p "
 						"has SCSI Status 0x%x\n",
@@ -1251,8 +2106,18 @@
 				status=0;
 			break;
 			case CMD_UNSOLICITED_ABORT:
-				printk(KERN_WARNING "cciss: cmd %p aborted "
-					"do to an unsolicited abort\n", cmd);
+				printk(KERN_WARNING "cciss: cmd %p aborted do "
+					"to an unsolicited abort \n",
+				       	cmd);
+				if (cmd->retry_count < MAX_CMD_RETRIES) {
+					retry_cmd=1;
+					printk(KERN_WARNING
+						"retrying cmd\n");
+					cmd->retry_count++;
+				} else {
+					printk(KERN_WARNING
+					"retried to many times\n");
+				}
 				status=0;
 			break;
 			case CMD_TIMEOUT:
@@ -1267,12 +2132,29 @@
 				status=0;
 		}
 	}
+	/* We need to return this command */
+	if (retry_cmd) {
+		resend_cciss_cmd(h,cmd);
+		return;
+	}	
+	/* command did not need to be retried */
+	/* unmap the DMA mapping for all the scatter gather elements */
+	if (cmd->Request.Type.Direction == XFER_READ)
+		ddir = PCI_DMA_FROMDEVICE;
+	else
+		ddir = PCI_DMA_TODEVICE;
+	for(i=0; i<cmd->Header.SGList; i++) {
+		temp64.val32.lower = cmd->SG[i].Addr.lower;
+		temp64.val32.upper = cmd->SG[i].Addr.upper;
+		pci_unmap_page(hba[cmd->ctlr]->pdev,
+			temp64.val, cmd->SG[i].Len, ddir);
+	}
 	complete_buffers(cmd->rq->bh, status);
-
 #ifdef CCISS_DEBUG
 	printk("Done with %p\n", cmd->rq);
 #endif /* CCISS_DEBUG */ 
 	end_that_request_last(cmd->rq);
+	cmd_free(h,cmd,1);
 }
 
 
@@ -1289,7 +2171,7 @@
 static int cpq_back_merge_fn(request_queue_t *q, struct request *rq,
                              struct buffer_head *bh, int max_segments)
 {
-	if (blk_seg_merge_ok(rq->bhtail, bh))
+	if (blk_seg_merge_ok(rq->bhtail, bh))	
                 return 1;
         return cpq_new_segment(q, rq, max_segments);
 }
@@ -1347,8 +2229,7 @@
 	if (creq->nr_segments > MAXSGENTRIES)
                 BUG();
 
-        if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR )
-        {
+        if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR ) {
                 printk(KERN_WARNING "doreq cmd for %d, %x at %p\n",
                                 h->ctlr, creq->rq_dev, creq);
                 blkdev_dequeue_request(creq);
@@ -1370,34 +2251,33 @@
 	
 	/* fill in the request */ 
 	log_unit = MINOR(creq->rq_dev) >> NWD_SHIFT; 
-	c->Header.ReplyQueue = 0;  // unused in simple mode
-	c->Header.Tag.lower = c->busaddr;  // use the physical address the cmd block for tag
+	c->Header.ReplyQueue = 0;  /* unused in simple mode */
+	c->Header.Tag.lower = c->busaddr;  /* use the physical address */
+					/* the cmd block for tag */
 	c->Header.LUN.LogDev.VolId= hba[h->ctlr]->drv[log_unit].LunID;
 	c->Header.LUN.LogDev.Mode = 1;
-	c->Request.CDBLen = 10; // 12 byte commands not in FW yet;
-	c->Request.Type.Type =  TYPE_CMD; // It is a command. 
+	c->Request.CDBLen = 10; /* 12 byte commands not in FW yet. */
+	c->Request.Type.Type =  TYPE_CMD; /* It is a command.  */
 	c->Request.Type.Attribute = ATTR_SIMPLE; 
 	c->Request.Type.Direction = 
 		(creq->cmd == READ) ? XFER_READ: XFER_WRITE; 
-	c->Request.Timeout = 0; // Don't time out	
+	c->Request.Timeout = 0; /* Don't time out */
 	c->Request.CDB[0] = (creq->cmd == READ) ? CCISS_READ : CCISS_WRITE;
 	start_blk = hba[h->ctlr]->hd[MINOR(creq->rq_dev)].start_sect + creq->sector;
 #ifdef CCISS_DEBUG
 	if (bh == NULL)
 		panic("cciss: bh== NULL?");
-	printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n",(int) creq->sector,
+	printk(KERN_DEBUG "cciss: sector =%d nr_sectors=%d\n",(int) creq->sector,
 		(int) creq->nr_sectors);	
 #endif /* CCISS_DEBUG */
 	seg = 0;
 	lastdataend = ~0ULL;
-	while(bh)
-	{
+	while(bh) {
 		if (bh_phys(bh) == lastdataend)
-		{  // tack it on to the last segment 
+		{  /* tack it on to the last segment */
 			tmp_sg[seg-1].length +=bh->b_size;
 			lastdataend += bh->b_size;
-		} else
-		{
+		} else {
 			if (seg == MAXSGENTRIES)
 				BUG();
 			tmp_sg[seg].page = bh->b_page;
@@ -1420,10 +2300,10 @@
 			    tmp_sg[i].offset, tmp_sg[i].length, ddir);
 		c->SG[i].Addr.lower = temp64.val32.lower;
                 c->SG[i].Addr.upper = temp64.val32.upper;
-                c->SG[i].Ext = 0;  // we are not chaining
+                c->SG[i].Ext = 0;  /* we are not chaining */
 	}
 	/* track how many SG entries we are using */ 
-	if( seg > h->maxSG)
+	if (seg > h->maxSG)
 		h->maxSG = seg; 
 
 #ifdef CCISS_DEBUG
@@ -1432,11 +2312,11 @@
 
 	c->Header.SGList = c->Header.SGTotal = seg;
 	c->Request.CDB[1]= 0;
-	c->Request.CDB[2]= (start_blk >> 24) & 0xff;	//MSB
+	c->Request.CDB[2]= (start_blk >> 24) & 0xff;	/* MSB */
 	c->Request.CDB[3]= (start_blk >> 16) & 0xff;
 	c->Request.CDB[4]= (start_blk >>  8) & 0xff;
 	c->Request.CDB[5]= start_blk & 0xff;
-	c->Request.CDB[6]= 0; // (sect >> 24) & 0xff; MSB
+	c->Request.CDB[6]= 0; /* (sect >> 24) & 0xff; MSB */
 	c->Request.CDB[7]= (creq->nr_sectors >>  8) & 0xff; 
 	c->Request.CDB[8]= creq->nr_sectors & 0xff; 
 	c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
@@ -1445,7 +2325,7 @@
 
 	addQ(&(h->reqQ),c);
 	h->Qdepth++;
-	if(h->Qdepth > h->maxQsinceinit)
+	if (h->Qdepth > h->maxQsinceinit)
 		h->maxQsinceinit = h->Qdepth; 
 
 	goto next;
@@ -1463,7 +2343,7 @@
 
 
 	/* Is this interrupt for us? */
-	if ( h->access.intr_pending(h) == 0)
+	if (h->access.intr_pending(h) == 0)
 		return;
 
 	/*
@@ -1471,14 +2351,11 @@
 	 * we had better do something about it.
 	 */
 	spin_lock_irqsave(&io_request_lock, flags);
-	while( h->access.intr_pending(h))
-	{
-		while((a = h->access.command_completed(h)) != FIFO_EMPTY) 
-		{
+	while( h->access.intr_pending(h)) {
+		while((a = h->access.command_completed(h)) != FIFO_EMPTY) {
 			a1 = a;
 			a &= ~3;
-			if ((c = h->cmpQ) == NULL)
-			{  
+			if ((c = h->cmpQ) == NULL) {  
 				printk(KERN_WARNING "cciss: Completion of %08lx ignored\n", (unsigned long)a1);
 				continue;	
 			} 
@@ -1494,8 +2371,7 @@
 			 if (c->busaddr == a) {
 				removeQ(&h->cmpQ, c);
 				if (c->cmd_type == CMD_RWREQ) {
-					complete_command(c, 0);
-					cmd_free(h, c, 1);
+					complete_command(h, c, 0);
 				} else if (c->cmd_type == CMD_IOCTL_PEND) {
 					complete(c->waiting);
 				}
@@ -1557,7 +2433,7 @@
 static void release_io_mem(ctlr_info_t *c)
 {
 	/* if IO mem was not protected do nothing */
-	if( c->io_mem_addr == 0)
+	if (c->io_mem_addr == 0)
 		return;
 	release_region(c->io_mem_addr, c->io_mem_length);
 	c->io_mem_addr = 0;
@@ -1582,15 +2458,13 @@
 	for(i=0; i<6; i++)
 		addr[i] = pdev->resource[i].start;
 
-	if (pci_enable_device(pdev))
-	{
+	if (pci_enable_device(pdev)) {
 		printk(KERN_ERR "cciss: Unable to Enable PCI device\n");
-		return( -1);
+		return -1;
 	}
-	if (pci_set_dma_mask(pdev, CCISS_DMA_MASK ) != 0)
-	{
+	if (pci_set_dma_mask(pdev, CCISS_DMA_MASK ) != 0) {
 		printk(KERN_ERR "cciss:  Unable to set DMA mask\n");
-		return(-1);
+		return -1;
 	}
 	
 	(void) pci_read_config_word(pdev, PCI_COMMAND,&command);
@@ -1606,7 +2480,7 @@
 	/* check to see if controller has been disabled */
 	if (!(command & 0x02)) {
 		printk(KERN_WARNING "cciss: controller appears to be disabled\n");
-		return(-1);
+		return -1;
 	}
 	/* search for our IO range so we can protect it */
 	for (i=0; i<6; i++) {
@@ -1700,8 +2574,7 @@
 	if (  (readb(&c->cfgtable->Signature[0]) != 'C') ||
 	      (readb(&c->cfgtable->Signature[1]) != 'I') ||
 	      (readb(&c->cfgtable->Signature[2]) != 'S') ||
-	      (readb(&c->cfgtable->Signature[3]) != 'S') )
-	{
+	      (readb(&c->cfgtable->Signature[3]) != 'S') ) {
 		printk("Does not appear to be a valid CISS config table\n");
 		return -1;
 	}
@@ -1714,8 +2587,7 @@
 		&(c->cfgtable->HostWrite.TransportRequest));
 	writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
 
-	for(i=0;i<MAX_CONFIG_WAIT;i++)
-	{
+	for(i=0;i<MAX_CONFIG_WAIT;i++) {
 		if (!(readl(c->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
 			break;
 		/* delay and try again */
@@ -1729,8 +2601,7 @@
 	print_cfg_table(c->cfgtable);	
 #endif /* CCISS_DEBUG */ 
 
-	if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple))
-	{
+	if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) {
 		printk(KERN_WARNING "cciss: unable to get board into"
 					" simple mode\n");
 		return -1;
@@ -1755,22 +2626,19 @@
 	int total_size; 
 
 	ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
-	if (ld_buff == NULL)
-	{
+	if (ld_buff == NULL) {
 		printk(KERN_ERR "cciss: out of memory\n");
 		return;
 	}
 	memset(ld_buff, 0, sizeof(ReportLunData_struct));
 	size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
-        if (size_buff == NULL)
-        {
+        if (size_buff == NULL) {
                 printk(KERN_ERR "cciss: out of memory\n");
 		kfree(ld_buff);
                 return;
         }
 	inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
-        if (inq_buff == NULL)
-        {
+        if (inq_buff == NULL) {
                 printk(KERN_ERR "cciss: out of memory\n");
                 kfree(ld_buff);
 		kfree(size_buff);
@@ -1779,14 +2647,12 @@
 	/* Get the firmware version */ 
 	return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, 
 		sizeof(InquiryData_struct), 0, 0 ,0, NULL);
-	if (return_code == IO_OK)
-	{
+	if (return_code == IO_OK) {
 		hba[cntl_num]->firm_ver[0] = inq_buff->data_byte[32];
 		hba[cntl_num]->firm_ver[1] = inq_buff->data_byte[33];
 		hba[cntl_num]->firm_ver[2] = inq_buff->data_byte[34];
 		hba[cntl_num]->firm_ver[3] = inq_buff->data_byte[35];
-	} else /* send command failed */
-	{
+	} else  {	/* send command failed */
 		printk(KERN_WARNING "cciss: unable to determine firmware"
 			" version of controller\n");
 	}
@@ -1794,8 +2660,7 @@
 	return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff, 
 			sizeof(ReportLunData_struct), 0, 0, 0, NULL);
 
-	if( return_code == IO_OK)
-	{
+	if (return_code == IO_OK) {
 #ifdef CCISS_DEBUG
 		printk("LUN Data\n--------------------------\n");
 #endif /* CCISS_DEBUG */ 
@@ -1804,16 +2669,14 @@
 		listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
 		listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;	
 		listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
-	} else /* reading number of logical volumes failed */
-	{
+	} else { /* reading number of logical volumes failed */
 		printk(KERN_WARNING "cciss: report logical volume"
 			" command failed\n");
 		listlength = 0;
 	}
-	hba[cntl_num]->num_luns = listlength / 8; // 8 bytes pre entry
-	if (hba[cntl_num]->num_luns > CISS_MAX_LUN)
-	{
-		printk(KERN_ERR "ciss:  only %d number of logical volumes supported\n",
+	hba[cntl_num]->num_luns = listlength / 8; /* 8 bytes pre entry */
+	if (hba[cntl_num]->num_luns > CISS_MAX_LUN) {
+		printk(KERN_ERR "cciss:  only %d number of logical volumes supported\n",
 			CISS_MAX_LUN);
 		hba[cntl_num]->num_luns = CISS_MAX_LUN;
 	}
@@ -1822,8 +2685,9 @@
 		ld_buff->LUNListLength[1], ld_buff->LUNListLength[2],
 		ld_buff->LUNListLength[3],  hba[cntl_num]->num_luns);
 #endif /* CCISS_DEBUG */
-	for(i=0; i<  hba[cntl_num]->num_luns ; i++)
-	{
+
+	hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns-1;
+	for(i=0; i<  hba[cntl_num]->num_luns; i++) {
 	  	lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24;
         	lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16;
         	lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8;
@@ -1839,8 +2703,7 @@
 	  	memset(size_buff, 0, sizeof(ReadCapdata_struct));
 	  	return_code = sendcmd(CCISS_READ_CAPACITY, cntl_num, size_buff, 
 				sizeof( ReadCapdata_struct), 1, i, 0, NULL);
-	  	if (return_code == IO_OK)
-		{
+	  	if (return_code == IO_OK) {
 			total_size = (0xff & 
 				(unsigned int)(size_buff->total_size[0])) << 24;
 			total_size |= (0xff & 
@@ -1849,7 +2712,8 @@
 				(unsigned int)(size_buff->total_size[2])) << 8;
 			total_size |= (0xff & (unsigned int)
 				(size_buff->total_size[3])); 
-			total_size++; // command returns highest block address
+			total_size++; 	/* command returns highest */
+					/* block address */
 
 			block_size = (0xff & 
 				(unsigned int)(size_buff->block_size[0])) << 24;
@@ -1859,8 +2723,7 @@
 				(unsigned int)(size_buff->block_size[2])) << 8;
                 	block_size |= (0xff & 
 				(unsigned int)(size_buff->block_size[3]));
-		} else /* read capacity command failed */ 
-		{
+		} else {	/* read capacity command failed */ 
 			printk(KERN_WARNING "cciss: read capacity failed\n");
 			total_size = block_size = 0; 
 		}	
@@ -1871,18 +2734,18 @@
 		memset(inq_buff, 0, sizeof(InquiryData_struct));
 		return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff,
 			sizeof(InquiryData_struct), 1, i, 0xC1, NULL );
-	  	if (return_code == IO_OK)
-		{
-			if(inq_buff->data_byte[8] == 0xFF)
-			{
+	  	if (return_code == IO_OK) {
+			if (inq_buff->data_byte[8] == 0xFF) {
 			   printk(KERN_WARNING "cciss: reading geometry failed, volume does not support reading geometry\n");
 
                            hba[cntl_num]->drv[i].block_size = block_size;
                            hba[cntl_num]->drv[i].nr_blocks = total_size;
                            hba[cntl_num]->drv[i].heads = 255;
-                           hba[cntl_num]->drv[i].sectors = 32; // Sectors per track
-                           hba[cntl_num]->drv[i].cylinders = total_size / 255 / 32;                	} else
-			{
+                           hba[cntl_num]->drv[i].sectors = 32; /* Sectors */
+			   					/* per track */
+                           hba[cntl_num]->drv[i].cylinders = total_size 
+				   				/ 255 / 32;
+			} else {
 
 		 	   hba[cntl_num]->drv[i].block_size = block_size;
                            hba[cntl_num]->drv[i].nr_blocks = total_size;
@@ -1894,23 +2757,27 @@
 					(inq_buff->data_byte[4] & 0xff) << 8;
 			   hba[cntl_num]->drv[i].cylinders += 
                                         inq_buff->data_byte[5];
+                           hba[cntl_num]->drv[i].raid_level = 
+					inq_buff->data_byte[8]; 
 			}
 		}
-		else /* Get geometry failed */
-		{
+		else {	/* Get geometry failed */
 			printk(KERN_WARNING "cciss: reading geometry failed, continuing with default geometry\n"); 
 
 			hba[cntl_num]->drv[i].block_size = block_size;
 			hba[cntl_num]->drv[i].nr_blocks = total_size;
 			hba[cntl_num]->drv[i].heads = 255;
-			hba[cntl_num]->drv[i].sectors = 32; // Sectors per track 
+			hba[cntl_num]->drv[i].sectors = 32; 	/* Sectors */
+								/* per track */
 			hba[cntl_num]->drv[i].cylinders = total_size / 255 / 32;
 		}
-		printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d\n\n",
+		if (hba[cntl_num]->drv[i].raid_level > 5)
+			hba[cntl_num]->drv[i].raid_level = RAID_UNKNOWN;
+		printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d RAID %s\n\n",
 			hba[cntl_num]->drv[i].heads, 
 			hba[cntl_num]->drv[i].sectors,
-			hba[cntl_num]->drv[i].cylinders);
-
+			hba[cntl_num]->drv[i].cylinders,
+			raid_label[hba[cntl_num]->drv[i].raid_level]); 
 	}
 	kfree(ld_buff);
 	kfree(size_buff);
@@ -1922,22 +2789,19 @@
 static int alloc_cciss_hba(void)
 {
 	int i;
-	for(i=0; i< MAX_CTLR; i++)
-	{
-		if (hba[i] == NULL)
-		{
+	for(i=0; i< MAX_CTLR; i++) {
+		if (hba[i] == NULL) {
 			hba[i] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
-			if(hba[i]==NULL)
-			{
+			if (hba[i]==NULL) {
 				printk(KERN_ERR "cciss: out of memory.\n");
-				return (-1);
+				return -1;
 			}
-			return (i);
+			return i;
 		}
 	}
 	printk(KERN_WARNING "cciss: This driver supports a maximum"
 		" of 8 controllers.\n");
-	return(-1);
+	return -1;
 }
 
 static void free_hba(int i)
@@ -1963,13 +2827,12 @@
 		pdev->device, pdev->bus->number, PCI_SLOT(pdev->devfn),
 			PCI_FUNC(pdev->devfn));
 	i = alloc_cciss_hba();
-	if( i < 0 ) 
-		return (-1);
+	if (i < 0 ) 
+		return -1;
 	memset(hba[i], 0, sizeof(ctlr_info_t));
-	if (cciss_pci_init(hba[i], pdev) != 0)
-	{
+	if (cciss_pci_init(hba[i], pdev) != 0) {
 		free_hba(i);
-		return (-1);
+		return -1;
 	}
 	sprintf(hba[i]->devname, "cciss%d", i);
 	hba[i]->ctlr = i;
@@ -1986,26 +2849,25 @@
 		return -ENODEV;
 	}
 		
-	if( register_blkdev(MAJOR_NR+i, hba[i]->devname, &cciss_fops))
-	{
+	if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &cciss_fops)) {
 		printk(KERN_ERR "cciss:  Unable to get major number "
 			"%d for %s\n", MAJOR_NR+i, hba[i]->devname);
 		release_io_mem(hba[i]);
 		free_hba(i);
-		return(-1);
+		return -1;
 	}
 	/* make sure the board interrupts are off */
 	hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
-	if( request_irq(hba[i]->intr, do_cciss_intr, 
+	if (request_irq(hba[i]->intr, do_cciss_intr, 
 		SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
-			hba[i]->devname, hba[i]))
-	{
-		printk(KERN_ERR "ciss: Unable to get irq %d for %s\n",
+			hba[i]->devname, hba[i])) {
+
+		printk(KERN_ERR "cciss: Unable to get irq %d for %s\n",
 			hba[i]->intr, hba[i]->devname);
 		unregister_blkdev( MAJOR_NR+i, hba[i]->devname);
 		release_io_mem(hba[i]);
 		free_hba(i);
-		return(-1);
+		return -1;
 	}
 	hba[i]->cmd_pool_bits = (__u32*)kmalloc(
         	((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
@@ -2015,17 +2877,17 @@
 	hba[i]->errinfo_pool = (ErrorInfo_struct *)pci_alloc_consistent(
 		hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct), 
 		&(hba[i]->errinfo_pool_dhandle));
-	if((hba[i]->cmd_pool_bits == NULL) 
+	if ((hba[i]->cmd_pool_bits == NULL) 
 		|| (hba[i]->cmd_pool == NULL)
-		|| (hba[i]->errinfo_pool == NULL))
-        {
-		if(hba[i]->cmd_pool_bits)
+		|| (hba[i]->errinfo_pool == NULL)) {
+
+		if (hba[i]->cmd_pool_bits)
                 	kfree(hba[i]->cmd_pool_bits);
-                if(hba[i]->cmd_pool)
+                if (hba[i]->cmd_pool)
                 	pci_free_consistent(hba[i]->pdev,  
 				NR_CMDS * sizeof(CommandList_struct), 
 				hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);	
-		if(hba[i]->errinfo_pool)
+		if (hba[i]->errinfo_pool)
 			pci_free_consistent(hba[i]->pdev,
 				NR_CMDS * sizeof( ErrorInfo_struct),
 				hba[i]->errinfo_pool, 
@@ -2035,7 +2897,7 @@
 		release_io_mem(hba[i]);
 		free_hba(i);
                 printk( KERN_ERR "cciss: out of memory");
-		return(-1);
+		return -1;
 	}
 
 	/* Initialize the pdev driver private data. 
@@ -2082,7 +2944,8 @@
 	hba[i]->gendisk.max_p = MAX_PART;
 	hba[i]->gendisk.part = hba[i]->hd;
 	hba[i]->gendisk.sizes = hba[i]->sizes;
-	hba[i]->gendisk.nr_real = hba[i]->num_luns;
+	hba[i]->gendisk.nr_real = hba[i]->highest_lun+1;
+	hba[i]->gendisk.fops = &cciss_fops;
 
 	/* Get on the disk list */ 
 	add_gendisk(&(hba[i]->gendisk));
@@ -2096,7 +2959,7 @@
 
 	cciss_register_scsi(i, 1);  /* hook ourself into SCSI subsystem */
 
-	return(1);
+	return 1;
 }
 
 static void __devexit cciss_remove_one (struct pci_dev *pdev)
@@ -2106,15 +2969,13 @@
 	char flush_buf[4];
 	int return_code; 
 
-	if (pci_get_drvdata(pdev) == NULL)
-	{
+	if (pci_get_drvdata(pdev) == NULL) {
 		printk( KERN_ERR "cciss: Unable to remove device \n");
 		return;
 	}
 	tmp_ptr = pci_get_drvdata(pdev);
 	i = tmp_ptr->ctlr;
-	if (hba[i] == NULL) 
-	{
+	if (hba[i] == NULL) {
 		printk(KERN_ERR "cciss: device appears to "
 			"already be removed \n");
 		return;
@@ -2175,7 +3036,7 @@
 static int __init init_cciss_module(void)
 {
 
-	return ( cciss_init());
+	return cciss_init();
 }
 
 static void __exit cleanup_cciss_module(void)
@@ -2184,10 +3045,8 @@
 
 	pci_unregister_driver(&cciss_pci_driver);
 	/* double check that all controller entrys have been removed */
-	for (i=0; i< MAX_CTLR; i++) 
-	{
-		if (hba[i] != NULL)
-		{
+	for (i=0; i< MAX_CTLR; i++) {
+		if (hba[i] != NULL) {
 			printk(KERN_WARNING "cciss: had to remove"
 					" controller %d\n", i);
 			cciss_remove_one(hba[i]->pdev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/cciss.h linux-2.4.21/drivers/block/cciss.h
--- linux-2.4.20/drivers/block/cciss.h	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/block/cciss.h	2002-12-18 18:58:01.000000000 +0000
@@ -27,13 +27,14 @@
 };
 typedef struct _drive_info_struct
 {
- 	__u32   LunID;	
-	int 	usage_count;
-	int 	nr_blocks;
-	int	block_size;
-	int 	heads;
-	int	sectors;
-	int 	cylinders;
+ 	__u32   	LunID;	
+	int 		usage_count;
+	unsigned int 	nr_blocks;
+	int		block_size;
+	int 		heads;
+	int		sectors;
+	int 		cylinders;
+	int 		raid_level;
 } drive_info_struct;
 
 struct ctlr_info 
@@ -55,6 +56,7 @@
 	int	commands_outstanding;
 	int 	max_outstanding; /* Debug */ 
 	int	num_luns;
+	int 	highest_lun;
 	int	usage_count;  /* number of opens all all minor devices */
 
 	// information about each logical volume
@@ -85,6 +87,7 @@
 	int              sizes[256];
 	int              blocksizes[256];
 	int              hardsizes[256];
+	int busy_configuring;
 #ifdef CONFIG_CISS_SCSI_TAPE
 	void *scsi_ctlr; /* ptr to structure containing scsi related stuff */
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/cciss_cmd.h linux-2.4.21/drivers/block/cciss_cmd.h
--- linux-2.4.20/drivers/block/cciss_cmd.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/drivers/block/cciss_cmd.h	2002-12-18 18:58:04.000000000 +0000
@@ -1,16 +1,17 @@
 #ifndef CCISS_CMD_H
 #define CCISS_CMD_H
-//###########################################################################
-//DEFINES
-//###########################################################################
+/* ########################################################################## */
+/* DEFINES                                                                    */
+/* ########################################################################## */
 #define CISS_VERSION "1.00"
 
-//general boundary defintions
-#define SENSEINFOBYTES          32//note that this value may vary between host implementations
+/* general boundary defintions */
+#define SENSEINFOBYTES          32	/* note that this value may vary */
+					/* between host implementations  */
 #define MAXSGENTRIES            31
 #define MAXREPLYQS              256
 
-//Command Status value
+/* Command Status value */
 #define CMD_SUCCESS             0x0000
 #define CMD_TARGET_STATUS       0x0001
 #define CMD_DATA_UNDERRUN       0x0002
@@ -25,30 +26,30 @@
 #define CMD_TIMEOUT             0x000B
 #define CMD_UNABORTABLE		0x000C
 
-//transfer direction
+/* transfer direction */
 #define XFER_NONE               0x00
 #define XFER_WRITE              0x01
 #define XFER_READ               0x02
 #define XFER_RSVD               0x03
 
-//task attribute
+/* task attribute */
 #define ATTR_UNTAGGED           0x00
 #define ATTR_SIMPLE             0x04
 #define ATTR_HEADOFQUEUE        0x05
 #define ATTR_ORDERED            0x06
 #define ATTR_ACA                0x07
 
-//cdb type
+/* cdb type */
 #define TYPE_CMD				0x00
 #define TYPE_MSG				0x01
 
-//config space register offsets
+/* config space register offsets */
 #define CFG_VENDORID            0x00
 #define CFG_DEVICEID            0x02
 #define CFG_I2OBAR              0x10
 #define CFG_MEM1BAR             0x14
 
-//i2o space register offsets
+/* i2o space register offsets */
 #define I2O_IBDB_SET            0x20
 #define I2O_IBDB_CLEAR          0x70
 #define I2O_INT_STATUS          0x30
@@ -56,7 +57,7 @@
 #define I2O_IBPOST_Q            0x40
 #define I2O_OBPOST_Q            0x44
 
-//Configuration Table
+/* Configuration Table */
 #define CFGTBL_ChangeReq        0x00000001l
 #define CFGTBL_AccCmds          0x00000001l
 
@@ -78,24 +79,24 @@
    __u64	val;
 } u64bit;
 
-// Type defs used in the following structs
-#define BYTE __u8
-#define WORD __u16
-#define HWORD __u16
-#define DWORD __u32
-#define QWORD vals32 
-
-//###########################################################################
-//STRUCTURES
-//###########################################################################
+/*  Type defs used in the following structs */
+typedef	__u8 BYTE;
+typedef	__u16 WORD;
+typedef __u16 HWORD;
+typedef	__u32 DWORD; 
+typedef vals32 QWORD; 
+
+/* ######################################################################### */
+/* STRUCTURES                                                                */
+/* ######################################################################### */
 #define CISS_MAX_LUN	16	
 #define CISS_MAX_PHYS_LUN	1024
-// SCSI-3 Cmmands 
+/* SCSI-3 Cmmands  */
 
 #pragma pack(1)	
 
 #define CISS_INQUIRY 0x12
-//Date returned
+/* Data returned */
 typedef struct _InquiryData_struct
 {
   BYTE data_byte[36];
@@ -103,7 +104,7 @@
 
 #define CISS_REPORT_LOG 0xc2    /* Report Logical LUNs */
 #define CISS_REPORT_PHYS 0xc3   /* Report Physical LUNs */
-// Data returned
+/*  Data returned */
 typedef struct _ReportLUNdata_struct
 {
   BYTE LUNListLength[4];
@@ -114,39 +115,39 @@
 #define CCISS_READ_CAPACITY 0x25 /* Read Capacity */ 
 typedef struct _ReadCapdata_struct
 {
-  BYTE total_size[4];	// Total size in blocks
-  BYTE block_size[4];	// Size of blocks in bytes
+  BYTE total_size[4];	/* Total size in blocks */
+  BYTE block_size[4];	/* Size of blocks in bytes */
 } ReadCapdata_struct;
 
-// 12 byte commands not implemented in firmware yet. 
-// #define CCISS_READ 	0xa8	// Read(12)
-// #define CCISS_WRITE	0xaa	// Write(12)
- #define CCISS_READ   0x28    // Read(10)
- #define CCISS_WRITE  0x2a    // Write(10)
+/* 12 byte commands not implemented in firmware yet.  */
+/* #define CCISS_READ 	0xa8	Read(12)	*/
+/* #define CCISS_WRITE	0xaa	Write(12) 	*/
+ #define CCISS_READ   0x28    /* Read(10) */
+ #define CCISS_WRITE  0x2a    /* Write(10) */
 
-// BMIC commands 
+/* BMIC commands */
 #define BMIC_READ 0x26
 #define BMIC_WRITE 0x27
 #define BMIC_CACHE_FLUSH 0xc2
-#define CCISS_CACHE_FLUSH 0x01	//C2 was already being used by CCISS
+#define CCISS_CACHE_FLUSH 0x01	/* 0xC2 was already being used by CCISS */
 
-//Command List Structure
+/* Command List Structure */
 typedef union _SCSI3Addr_struct {
    struct {
     BYTE Dev;
     BYTE Bus:6;
-    BYTE Mode:2;        // b00
+    BYTE Mode:2;        /* b00 */
   } PeripDev;
    struct {
     BYTE DevLSB;
     BYTE DevMSB:6;
-    BYTE Mode:2;        // b01
+    BYTE Mode:2;        /* b01 */
   } LogDev;
    struct {
     BYTE Dev:5;
     BYTE Bus:3;
     BYTE Targ:6;
-    BYTE Mode:2;        // b10
+    BYTE Mode:2;        /* b10 */
   } LogUnit;
 } SCSI3Addr_struct;
 
@@ -154,7 +155,7 @@
   DWORD             TargetId:24;
   DWORD             Bus:6;
   DWORD             Mode:2;
-  SCSI3Addr_struct  Target[2]; //2 level target device addr
+  SCSI3Addr_struct  Target[2]; /* 2 level target device addr */
 } PhysDevAddr_struct;
   
 typedef struct _LogDevAddr_struct {
@@ -205,8 +206,8 @@
   }Common_Info;
   struct{
     BYTE  Reserved[2];
-    BYTE  offense_size;//size of offending entry
-    BYTE  offense_num; //byte # of offense 0-base
+    BYTE  offense_size;	/* size of offending entry 	*/
+    BYTE  offense_num; 	/* byte # of offense 0-base 	*/
     DWORD offense_value;
   }Invalid_Cmd;
 }MoreErrInfo_struct;
@@ -240,12 +241,13 @@
   struct _CommandList_struct *next;
   struct request *	   rq;
   struct completion *waiting;
+  int	 retry_count;
 #ifdef CONFIG_CISS_SCSI_TAPE
   void * scsi_cmd;
 #endif
 } CommandList_struct;
 
-//Configuration Table Structure
+/* Configuration Table Structure */
 typedef struct _HostWrite_struct {
   DWORD TransportRequest;
   DWORD Reserved;
@@ -266,4 +268,4 @@
   DWORD            HeartBeat;
 } CfgTable_struct;
 #pragma pack()	 
-#endif // CCISS_CMD_H
+#endif /* CCISS_CMD_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/cciss_scsi.c linux-2.4.21/drivers/block/cciss_scsi.c
--- linux-2.4.20/drivers/block/cciss_scsi.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/block/cciss_scsi.c	2002-12-18 18:58:01.000000000 +0000
@@ -1,7 +1,7 @@
 /*
- *    Disk Array driver for Compaq SA53xx Controllers, SCSI Tape module
- *    Copyright 2001 Compaq Computer Corporation
- *
+ *    Disk Array driver for HP SA 5xxx and 6xxx Controllers, SCSI Tape module
+ *    Copyright 2001, 2002 Hewlett-Packard Development Company, L.P.
+ *    
  *    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
@@ -16,7 +16,7 @@
  *    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
+ *    Questions/Comments/Bugfixes to Cciss-discuss@lists.sourceforge.net 
  *
  *    Author: Stephen M. Cameron
  */
@@ -233,8 +233,8 @@
 		printk( "cciss: %d scsi commands are still outstanding.\n",
 			CMD_STACK_SIZE - stk->top);
 		// BUG();
-		printk("WE HAVE A BUG HERE!!! stk=%p\n",
-			stk);
+		printk("WE HAVE A BUG HERE!!! stk=0x%08x\n",
+			(unsigned int) stk);
 	}
 	size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
 
@@ -896,7 +896,7 @@
 
 	memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB));
 	memcpy(cp->Request.CDB, cdb, cdblen);
-	cp->Request.Timeout = 1000;		// guarantee completion.
+	cp->Request.Timeout = 0;	// No timeout
 	cp->Request.CDBLen = cdblen;
 	cp->Request.Type.Type = TYPE_CMD;
 	cp->Request.Type.Attribute = ATTR_SIMPLE;
@@ -1414,7 +1414,7 @@
 
 	// Fill in the request block...
 
-	cp->Request.Timeout = 1000; // guarantee completion
+	cp->Request.Timeout = 0; // No timeout 
 	memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB));
 	if (cmd->cmd_len > sizeof(cp->Request.CDB)) BUG();
 	cp->Request.CDBLen = cmd->cmd_len;
@@ -1578,14 +1578,14 @@
 cciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len)
 {
 	int size;
-	unsigned long flags;
+	unsigned int flags;
 
 	*pos = *pos -1; *len = *len - 1; // cut off the last trailing newline
 
 	CPQ_TAPE_LOCK(ctlr, flags);
 	size = sprintf(buffer + *len,
-		"       Sequential access devices: %d\n\n",
-			ccissscsi[ctlr].ndevices);
+		"Sequential access devices: %d\n\n",
+		 ccissscsi[ctlr].ndevices);
 	CPQ_TAPE_UNLOCK(ctlr, flags);
 	*pos += size; *len += size;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/cciss_scsi.h linux-2.4.21/drivers/block/cciss_scsi.h
--- linux-2.4.20/drivers/block/cciss_scsi.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/drivers/block/cciss_scsi.h	2002-12-18 18:58:02.000000000 +0000
@@ -1,6 +1,6 @@
 /*
- *    Disk Array driver for Compaq SA53xx Controllers, SCSI Tape module
- *    Copyright 2001 Compaq Computer Corporation
+ *    Disk Array driver for HP SA 5xxx and 6xxx Controllers, SCSI Tape module
+ *    Copyright 2001, 2002 Hewlett-Packard Development Company, L.P.
  *
  *    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
@@ -16,7 +16,7 @@
  *    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
+ *    Questions/Comments/Bugfixes to Cciss-discuss@lists.sourceforge.net
  *
  */
 #ifdef CONFIG_CISS_SCSI_TAPE
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/cpqarray.c linux-2.4.21/drivers/block/cpqarray.c
--- linux-2.4.20/drivers/block/cpqarray.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/block/cpqarray.c	2002-12-18 18:58:03.000000000 +0000
@@ -16,7 +16,7 @@
  *    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
+ *    Questions/Comments/Bugfixes to Cpqarray-discuss@lists.sourceforge.net
  *
  */
 #include <linux/config.h>	/* CONFIG_PROC_FS */
@@ -41,13 +41,13 @@
 
 #define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
 
-#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.21)"
-#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,21)
+#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.25)"
+#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,25)
 
 /* Embedded module documentation macros - see modules.h */
 /* Original author Chris Frantz - Compaq Computer Corporation */
 MODULE_AUTHOR("Compaq Computer Corporation");
-MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers version 2.4.21");
+MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers version 2.4.25");
 MODULE_LICENSE("GPL");
 
 #define MAJOR_NR COMPAQ_SMART2_MAJOR
@@ -162,6 +162,7 @@
 static int 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 int ida_ctlr_big_ioctl( int ctlr, int dsk, ida_big_ioctl_t *io);
 
 static void do_ida_request(request_queue_t *q);
 static void start_io(ctlr_info_t *h);
@@ -279,8 +280,7 @@
 
 	for(i=0; i<=h->highest_lun; i++) {
 		drv = &h->drv[i];
-		if(drv->nr_blks != 0)
-		{
+		if(drv->nr_blks != 0) {
 		    	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;
@@ -293,7 +293,8 @@
 
 	c = h->reqQ;
 	size = sprintf(buffer+len, "reqQ = %p", c); pos += size; len += size;
-	if (c) c=c->next;
+	if (c) 
+		c=c->next;
 	while(c && c != h->reqQ) {
 		size = sprintf(buffer+len, "->%p", c);
 		pos += size; len += size;
@@ -302,7 +303,8 @@
 
 	c = h->cmpQ;
 	size = sprintf(buffer+len, "\ncmpQ = %p", c); pos += size; len += size;
-	if (c) c=c->next;
+	if (c) 
+		c=c->next;
 	while(c && c != h->cmpQ) {
 		size = sprintf(buffer+len, "->%p", c);
 		pos += size; len += size;
@@ -352,12 +354,12 @@
 	ctlr_info_t *tmp_ptr;
 	char buff[4]; 
 
-		if (pdev->driver_data == NULL)
+	tmp_ptr = pci_get_drvdata(pdev);
+	if (tmp_ptr == NULL)
 	{
 		printk( KERN_ERR "cpqarray: Unable to remove device \n");
 		return;
 	}
-	tmp_ptr = (ctlr_info_t *) pdev->driver_data;
 	i = tmp_ptr->ctlr;
 	if (hba[i] == NULL) 
 	{
@@ -369,13 +371,12 @@
 	/* sendcmd will turn off interrupt, and send the flush... 
 	 * To write all data in the battery backed cache to disks    */
 	memset(buff, 0 , 4);
-	if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0))
-	{
+	if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0)) {
 		printk(KERN_WARNING "Unable to flush cache on controller %d\n",
 			 i);	
 	}
 	free_irq(hba[i]->intr, hba[i]);
-	pdev->driver_data = NULL;
+	pci_set_drvdata(pdev, NULL);
 	/* remove it from the disk list */
 	del_gendisk(&(hba[i]->gendisk));
 
@@ -399,8 +400,7 @@
 {
 	char buff[4]; 
 
-	if (hba[i] == NULL) 
-	{
+	if (hba[i] == NULL) {
 		printk(KERN_ERR "cpqarray: device appears to "
 			"already be removed \n");
 		return;
@@ -409,8 +409,7 @@
 	/* sendcmd will turn off interrupt, and send the flush... 
 	 * To write all data in the battery backed cache to disks    
 	 * no data returned, but don't want to send NULL to sendcmd */	
-	if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0))
-	{
+	if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0)) {
 		printk(KERN_WARNING "Unable to flush cache on controller %d\n",
 			 i);	
 	}
@@ -488,15 +487,14 @@
 	memset(hba[i], 0, sizeof(ctlr_info_t));
 	/* fill in default block size */
 	for(j=0;j<256;j++)
-                hba[i]->hardsizes[j] = BLOCK_SIZE;
+                hba[i]->hardsizes[j] = hba[i]->drv[j].blk_size;
 
 	sprintf(hba[i]->devname, "ida%d", i);
         hba[i]->ctlr = i;
 	/* Initialize the pdev driver private data */
-	pdev->driver_data = hba[i];
+	pci_set_drvdata(pdev, hba[i]);
 
-	if (cpqarray_pci_init(hba[i], pdev) != 0)
-	{
+	if (cpqarray_pci_init(hba[i], pdev) != 0) {
 		release_io_mem(hba[i]);
 		free_hba(i);
 		return (-1);
@@ -510,8 +508,7 @@
 	
 	/* If this successful it should insure that we are the only */
 	/* instance of the driver */	
-	if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) 
-	{
+	if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) {
         	printk(KERN_ERR "cpqarray: Unable to get major number %d for ida\n",
                                 MAJOR_NR+i);
                 release_io_mem(hba[i]);
@@ -522,8 +519,8 @@
 	
 	hba[i]->access.set_intr_mask(hba[i], 0);
 	if (request_irq(hba[i]->intr, do_ida_intr,
-		SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i])) 
-	{
+		SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
+				hba[i]->devname, hba[i])) {
 
 		printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n", 
 				hba[i]->intr, hba[i]->devname);
@@ -538,8 +535,7 @@
 	hba[i]->cmd_pool_bits = (__u32*)kmalloc(
 				((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
 		
-	if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL)
-	{
+	if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL) {
 		if(hba[i]->cmd_pool_bits)
 			kfree(hba[i]->cmd_pool_bits);
 		if(hba[i]->cmd_pool)
@@ -583,6 +579,7 @@
 	hba[i]->gendisk.part = hba[i]->hd;
 	hba[i]->gendisk.sizes = hba[i]->sizes;
 	hba[i]->gendisk.nr_real = hba[i]->highest_lun+1; 
+	hba[i]->gendisk.fops = &ida_fops;
 	
 		/* Get on the disk list */
 	add_gendisk(&(hba[i]->gendisk));
@@ -622,8 +619,7 @@
 	pci_register_driver(&cpqarray_pci_driver);
 	cpqarray_eisa_detect();
 
-	for(i=0; i< MAX_CTLR; i++)
-        {
+	for(i=0; i< MAX_CTLR; i++) {
 		if (hba[i] != NULL)
 			num_cntlrs_reg++;
 	}
@@ -634,13 +630,10 @@
 static int alloc_cpqarray_hba(void)
 {
 	int i;
-	for(i=0; i< MAX_CTLR; i++)
-	{
-		if (hba[i] == NULL)
-		{
+	for(i=0; i< MAX_CTLR; i++) {
+		if (hba[i] == NULL) {
 			hba[i] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
-			if(hba[i]==NULL)
-			{
+			if(hba[i]==NULL) {
 				printk(KERN_ERR "cpqarray: out of memory.\n");
 				return (-1);
 			}
@@ -674,8 +667,7 @@
 
 	pci_read_config_word(pdev, PCI_COMMAND, &command);
 	/* check to see if controller has been disabled */
-	if(!(command & 0x02))
-	{
+	if(!(command & 0x02)) {
 		printk(KERN_WARNING "cpqarray: controller appears to be disabled\n");
 		return(-1);
 	}
@@ -688,13 +680,11 @@
 	for(i=0; i<6; i++)
 		addr[i] = pci_resource_start(pdev, i);
 
-	if (pci_enable_device(pdev))
-	{
+	if (pci_enable_device(pdev)) {
 		printk(KERN_ERR "cpqarray: Unable to Enable PCI device\n");
 		return -1;
 	}
-	if (pci_set_dma_mask(pdev, CPQARRAY_DMA_MASK) != 0)
-	{
+	if (pci_set_dma_mask(pdev, CPQARRAY_DMA_MASK) != 0) {
 		printk(KERN_ERR "cpqarray: Unable to set DMA mask\n");
 		return -1;
 	}
@@ -719,18 +709,16 @@
 );
 
 	c->intr = irq;
-	for(i=0; i<6; i++)
-	{
-		if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO)
-		{ /* IO space */  
+	for(i=0; i<6; i++) {
+		if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO) { 
+			/* IO space */  
 			c->io_mem_addr = addr[i];
 			c->io_mem_length = pci_resource_end(pdev, i) 
 				- pci_resource_start(pdev, i) +1; 
 			// printk("IO Value found addr[%d] %lx %lx\n",
 			//		i, c->io_mem_addr, c->io_mem_length);
 			if(!request_region( c->io_mem_addr, c->io_mem_length,
-				"cpqarray"))
-			{
+				"cpqarray")) {
 				printk( KERN_WARNING "cpqarray I/O memory range already in use addr %lx length = %ld\n", c->io_mem_addr, c->io_mem_length);
 				c->io_mem_addr = 0;
 				c->io_mem_length = 0;
@@ -740,7 +728,8 @@
 	}	
 	c->paddr = 0;
 	for(i=0; i<6; i++)
-		if (!(pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO)) {
+		if (!(pci_resource_flags(pdev, i) & 
+					PCI_BASE_ADDRESS_SPACE_IO)) {
 			c->paddr = pci_resource_start (pdev, i);
 			break;
 		}
@@ -843,8 +832,7 @@
 		hba[ctlr]->io_mem_length = 0x7FF;		
 		if(!request_region( hba[ctlr]->io_mem_addr, 
 					hba[ctlr]->io_mem_length, 
-				"cpqarray"))
-		{
+				"cpqarray")) {
 			printk( KERN_WARNING "cpqarray: I/0 range already in use addr = %lx length=%ld\n",
 			 hba[ctlr]->io_mem_addr, hba[ctlr]->io_mem_length);
 			free_hba(ctlr);
@@ -854,10 +842,14 @@
 		 * Read the config register to find our interrupt
 		 */
 		intr = inb(eisa[i]+0xCC0) >> 4;
-		if (intr & 1) intr = 11;
-		else if (intr & 2) intr = 10;
-		else if (intr & 4) intr = 14;
-		else if (intr & 8) intr = 15;
+		if (intr & 1) 
+			intr = 11;
+		else if (intr & 2) 
+			intr = 10;
+		else if (intr & 4) 
+			intr = 14;
+		else if (intr & 8) 
+			intr = 15;
 		
 		hba[ctlr]->intr = intr;
 		sprintf(hba[ctlr]->devname, "ida%d", ctlr);
@@ -894,19 +886,18 @@
 	if (ctlr > MAX_CTLR || hba[ctlr] == NULL)
 		return -ENXIO;
 
-	if (!suser() && hba[ctlr]->sizes[ 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()
-		&& hba[ctlr]->sizes[ MINOR(inode->i_rdev)] == 0 
-		&& MINOR(inode->i_rdev) != 0)
-		return -ENXIO;
+	if (hba[ctlr]->sizes[MINOR(inode->i_rdev)] == 0) {
+		if (MINOR(inode->i_rdev) != 0)
+			return -ENXIO;
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+	}
 
 	hba[ctlr]->drv[dsk].usage_count++;
 	hba[ctlr]->usage_count++;
@@ -947,7 +938,8 @@
 static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c)
 {
 	if (c && c->next != c) {
-		if (*Qptr == c) *Qptr = c->next;
+		if (*Qptr == c) 
+			*Qptr = c->next;
 		c->prev->next = c->next;
 		c->next->prev = c->prev;
 	} else {
@@ -985,8 +977,7 @@
 	if (creq->nr_segments > SG_MAX)
 		BUG();
 
-	if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR )
-	{
+	if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR ) {
 		printk(KERN_WARNING "doreq cmd for %d, %x at %p\n",
 				h->ctlr, creq->rq_dev, creq);
 		blkdev_dequeue_request(creq);
@@ -1036,8 +1027,7 @@
 		bh = bh->b_reqnext;
 	}
 	/* Now do all the DMA Mappings */
-	for( i=0; i < seg; i++)
-	{
+	for( i=0; i < seg; i++) {
 		c->req.sg[i].size = tmp_sg[i].length;
 		c->req.sg[i].addr = (__u32) pci_map_page(
                 		h->pci_dev, tmp_sg[i].page, tmp_sg[i].offset,
@@ -1131,7 +1121,8 @@
 				cmd->req.hdr.sg_cnt, cmd->req.hdr.rcode);
 		ok = 0;	
 	}
-	if (timeout) ok = 0;
+	if (timeout) 
+		ok = 0;
 	/* unmap the DMA mapping for all the scatter gather elements */
         for(i=0; i<cmd->req.hdr.sg_cnt; i++)
         {
@@ -1192,15 +1183,14 @@
                                  *  But rcode = 0.
                                  */
 
-				if((a1 & 0x03) && (c->req.hdr.rcode == 0))
-                                {
+				if((a1 & 0x03) && (c->req.hdr.rcode == 0)) {
                                 	c->req.hdr.rcode = RCODE_INVREQ;
                                 }
 				if (c->type == CMD_RWREQ) {
 					complete_command(c, 0);
 					cmd_free(h, c, 1);
 				} else if (c->type == CMD_IOCTL_PEND) {
-					c->type = CMD_IOCTL_DONE;
+					complete(c->waiting);
 				}
 				continue;
 			}
@@ -1238,8 +1228,6 @@
 	int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
 	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
 	int error;
-	ida_ioctl_t *io = (ida_ioctl_t*)arg;
-	ida_ioctl_t my_io;
 
 	switch(cmd) {
 	case HDIO_GETGEO:
@@ -1286,9 +1274,14 @@
 	}
 
 	case IDAGETDRVINFO:
+	{
+
+		ida_ioctl_t *io = (ida_ioctl_t*)arg;
 		return copy_to_user(&io->c.drv,&hba[ctlr]->drv[dsk],sizeof(drv_info_t));
+	}
 	case BLKGETSIZE:
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		return put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects, 
 			(unsigned long *)arg);
 	case BLKGETSIZE64:
@@ -1296,16 +1289,42 @@
 	case BLKRRPART:
 		return revalidate_logvol(inode->i_rdev, 1);
 	case IDAPASSTHRU:
-		if (!suser()) return -EPERM;
-		error = copy_from_user(&my_io, io, sizeof(my_io));
-		if (error) return error;
+	{
+
+		ida_ioctl_t *io = (ida_ioctl_t*)arg;
+		ida_ioctl_t my_io;
+
+		if (!capable(CAP_SYS_RAWIO)) 
+			return -EPERM;
+		if (copy_from_user(&my_io, io, sizeof(my_io)))
+			return -EFAULT;
 		error = ida_ctlr_ioctl(ctlr, dsk, &my_io);
-		if (error) return error;
-		if(copy_to_user(io, &my_io, sizeof(my_io)))
+		if (error)
+			return error;
+		if (copy_to_user(io, &my_io, sizeof(my_io)))
 			return -EFAULT;
-		return error;
+		return 0;
+	}
+	case IDABIGPASSTHRU:
+	{
+
+		ida_big_ioctl_t *io = (ida_big_ioctl_t*)arg;
+		ida_big_ioctl_t my_io;
+		
+		if (!capable(CAP_SYS_RAWIO))
+			return -EPERM;
+		if (copy_from_user(&my_io, io, sizeof(my_io)))
+			return -EFAULT;
+		error = ida_ctlr_big_ioctl(ctlr, dsk, &my_io);
+		if (error)
+			return error;
+		if (copy_to_user(io, &my_io, sizeof(my_io)))
+			return -EFAULT;
+		return 0;
+	}
 	case IDAGETCTLRSIG:
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		put_user(hba[ctlr]->ctlr_sig, (int*)arg);
 		return 0;
 	case IDAREVALIDATEVOLS:
@@ -1319,7 +1338,8 @@
 		
 		ida_pci_info_struct pciinfo;
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		pciinfo.bus = hba[ctlr]->pci_dev->bus->number;
 		pciinfo.dev_fn = hba[ctlr]->pci_dev->devfn;
 		pciinfo.board_id = hba[ctlr]->board_id;
@@ -1347,8 +1367,7 @@
 
 		/* count partitions 1 to 15 with sizes > 0 */
 		start = (dsk << NWD_SHIFT); 	
-		for(i=1; i <IDA_MAX_PART; i++)
-		{
+		for(i=1; i <IDA_MAX_PART; i++) {
 			int minor = start+i;
 			if(hba[ctlr]->sizes[minor] != 0)
 				num_parts++;
@@ -1394,6 +1413,7 @@
 	void *p = NULL;
 	unsigned long flags;
 	int error;
+	DECLARE_COMPLETION(wait);
 
 	if ((c = cmd_alloc(h, 0)) == NULL)
 		return -ENOMEM;
@@ -1411,8 +1431,7 @@
 	switch(io->cmd) {
 	case PASSTHRU_A:
 		p = kmalloc(io->sg[0].size, GFP_KERNEL);
-		if (!p) 
-		{ 
+		if (!p) { 
 			error = -ENOMEM; 
 			cmd_free(h, c, 0); 
 			return(error);
@@ -1431,11 +1450,11 @@
 		c->req.hdr.sg_cnt = 1;
 		break;
 	case IDA_READ:
+	case SENSE_SURF_STATUS:
 	case READ_FLASH_ROM:
 	case SENSE_CONTROLLER_PERFORMANCE:
 		p = kmalloc(io->sg[0].size, GFP_KERNEL);
-		if (!p) 
-		{ 
+		if (!p) { 
                         error = -ENOMEM; 
                         cmd_free(h, c, 0);
                         return(error);
@@ -1452,8 +1471,7 @@
 	case COLLECT_BUFFER:
 	case WRITE_FLASH_ROM:
 		p = kmalloc(io->sg[0].size, GFP_KERNEL);
-		if (!p) 
- 		{ 
+		if (!p) { 
                         error = -ENOMEM; 
                         cmd_free(h, c, 0);
                         return(error);
@@ -1474,7 +1492,9 @@
 			c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL);
 		c->req.hdr.sg_cnt = 1;
 	}
-	
+
+	c->waiting = &wait;
+
 	/* Put the request on the tail of the request queue */
 	spin_lock_irqsave(&io_request_lock, flags);
 	addQ(&h->reqQ, c);
@@ -1483,8 +1503,7 @@
 	spin_unlock_irqrestore(&io_request_lock, flags);
 
 	/* Wait for completion */
-	while(c->type != CMD_IOCTL_DONE)
-		schedule();
+	wait_for_completion(&wait);
 
 	/* Unmap the DMA  */
 	pci_unmap_single(h->pci_dev, c->req.sg[0].addr, c->req.sg[0].size, 
@@ -1496,6 +1515,7 @@
                                 sizeof(ida_ioctl_t),
                                 PCI_DMA_BIDIRECTIONAL);
 	case IDA_READ:
+	case SENSE_SURF_STATUS:
 	case DIAG_PASS_THRU:
 	case SENSE_CONTROLLER_PERFORMANCE:
 	case READ_FLASH_ROM:
@@ -1520,6 +1540,175 @@
 }
 
 /*
+ * ida_ctlr_big_ioctl is for passing commands to the controller from userspace.
+ * The command block (io) has already been copied to kernel space for us,
+ *
+ * Only root may perform a controller passthru command, however I'm not doing
+ * any serious sanity checking on the arguments.  
+ */
+static int ida_ctlr_big_ioctl(int ctlr, int dsk, ida_big_ioctl_t *io)
+{
+	ctlr_info_t *h = hba[ctlr];
+	cmdlist_t *c;
+	__u8   *scsi_param = NULL;
+	__u8	*buff[SG_MAX] = {NULL,};
+	size_t	buff_size[SG_MAX];
+	__u8	sg_used = 0;
+	unsigned long flags;
+	int error = 0;
+	int i;
+	DECLARE_COMPLETION(wait);
+
+	/* Check kmalloc limits  using all SGs */
+	if( io->buff_malloc_size > IDA_MAX_KMALLOC_SIZE)
+		return -EINVAL;
+	if( io->buff_size > io->buff_malloc_size * SG_MAX)
+		return -EINVAL;
+	if ((c = cmd_alloc(h, 0)) == NULL)
+		return -ENOMEM;
+
+	c->ctlr = ctlr;
+	c->hdr.unit = (io->unit & UNITVALID) ? (io->unit & ~UNITVALID) : dsk;
+	c->hdr.size = sizeof(rblk_t) >> 2;
+	c->size += sizeof(rblk_t);
+
+	c->req.hdr.cmd = io->cmd;
+	c->req.hdr.blk = io->blk;
+	c->req.hdr.blk_cnt = io->blk_cnt;
+	c->type = CMD_IOCTL_PEND;
+
+	/* Pre submit processing */
+	/* for passthru_a the scsi command is in another record */
+	if (io->cmd == PASSTHRU_A) {
+
+		if (io->scsi_param == NULL)
+		{
+			error = -EINVAL;
+			cmd_free(h, c, 0);
+			return(error);
+		}
+		scsi_param = kmalloc(sizeof(scsi_param_t),  GFP_KERNEL);
+		if (scsi_param == NULL) {
+			error = -ENOMEM;
+			cmd_free(h, c, 0);
+			return(error);
+		}
+
+		/* copy the scsi command to get passed thru */ 	
+		if (copy_from_user(scsi_param, io->scsi_param, 
+					sizeof(scsi_param_t))) {	
+			kfree(scsi_param);
+			cmd_free(h, c, 0);
+			return -EFAULT;
+		}
+
+		/* with this command the scsi command is seperate */
+		c->req.hdr.blk = pci_map_single(h->pci_dev, scsi_param,
+				sizeof(scsi_param_t), PCI_DMA_BIDIRECTIONAL);
+	}
+
+	/* fill in the SG entries */
+	/* create buffers if we need to */ 
+	if(io->buff_size > 0) {
+		size_t size_left_alloc = io->buff_size;
+		__u8 *data_ptr = io->buff;
+
+		while(size_left_alloc > 0) {
+			buff_size[sg_used] = (size_left_alloc 
+					> io->buff_malloc_size)
+				? io->buff_malloc_size : size_left_alloc;
+			buff[sg_used] = kmalloc( buff_size[sg_used], 
+					GFP_KERNEL);
+			if (buff[sg_used] == NULL) {
+				error = -ENOMEM;
+				goto ida_alloc_cleanup;
+			}
+			if(io->xfer_type & IDA_XFER_WRITE) {
+				/* Copy the data into the buffer created */
+				if (copy_from_user(buff[sg_used], data_ptr,
+						buff_size[sg_used])) {
+					error = -EFAULT;
+					goto ida_alloc_cleanup;
+				}
+			}
+			/* put the data into the scatter gather list */
+			c->req.sg[sg_used].size = buff_size[sg_used];
+			c->req.sg[sg_used].addr = pci_map_single(h->pci_dev, 
+					buff[sg_used], buff_size[sg_used],
+					 PCI_DMA_BIDIRECTIONAL);
+			
+			size_left_alloc -= buff_size[sg_used];
+			data_ptr += buff_size[sg_used];
+			sg_used++;
+		}
+	}
+	c->req.hdr.sg_cnt = sg_used;
+
+	c->waiting = &wait;
+
+	/* Put the request on the tail of the request queue */
+	spin_lock_irqsave(&io_request_lock, flags);
+	addQ(&h->reqQ, c);
+	h->Qdepth++;
+	start_io(h);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	/* Wait for completion */
+	wait_for_completion(&wait);
+	/* Unmap the DMA  */
+	for(i=0; i<c->req.hdr.sg_cnt; i++) {
+		pci_unmap_single(h->pci_dev, c->req.sg[i].addr, 
+				c->req.sg[i].size, PCI_DMA_BIDIRECTIONAL);
+	}
+
+	/* if we are reading data from the hardware copy it back to user */
+	if (io->xfer_type & IDA_XFER_READ) {
+		__u8	*data_ptr = io->buff;
+		int i;
+
+	    	for(i=0; i<c->req.hdr.sg_cnt; i++) {
+			if (copy_to_user(data_ptr, buff[i], buff_size[i])) { 
+				error = -EFAULT;
+				goto ida_alloc_cleanup;
+			}
+			data_ptr += buff_size[i];
+			
+		}
+
+	}
+
+	io->rcode = c->req.hdr.rcode;
+
+	if(scsi_param) {
+		pci_unmap_single(h->pci_dev, c->req.hdr.blk,
+			sizeof(scsi_param_t), PCI_DMA_BIDIRECTIONAL);
+		/* copy the scsi_params back to the user */ 
+		if( copy_to_user(io->scsi_param, scsi_param, 
+					sizeof(scsi_param_t))) {
+			error = -EFAULT;	
+		}
+		kfree(scsi_param);
+	}
+	cmd_free(h, c, 0);
+	return(error);
+	
+ida_alloc_cleanup:
+	if(scsi_param) {
+		pci_unmap_single(h->pci_dev, c->req.hdr.blk,
+			sizeof(scsi_param_t), PCI_DMA_BIDIRECTIONAL);
+		kfree(scsi_param);
+	}
+	for (i=0; i<sg_used; i++) {
+		if(buff[sg_used] != NULL) {	
+			pci_unmap_single(h->pci_dev, c->req.sg[i].addr, 
+				buff_size[sg_used], PCI_DMA_BIDIRECTIONAL);
+			kfree(buff[sg_used]);
+		}
+	}	
+	cmd_free(h, c, 0);
+	return(error);
+}
+/*
  * Commands are pre-allocated in a large block.  Here we use a simple bitmap
  * scheme to suballocte them to the driver.  Operations that are not time
  * critical (and can wait for kmalloc and possibly sleep) can pass in NULL
@@ -1720,7 +1909,7 @@
 	hba[ctlr]->gendisk.nr_real = 0;
 
 	for(i=0;i<256;i++)
-                hba[ctlr]->hardsizes[i] = BLOCK_SIZE;
+                hba[ctlr]->hardsizes[i] = 0;
 	/*
 	 * Tell the array controller not to give us any interrupts while
 	 * we check the new geometry.  Then turn interrupts back on when
@@ -1752,8 +1941,7 @@
 
 	spin_lock_irqsave(&io_request_lock, flags);
 	/* make sure logical volume is NOT is use */
-	if( h->drv[logvol].usage_count > 1)
-	{
+	if( h->drv[logvol].usage_count > 1) {
 		spin_unlock_irqrestore(&io_request_lock, flags);
                 return -EBUSY;
 	}
@@ -1763,21 +1951,21 @@
 	/* invalidate the devices and deregister the disk */ 
 	max_p = gdev->max_p;
 	start = logvol << gdev->minor_shift;
-	for (i=max_p-1; i>=0; i--)
-	{
+	for (i=max_p-1; i>=0; i--) {
 		int minor = start+i;
 		// printk("invalidating( %d %d)\n", ctlr, minor);
 		invalidate_device(MKDEV(MAJOR_NR+ctlr, minor), 1);
 		/* so open will now fail */
 		hba[ctlr]->sizes[minor] = 0;
+		/* so it will no longer appear in /proc/partitions */
+		gdev->part[minor].start_sect = 0;
+		gdev->part[minor].nr_sects = 0;
 	}
 	/* check to see if it was the last disk */
-	if (logvol == h->highest_lun)
-	{
+	if (logvol == h->highest_lun) {
 		/* if so, find the new hightest lun */
 		int i, newhighest =-1;
-		for(i=0; i<h->highest_lun; i++)
-		{
+		for(i=0; i<h->highest_lun; i++) {
 			/* if the disk has size > 0, it is available */
 			if (hba[ctlr]->sizes[i << gdev->minor_shift] != 0)
 				newhighest = i;
@@ -1789,7 +1977,8 @@
 	gdev->nr_real = h->highest_lun+1; 
 	/* zero out the disk size info */ 
 	h->drv[logvol].nr_blks = 0;
-	h->drv[logvol].blk_size = BLOCK_SIZE;
+	h->drv[logvol].cylinders = 0;
+	h->drv[logvol].blk_size = 0;
 	return(0);
 
 }
@@ -1806,6 +1995,7 @@
 	cmdlist_t *c;
 	unsigned long flags;
 	ctlr_info_t *info_p = hba[ctlr];
+	DECLARE_COMPLETION(wait);
 
 	c = cmd_alloc(info_p, 0);
 	if(!c)
@@ -1835,6 +2025,7 @@
 	c->req.sg[0].addr = (__u32) pci_map_single(info_p->pci_dev, 
 		buff, c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL);
 
+	c->waiting = &wait;
 	/* Put the request on the tail of the request queue */
 	spin_lock_irqsave(&io_request_lock, flags);
 	addQ(&info_p->reqQ, c);
@@ -1843,8 +2034,7 @@
 	spin_unlock_irqrestore(&io_request_lock, flags);
 
 	/* Wait for completion */
-	while(c->type != CMD_IOCTL_DONE)
-		schedule();
+	wait_for_completion(&wait);
 
 	if (c->req.hdr.rcode & RCODE_FATAL) {
 		printk(KERN_WARNING "Fatal error on ida/c%dd%d\n",
@@ -1885,14 +2075,12 @@
 		return -EINVAL;
 
 	id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);
-	if(id_ldrive == NULL)
-	{
+	if(id_ldrive == NULL) {
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
 		return -1;
 	}
 	id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
-	if(id_lstatus_buf == NULL)
-	{
+	if(id_lstatus_buf == NULL) {
 		kfree(id_ldrive);
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
 		return -1;
@@ -1905,8 +2093,7 @@
 	 */
 	ret_code = sendcmd_withirq(SENSE_LOG_DRV_STAT,
 		ctlr, id_lstatus_buf, size, 0, 0, logvol);
-	if (ret_code == IO_ERROR) 
-	{
+	if (ret_code == IO_ERROR) {
 			/*
 			   If can't get logical drive status, set
 			   the logical drive map to 0, so the
@@ -1922,8 +2109,7 @@
 	/*
 		   Make sure the logical drive is configured
 	 */
-	if (id_lstatus_buf->status == LOG_NOT_CONF) 
-	{
+	if (id_lstatus_buf->status == LOG_NOT_CONF) {
 		printk(KERN_WARNING "cpqarray: c%dd%d array not configured\n",
 			ctlr, logvol); 
 		kfree(id_lstatus_buf);
@@ -1937,8 +2123,7 @@
 			   logical drive won't be set and
 			   idastubopen will return error. 
 			 */
-	if (ret_code == IO_ERROR) 
-	{
+	if (ret_code == IO_ERROR) {
 		printk(KERN_WARNING "cpqarray: c%dd%d unable to ID logical volume\n",
 			ctlr,logvol);
 		kfree(id_lstatus_buf);
@@ -1963,8 +2148,7 @@
 	max_p = gdev->max_p;
 	start = logvol<< gdev->minor_shift;
 	
-	for(i=max_p-1; i>=0; i--) 
-	{
+	for(i=max_p-1; i>=0; i--) {
 		int minor = start+i;
 		invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 1);
 		gdev->part[minor].start_sect = 0;
@@ -1972,6 +2156,7 @@
 	
 		/* reset the blocksize so we can read the partition table */
 		blksize_size[MAJOR_NR+ctlr][minor] = 1024;
+		hba[ctlr]->hardsizes[minor] = drv->blk_size;
 	}
 	++hba[ctlr]->log_drives;
 	gdev->nr_real = info_p->highest_lun + 1;
@@ -2075,8 +2260,7 @@
 	/* Command does not return anything, but idasend command needs a 
 		buffer */
 	id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
-	if(id_ctlr_buf==NULL)
-	{
+	if(id_ctlr_buf==NULL) {
 		printk(KERN_WARNING "cpqarray: Out of memory. "
 			"Unable to start background processing.\n");
 		return;
@@ -2110,23 +2294,20 @@
 	info_p->log_drv_map = 0;	
 	
 	id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);
-	if(id_ldrive == NULL)
-	{
+	if(id_ldrive == NULL) {
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
 		return;
 	}
 
 	id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
-	if(id_ctlr_buf == NULL)
-	{
+	if(id_ctlr_buf == NULL) {
 		kfree(id_ldrive);
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
 		return;
 	}
 
 	id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
-	if(id_lstatus_buf == NULL)
-	{
+	if(id_lstatus_buf == NULL) {
 		kfree(id_ctlr_buf);
 		kfree(id_ldrive);
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
@@ -2134,8 +2315,7 @@
 	}
 
 	sense_config_buf = (config_t *)kmalloc(sizeof(config_t), GFP_KERNEL);
-	if(sense_config_buf == NULL)
-	{
+	if(sense_config_buf == NULL) {
 		kfree(id_lstatus_buf);
 		kfree(id_ctlr_buf);
 		kfree(id_ldrive);
@@ -2285,10 +2465,8 @@
 
         pci_unregister_driver(&cpqarray_pci_driver);
         /* double check that all controller entrys have been removed */
-        for (i=0; i< MAX_CTLR; i++)
-        {
-                if (hba[i] != NULL)
-                {
+        for (i=0; i< MAX_CTLR; i++) {
+                if (hba[i] != NULL) {
                         printk(KERN_WARNING "cpqarray: had to remove"
                                         " controller %d\n", i);
                         cpqarray_remove_one_eisa(i);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/ida_cmd.h linux-2.4.21/drivers/block/ida_cmd.h
--- linux-2.4.20/drivers/block/ida_cmd.h	2001-11-03 01:45:42.000000000 +0000
+++ linux-2.4.21/drivers/block/ida_cmd.h	2002-12-18 18:58:05.000000000 +0000
@@ -82,7 +82,6 @@
 
 #define CMD_RWREQ	0x00
 #define CMD_IOCTL_PEND	0x01
-#define CMD_IOCTL_DONE	0x02
 
 typedef struct cmdlist {
 	chdr_t	hdr;
@@ -94,6 +93,7 @@
 	struct cmdlist *prev;
 	struct cmdlist *next;
 	struct request *rq;
+	struct completion *waiting;
 	int type;
 } cmdlist_t;
 	
@@ -318,6 +318,8 @@
 	__u8	reserved[510];
 } mp_delay_t;
 
+#define SENSE_SURF_STATUS	0x70
+
 #define PASSTHRU_A	0x91
 typedef struct {
 	__u8	target;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/ida_ioctl.h linux-2.4.21/drivers/block/ida_ioctl.h
--- linux-2.4.20/drivers/block/ida_ioctl.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/drivers/block/ida_ioctl.h	2002-12-18 18:58:08.000000000 +0000
@@ -34,6 +34,7 @@
 #define IDADEREGDISK		0x33333434
 #define IDAREGNEWDISK		0x34343535
 #define IDAGETLOGINFO		0x35353636
+#define IDABIGPASSTHRU          0x36363535
 
 typedef struct _ida_pci_info_struct
 {
@@ -94,4 +95,27 @@
 	} c;
 } ida_ioctl_t;
 
+#define IDA_MAX_KMALLOC_SIZE 128000
+
+/* transfer type of the commands */
+#define IDA_XFER_NONE	0x00
+#define IDA_XFER_READ	0x01
+#define IDA_XFER_WRITE	0x02
+#define IDA_XFER_BOTH	0x03
+
+typedef struct {
+	__u8	cmd;
+	__u8	rcode;
+	__u8	unit;
+	__u32	blk;
+	__u16	blk_cnt;
+
+	__u8	xfer_type;
+	__u8    *buff;
+	size_t	buff_size;
+	__u32	buff_malloc_size;
+	scsi_param_t *scsi_param; /* used only for PASSTHRU_A */
+
+} ida_big_ioctl_t;
+
 #endif /* IDA_IOCTL_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/ll_rw_blk.c linux-2.4.21/drivers/block/ll_rw_blk.c
--- linux-2.4.20/drivers/block/ll_rw_blk.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/block/ll_rw_blk.c	2002-12-18 18:58:03.000000000 +0000
@@ -394,7 +394,7 @@
 	unsigned long flags;
 	/* Several broken drivers assume that this function doesn't sleep,
 	 * this causes system hangs during boot.
-	 * As a temporary fix, make the the function non-blocking.
+	 * As a temporary fix, make the function non-blocking.
 	 */
 	spin_lock_irqsave(&io_request_lock, flags);
 	while (q->nr_requests < nr_requests) {
@@ -1413,12 +1413,6 @@
 #ifdef CONFIG_ISP16_CDI
 	isp16_init();
 #endif
-#if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_IDE)
-	ide_init();		/* this MUST precede hd_init */
-#endif
-#if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_HD)
-	hd_init();
-#endif
 #ifdef CONFIG_BLK_DEV_PS2
 	ps2esdi_init();
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/loop.c linux-2.4.21/drivers/block/loop.c
--- linux-2.4.20/drivers/block/loop.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/block/loop.c	2002-12-18 18:58:09.000000000 +0000
@@ -199,9 +199,9 @@
 		page = grab_cache_page(mapping, index);
 		if (!page)
 			goto fail;
+		kaddr = kmap(page);
 		if (aops->prepare_write(file, page, offset, offset+size))
 			goto unlock;
-		kaddr = page_address(page);
 		flush_dcache_page(page);
 		transfer_result = lo_do_transfer(lo, WRITE, kaddr + offset, data, size, IV);
 		if (transfer_result) {
@@ -216,6 +216,7 @@
 			goto unlock;
 		if (transfer_result)
 			goto unlock;
+		kunmap(page);
 		data += size;
 		len -= size;
 		offset = 0;
@@ -228,6 +229,7 @@
 	return 0;
 
 unlock:
+	kunmap(page);
 	UnlockPage(page);
 	page_cache_release(page);
 fail:
@@ -418,6 +420,7 @@
 			break;
 
 		run_task_queue(&tq_disk);
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(HZ);
 	} while (1);
 	memset(bh, 0, sizeof(*bh));
@@ -437,6 +440,7 @@
 			break;
 
 		run_task_queue(&tq_disk);
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(HZ);
 	} while (1);
 
@@ -563,6 +567,7 @@
 
 	daemonize();
 	exit_files(current);
+	reparent_to_init();
 
 	sprintf(current->comm, "loop%d", lo->lo_number);
 
@@ -571,9 +576,6 @@
 	flush_signals(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	current->policy = SCHED_OTHER;
-	current->nice = -20;
-
 	spin_lock_irq(&lo->lo_lock);
 	lo->lo_state = Lo_bound;
 	atomic_inc(&lo->lo_pending);
@@ -645,7 +647,7 @@
 		lo_device = inode->i_rdev;
 		if (lo_device == dev) {
 			error = -EBUSY;
-			goto out;
+			goto out_putf;
 		}
 	} else if (S_ISREG(inode->i_mode)) {
 		struct address_space_operations *aops = inode->i_mapping->a_ops;
@@ -1014,11 +1016,6 @@
 		return -EIO;
 	}
 
-	devfs_handle = devfs_mk_dir(NULL, "loop", NULL);
-	devfs_register_series(devfs_handle, "%u", max_loop, DEVFS_FL_DEFAULT,
-			      MAJOR_NR, 0,
-			      S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
-			      &lo_fops, NULL);
 
 	loop_dev = kmalloc(max_loop * sizeof(struct loop_device), GFP_KERNEL);
 	if (!loop_dev)
@@ -1051,13 +1048,21 @@
 	for (i = 0; i < max_loop; i++)
 		register_disk(NULL, MKDEV(MAJOR_NR, i), 1, &lo_fops, 0);
 
+	devfs_handle = devfs_mk_dir(NULL, "loop", NULL);
+	devfs_register_series(devfs_handle, "%u", max_loop, DEVFS_FL_DEFAULT,
+			      MAJOR_NR, 0,
+			      S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
+			      &lo_fops, NULL);
+
 	printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop);
 	return 0;
 
-out_sizes:
-	kfree(loop_dev);
 out_blksizes:
 	kfree(loop_sizes);
+out_sizes:
+	kfree(loop_dev);
+	if (devfs_unregister_blkdev(MAJOR_NR, "loop"))
+		printk(KERN_WARNING "loop: cannot unregister blkdev\n");
 	printk(KERN_ERR "loop: ran out of memory\n");
 	return -ENOMEM;
 }
@@ -1067,7 +1072,6 @@
 	devfs_unregister(devfs_handle);
 	if (devfs_unregister_blkdev(MAJOR_NR, "loop"))
 		printk(KERN_WARNING "loop: cannot unregister blkdev\n");
-
 	kfree(loop_dev);
 	kfree(loop_sizes);
 	kfree(loop_blksizes);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/nbd.c linux-2.4.21/drivers/block/nbd.c
--- linux-2.4.20/drivers/block/nbd.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/drivers/block/nbd.c	2002-12-18 18:58:04.000000000 +0000
@@ -26,6 +26,8 @@
  *   reduce number of partial TCP segments sent. <steve@chygwyn.com>
  * 01-12-6 Fix deadlock condition by making queue locks independant of
  *   the transmit lock. <steve@chygwyn.com>
+ * 02-10-11 Allow hung xmit to be aborted via SIGKILL & various fixes.
+ *   <Paul.Clements@SteelEye.com> <James.Bottomley@SteelEye.com>
  *
  * possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall
  * why not: would need verify_area and friends, would share yet another 
@@ -101,9 +103,12 @@
 	oldfs = get_fs();
 	set_fs(get_ds());
 
+	/* Allow interception of SIGKILL only
+	 * Don't allow other signals to interrupt the transmission */
 	spin_lock_irqsave(&current->sigmask_lock, flags);
 	oldset = current->blocked;
 	sigfillset(&current->blocked);
+	sigdelsetmask(&current->blocked, sigmask(SIGKILL));
 	recalc_sigpending(current);
 	spin_unlock_irqrestore(&current->sigmask_lock, flags);
 
@@ -126,6 +131,17 @@
 		else
 			result = sock_recvmsg(sock, &msg, size, 0);
 
+		if (signal_pending(current)) {
+			siginfo_t info;
+			spin_lock_irqsave(&current->sigmask_lock, flags);
+			printk(KERN_WARNING "NBD (pid %d: %s) got signal %d\n",
+				current->pid, current->comm, 
+				dequeue_signal(&current->blocked, &info));
+			spin_unlock_irqrestore(&current->sigmask_lock, flags);
+			result = -EINTR;
+			break;
+		}
+
 		if (result <= 0) {
 #ifdef PARANOIA
 			printk(KERN_ERR "NBD: %s - sock=%ld at buf=%ld, size=%d returned %d.\n",
@@ -150,7 +166,7 @@
 
 void nbd_send_req(struct nbd_device *lo, struct request *req)
 {
-	int result;
+	int result = -1;
 	struct nbd_request request;
 	unsigned long size = req->nr_sectors << 9;
 	struct socket *sock = lo->sock;
@@ -164,6 +180,10 @@
 
 	down(&lo->tx_lock);
 
+	if (!sock || !lo->sock) {
+		FAIL("Attempted sendmsg to closed socket\n");
+	}
+
 	result = nbd_xmit(1, sock, (char *) &request, sizeof(request), req->cmd == WRITE ? MSG_MORE : 0);
 	if (result <= 0)
 		FAIL("Sendmsg failed for control.");
@@ -345,10 +365,28 @@
 		spin_unlock_irq(&io_request_lock);
 
 		spin_lock(&lo->queue_lock);
+		if (!lo->file) {
+			spin_unlock(&lo->queue_lock);
+			printk(KERN_ERR "nbd: failed between accept and semaphore, file lost\n");
+			req->errors++;
+			nbd_end_request(req);
+			spin_lock_irq(&io_request_lock);
+			continue;
+		}
+
 		list_add_tail(&req->queue, &lo->queue_head);
 		spin_unlock(&lo->queue_lock);
 
 		nbd_send_req(lo, req);
+		if (req->errors) {
+			printk(KERN_ERR "nbd: nbd_send_req failed\n");
+			spin_lock(&lo->queue_lock);
+			list_del(&req->queue);
+			spin_unlock(&lo->queue_lock);
+			nbd_end_request(req);
+			spin_lock_irq(&io_request_lock);
+			continue;
+		}
 
 		spin_lock_irq(&io_request_lock);
 		continue;
@@ -397,12 +435,14 @@
 			printk(KERN_ERR "nbd: Some requests are in progress -> can not turn off.\n");
 			return -EBUSY;
 		}
-		spin_unlock(&lo->queue_lock);
 		file = lo->file;
-		if (!file)
+		if (!file) {
+			spin_unlock(&lo->queue_lock);
 			return -EINVAL;
+		}
 		lo->file = NULL;
 		lo->sock = NULL;
+		spin_unlock(&lo->queue_lock);
 		fput(file);
 		return 0;
 	case NBD_SET_SOCK:
@@ -443,6 +483,26 @@
 		if (!lo->file)
 			return -EINVAL;
 		nbd_do_it(lo);
+		/* on return tidy up in case we have a signal */
+		/* Forcibly shutdown the socket causing all listeners
+		 * to error
+		 *
+		 * FIXME: This code is duplicated from sys_shutdown, but
+		 * there should be a more generic interface rather than
+		 * calling socket ops directly here */
+		down(&lo->tx_lock);
+		printk(KERN_WARNING "nbd: shutting down socket\n");
+		lo->sock->ops->shutdown(lo->sock, SEND_SHUTDOWN|RCV_SHUTDOWN);
+		lo->sock = NULL;
+		up(&lo->tx_lock);
+		spin_lock(&lo->queue_lock);
+		file = lo->file;
+		lo->file = NULL;
+		spin_unlock(&lo->queue_lock);
+		nbd_clear_que(lo);
+		printk(KERN_WARNING "nbd: queue cleared\n");
+		if (file)
+			fput(file);
 		return lo->harderror;
 	case NBD_CLEAR_QUE:
 		nbd_clear_que(lo);
@@ -523,7 +583,7 @@
 		init_MUTEX(&nbd_dev[i].tx_lock);
 		nbd_blksizes[i] = 1024;
 		nbd_blksize_bits[i] = 10;
-		nbd_bytesizes[i] = 0x7ffffc00; /* 2GB */
+		nbd_bytesizes[i] = ((u64)0x7ffffc00) << 10; /* 2TB */
 		nbd_sizes[i] = nbd_bytesizes[i] >> BLOCK_SIZE_BITS;
 		register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &nbd_fops,
 				nbd_bytesizes[i]>>9);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/umem.c linux-2.4.21/drivers/block/umem.c
--- linux-2.4.20/drivers/block/umem.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/block/umem.c	2002-12-18 18:58:10.000000000 +0000
@@ -1230,7 +1230,7 @@
 
         spin_lock_init(&card->lock);
 
-	dev->driver_data = card;
+	pci_set_drvdata(dev, card);
 
 	if (pci_write_cmd != 0x0F) 	/* If not Memory Write & Invalidate */
 		pci_write_cmd = 0x07;	/* then Memory Write command */
@@ -1290,7 +1290,7 @@
 */
 static void mm_pci_remove(struct pci_dev *dev)
 {
-	struct cardinfo *card = dev->driver_data;
+	struct cardinfo *card = pci_get_drvdata(dev);
 
 	tasklet_kill(&card->tasklet);
 	iounmap(card->csr_remap);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/Config.in linux-2.4.21/drivers/bluetooth/Config.in
--- linux-2.4.20/drivers/bluetooth/Config.in	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/bluetooth/Config.in	2002-12-18 18:58:01.000000000 +0000
@@ -1,3 +1,7 @@
+#
+# Bluetooth HCI device drivers configuration
+#
+
 mainmenu_option next_comment
 comment 'Bluetooth device drivers'
 
@@ -9,6 +13,8 @@
 dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ
 if [ "$CONFIG_BLUEZ_HCIUART" != "n" ]; then
    bool '  UART (H4) protocol support' CONFIG_BLUEZ_HCIUART_H4
+   bool '  BCSP protocol support' CONFIG_BLUEZ_HCIUART_BCSP
+   dep_bool '  Transmit CRC with every BCSP packet' CONFIG_BLUEZ_HCIUART_BCSP_TXCRC $CONFIG_BLUEZ_HCIUART_BCSP
 fi
 
 dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ
@@ -17,6 +23,9 @@
 
 dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ
 
+dep_tristate 'HCI UART (PC Card) driver' CONFIG_BLUEZ_HCIBTUART $CONFIG_PCMCIA $CONFIG_BLUEZ
+
 dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
 
 endmenu
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/Makefile linux-2.4.21/drivers/bluetooth/Makefile
--- linux-2.4.20/drivers/bluetooth/Makefile	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/bluetooth/Makefile	2002-12-18 18:58:12.000000000 +0000
@@ -1,5 +1,5 @@
 #
-# Makefile for Bluetooth HCI device drivers.
+# Makefile for the Linux Bluetooth HCI device drivers
 #
 
 O_TARGET	:= bluetooth.o
@@ -9,13 +9,15 @@
 obj-$(CONFIG_BLUEZ_HCIUSB)	+= hci_usb.o
 obj-$(CONFIG_BLUEZ_HCIVHCI)	+= hci_vhci.o
 
-obj-$(CONFIG_BLUEZ_HCIUART)	+= hci_uart.o
-uart-y				:= hci_ldisc.o
-uart-$(CONFIG_BLUEZ_HCIUART_H4)	+= hci_h4.o
+obj-$(CONFIG_BLUEZ_HCIUART)		+= hci_uart.o
+uart-y					:= hci_ldisc.o
+uart-$(CONFIG_BLUEZ_HCIUART_H4)		+= hci_h4.o
+uart-$(CONFIG_BLUEZ_HCIUART_BCSP)	+= hci_bcsp.o
 
 obj-$(CONFIG_BLUEZ_HCIDTL1)	+= dtl1_cs.o
 obj-$(CONFIG_BLUEZ_HCIBT3C)	+= bt3c_cs.o
 obj-$(CONFIG_BLUEZ_HCIBLUECARD)	+= bluecard_cs.o
+obj-$(CONFIG_BLUEZ_HCIBTUART)	+= btuart_cs.o
 
 include $(TOPDIR)/Rules.make
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/btuart_cs.c linux-2.4.21/drivers/bluetooth/btuart_cs.c
--- linux-2.4.20/drivers/bluetooth/btuart_cs.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/bluetooth/btuart_cs.c	2002-12-18 18:58:09.000000000 +0000
@@ -0,0 +1,906 @@
+/*
+ *
+ *  Driver for Bluetooth PCMCIA cards with HCI UART interface
+ *
+ *  Copyright (C) 2001-2002  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS
+ *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ *  implied. See the License for the specific language governing
+ *  rights and limitations under the License.
+ *
+ *  The initial developer of the original code is David A. Hinds
+ *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+
+#include <linux/skbuff.h>
+#include <linux/string.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+
+
+/* ======================== Module parameters ======================== */
+
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xffff;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
+MODULE_DESCRIPTION("BlueZ driver for Bluetooth PCMCIA cards with HCI UART interface");
+MODULE_LICENSE("GPL");
+
+
+
+/* ======================== Local structures ======================== */
+
+
+typedef struct btuart_info_t {
+	dev_link_t link;
+	dev_node_t node;
+
+	struct hci_dev hdev;
+
+	spinlock_t lock;	/* For serializing operations */
+
+	struct sk_buff_head txq;
+	unsigned long tx_state;
+
+	unsigned long rx_state;
+	unsigned long rx_count;
+	struct sk_buff *rx_skb;
+} btuart_info_t;
+
+
+void btuart_config(dev_link_t *link);
+void btuart_release(u_long arg);
+int btuart_event(event_t event, int priority, event_callback_args_t *args);
+
+static dev_info_t dev_info = "btuart_cs";
+
+dev_link_t *btuart_attach(void);
+void btuart_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+
+
+/* Maximum baud rate */
+#define SPEED_MAX  115200
+
+/* Default baud rate: 57600, 115200, 230400 or 460800 */
+#define DEFAULT_BAUD_RATE  115200
+
+
+/* Transmit states  */
+#define XMIT_SENDING	1
+#define XMIT_WAKEUP	2
+#define XMIT_WAITING	8
+
+/* Receiver states */
+#define RECV_WAIT_PACKET_TYPE	0
+#define RECV_WAIT_EVENT_HEADER	1
+#define RECV_WAIT_ACL_HEADER	2
+#define RECV_WAIT_SCO_HEADER	3
+#define RECV_WAIT_DATA		4
+
+
+
+/* ======================== Interrupt handling ======================== */
+
+
+static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
+{
+	int actual = 0;
+
+	/* Tx FIFO should be empty */
+	if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
+		return 0;
+
+	/* Fill FIFO with current frame */
+	while ((fifo_size-- > 0) && (actual < len)) {
+		/* Transmit next byte */
+		outb(buf[actual], iobase + UART_TX);
+		actual++;
+	}
+
+	return actual;
+}
+
+
+static void btuart_write_wakeup(btuart_info_t *info)
+{
+	if (!info) {
+		printk(KERN_WARNING "btuart_cs: Call of write_wakeup for unknown device.\n");
+		return;
+	}
+
+	if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
+		set_bit(XMIT_WAKEUP, &(info->tx_state));
+		return;
+	}
+
+	do {
+		register unsigned int iobase = info->link.io.BasePort1;
+		register struct sk_buff *skb;
+		register int len;
+
+		clear_bit(XMIT_WAKEUP, &(info->tx_state));
+
+		if (!(info->link.state & DEV_PRESENT))
+			return;
+
+		if (!(skb = skb_dequeue(&(info->txq))))
+			break;
+
+		/* Send frame */
+		len = btuart_write(iobase, 16, skb->data, skb->len);
+		set_bit(XMIT_WAKEUP, &(info->tx_state));
+
+		if (len == skb->len) {
+			kfree_skb(skb);
+		} else {
+			skb_pull(skb, len);
+			skb_queue_head(&(info->txq), skb);
+		}
+
+		info->hdev.stat.byte_tx += len;
+
+	} while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
+
+	clear_bit(XMIT_SENDING, &(info->tx_state));
+}
+
+
+static void btuart_receive(btuart_info_t *info)
+{
+	unsigned int iobase;
+	int boguscount = 0;
+
+	if (!info) {
+		printk(KERN_WARNING "btuart_cs: Call of receive for unknown device.\n");
+		return;
+	}
+
+	iobase = info->link.io.BasePort1;
+
+	do {
+		info->hdev.stat.byte_rx++;
+
+		/* Allocate packet */
+		if (info->rx_skb == NULL) {
+			info->rx_state = RECV_WAIT_PACKET_TYPE;
+			info->rx_count = 0;
+			if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+				printk(KERN_WARNING "btuart_cs: Can't allocate mem for new packet.\n");
+				return;
+			}
+		}
+
+		if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
+
+			info->rx_skb->dev = (void *)&(info->hdev);
+			info->rx_skb->pkt_type = inb(iobase + UART_RX);
+
+			switch (info->rx_skb->pkt_type) {
+
+			case HCI_EVENT_PKT:
+				info->rx_state = RECV_WAIT_EVENT_HEADER;
+				info->rx_count = HCI_EVENT_HDR_SIZE;
+				break;
+
+			case HCI_ACLDATA_PKT:
+				info->rx_state = RECV_WAIT_ACL_HEADER;
+				info->rx_count = HCI_ACL_HDR_SIZE;
+				break;
+
+			case HCI_SCODATA_PKT:
+				info->rx_state = RECV_WAIT_SCO_HEADER;
+				info->rx_count = HCI_SCO_HDR_SIZE;
+				break;
+
+			default:
+				/* Unknown packet */
+				printk(KERN_WARNING "btuart_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
+				info->hdev.stat.err_rx++;
+				clear_bit(HCI_RUNNING, &(info->hdev.flags));
+
+				kfree_skb(info->rx_skb);
+				info->rx_skb = NULL;
+				break;
+
+			}
+
+		} else {
+
+			*skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
+			info->rx_count--;
+
+			if (info->rx_count == 0) {
+
+				int dlen;
+				hci_event_hdr *eh;
+				hci_acl_hdr *ah;
+				hci_sco_hdr *sh;
+
+
+				switch (info->rx_state) {
+
+				case RECV_WAIT_EVENT_HEADER:
+					eh = (hci_event_hdr *)(info->rx_skb->data);
+					info->rx_state = RECV_WAIT_DATA;
+					info->rx_count = eh->plen;
+					break;
+
+				case RECV_WAIT_ACL_HEADER:
+					ah = (hci_acl_hdr *)(info->rx_skb->data);
+					dlen = __le16_to_cpu(ah->dlen);
+					info->rx_state = RECV_WAIT_DATA;
+					info->rx_count = dlen;
+					break;
+
+				case RECV_WAIT_SCO_HEADER:
+					sh = (hci_sco_hdr *)(info->rx_skb->data);
+					info->rx_state = RECV_WAIT_DATA;
+					info->rx_count = sh->dlen;
+					break;
+
+				case RECV_WAIT_DATA:
+					hci_recv_frame(info->rx_skb);
+					info->rx_skb = NULL;
+					break;
+
+				}
+
+			}
+
+		}
+
+		/* Make sure we don't stay here to long */
+		if (boguscount++ > 16)
+			break;
+
+	} while (inb(iobase + UART_LSR) & UART_LSR_DR);
+}
+
+
+void btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
+{
+	btuart_info_t *info = dev_inst;
+	unsigned int iobase;
+	int boguscount = 0;
+	int iir, lsr;
+
+	if (!info) {
+		printk(KERN_WARNING "btuart_cs: Call of irq %d for unknown device.\n", irq);
+		return;
+	}
+
+	iobase = info->link.io.BasePort1;
+
+	spin_lock(&(info->lock));
+
+	iir = inb(iobase + UART_IIR) & UART_IIR_ID;
+	while (iir) {
+
+		/* Clear interrupt */
+		lsr = inb(iobase + UART_LSR);
+
+		switch (iir) {
+		case UART_IIR_RLSI:
+			printk(KERN_NOTICE "btuart_cs: RLSI\n");
+			break;
+		case UART_IIR_RDI:
+			/* Receive interrupt */
+			btuart_receive(info);
+			break;
+		case UART_IIR_THRI:
+			if (lsr & UART_LSR_THRE) {
+				/* Transmitter ready for data */
+				btuart_write_wakeup(info);
+			}
+			break;
+		default:
+			printk(KERN_NOTICE "btuart_cs: Unhandled IIR=%#x\n", iir);
+			break;
+		}
+
+		/* Make sure we don't stay here to long */
+		if (boguscount++ > 100)
+			break;
+
+		iir = inb(iobase + UART_IIR) & UART_IIR_ID;
+
+	}
+
+	spin_unlock(&(info->lock));
+}
+
+
+static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
+{
+	unsigned long flags;
+	unsigned int iobase;
+	int fcr;		/* FIFO control reg */
+	int lcr;		/* Line control reg */
+	int divisor;
+
+	if (!info) {
+		printk(KERN_WARNING "btuart_cs: Call of change speed for unknown device.\n");
+		return;
+	}
+
+	iobase = info->link.io.BasePort1;
+
+	spin_lock_irqsave(&(info->lock), flags);
+
+	/* Turn off interrupts */
+	outb(0, iobase + UART_IER);
+
+	divisor = SPEED_MAX / speed;
+
+	fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT;
+
+	/* 
+	 * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
+	 * almost 1,7 ms at 19200 bps. At speeds above that we can just forget
+	 * about this timeout since it will always be fast enough. 
+	 */
+
+	if (speed < 38400)
+		fcr |= UART_FCR_TRIGGER_1;
+	else
+		fcr |= UART_FCR_TRIGGER_14;
+
+	/* Bluetooth cards use 8N1 */
+	lcr = UART_LCR_WLEN8;
+
+	outb(UART_LCR_DLAB | lcr, iobase + UART_LCR);	/* Set DLAB */
+	outb(divisor & 0xff, iobase + UART_DLL);	/* Set speed */
+	outb(divisor >> 8, iobase + UART_DLM);
+	outb(lcr, iobase + UART_LCR);	/* Set 8N1  */
+	outb(fcr, iobase + UART_FCR);	/* Enable FIFO's */
+
+	/* Turn on interrups */
+	outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
+
+	spin_unlock_irqrestore(&(info->lock), flags);
+}
+
+
+
+/* ======================== HCI interface ======================== */
+
+
+static int btuart_hci_flush(struct hci_dev *hdev)
+{
+	btuart_info_t *info = (btuart_info_t *)(hdev->driver_data);
+
+	/* Drop TX queue */
+	skb_queue_purge(&(info->txq));
+
+	return 0;
+}
+
+
+static int btuart_hci_open(struct hci_dev *hdev)
+{
+	set_bit(HCI_RUNNING, &(hdev->flags));
+
+	return 0;
+}
+
+
+static int btuart_hci_close(struct hci_dev *hdev)
+{
+	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
+		return 0;
+
+	btuart_hci_flush(hdev);
+
+	return 0;
+}
+
+
+static int btuart_hci_send_frame(struct sk_buff *skb)
+{
+	btuart_info_t *info;
+	struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
+
+	if (!hdev) {
+		printk(KERN_WARNING "btuart_cs: Frame for unknown HCI device (hdev=NULL).");
+		return -ENODEV;
+	}
+
+	info = (btuart_info_t *)(hdev->driver_data);
+
+	switch (skb->pkt_type) {
+	case HCI_COMMAND_PKT:
+		hdev->stat.cmd_tx++;
+		break;
+	case HCI_ACLDATA_PKT:
+		hdev->stat.acl_tx++;
+		break;
+	case HCI_SCODATA_PKT:
+		hdev->stat.sco_tx++;
+		break;
+	};
+
+	/* Prepend skb with frame type */
+	memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
+	skb_queue_tail(&(info->txq), skb);
+
+	btuart_write_wakeup(info);
+
+	return 0;
+}
+
+
+static void btuart_hci_destruct(struct hci_dev *hdev)
+{
+}
+
+
+static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
+{
+	return -ENOIOCTLCMD;
+}
+
+
+
+/* ======================== Card services HCI interaction ======================== */
+
+
+int btuart_open(btuart_info_t *info)
+{
+	unsigned long flags;
+	unsigned int iobase = info->link.io.BasePort1;
+	struct hci_dev *hdev;
+
+	spin_lock_init(&(info->lock));
+
+	skb_queue_head_init(&(info->txq));
+
+	info->rx_state = RECV_WAIT_PACKET_TYPE;
+	info->rx_count = 0;
+	info->rx_skb = NULL;
+
+	spin_lock_irqsave(&(info->lock), flags);
+
+	/* Reset UART */
+	outb(0, iobase + UART_MCR);
+
+	/* Turn off interrupts */
+	outb(0, iobase + UART_IER);
+
+	/* Initialize UART */
+	outb(UART_LCR_WLEN8, iobase + UART_LCR);	/* Reset DLAB */
+	outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
+
+	/* Turn on interrupts */
+	// outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
+
+	spin_unlock_irqrestore(&(info->lock), flags);
+
+	btuart_change_speed(info, DEFAULT_BAUD_RATE);
+
+	/* Timeout before it is safe to send the first HCI packet */
+	set_current_state(TASK_INTERRUPTIBLE);
+	schedule_timeout(HZ);
+
+
+	/* Initialize and register HCI device */
+
+	hdev = &(info->hdev);
+
+	hdev->type = HCI_PCCARD;
+	hdev->driver_data = info;
+
+	hdev->open = btuart_hci_open;
+	hdev->close = btuart_hci_close;
+	hdev->flush = btuart_hci_flush;
+	hdev->send = btuart_hci_send_frame;
+	hdev->destruct = btuart_hci_destruct;
+	hdev->ioctl = btuart_hci_ioctl;
+
+	if (hci_register_dev(hdev) < 0) {
+		printk(KERN_WARNING "btuart_cs: Can't register HCI device %s.\n", hdev->name);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+
+int btuart_close(btuart_info_t *info)
+{
+	unsigned long flags;
+	unsigned int iobase = info->link.io.BasePort1;
+	struct hci_dev *hdev = &(info->hdev);
+
+	btuart_hci_close(hdev);
+
+	spin_lock_irqsave(&(info->lock), flags);
+
+	/* Reset UART */
+	outb(0, iobase + UART_MCR);
+
+	/* Turn off interrupts */
+	outb(0, iobase + UART_IER);
+
+	spin_unlock_irqrestore(&(info->lock), flags);
+
+	if (hci_unregister_dev(hdev) < 0)
+		printk(KERN_WARNING "btuart_cs: Can't unregister HCI device %s.\n", hdev->name);
+
+	return 0;
+}
+
+
+
+/* ======================== Card services ======================== */
+
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+	error_info_t err = { func, ret };
+
+	CardServices(ReportError, handle, &err);
+}
+
+
+dev_link_t *btuart_attach(void)
+{
+	btuart_info_t *info;
+	client_reg_t client_reg;
+	dev_link_t *link;
+	int i, ret;
+
+	/* Create new info device */
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return NULL;
+	memset(info, 0, sizeof(*info));
+
+	link = &info->link;
+	link->priv = info;
+
+	link->release.function = &btuart_release;
+	link->release.data = (u_long)link;
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	link->io.NumPorts1 = 8;
+	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+
+	if (irq_list[0] == -1)
+		link->irq.IRQInfo2 = irq_mask;
+	else
+		for (i = 0; i < 4; i++)
+			link->irq.IRQInfo2 |= 1 << irq_list[i];
+
+	link->irq.Handler = btuart_interrupt;
+	link->irq.Instance = info;
+
+	link->conf.Attributes = CONF_ENABLE_IRQ;
+	link->conf.Vcc = 50;
+	link->conf.IntType = INT_MEMORY_AND_IO;
+
+	/* Register with Card Services */
+	link->next = dev_list;
+	dev_list = link;
+	client_reg.dev_info = &dev_info;
+	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+	client_reg.EventMask =
+		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+	client_reg.event_handler = &btuart_event;
+	client_reg.Version = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+
+	ret = CardServices(RegisterClient, &link->handle, &client_reg);
+	if (ret != CS_SUCCESS) {
+		cs_error(link->handle, RegisterClient, ret);
+		btuart_detach(link);
+		return NULL;
+	}
+
+	return link;
+}
+
+
+void btuart_detach(dev_link_t *link)
+{
+	btuart_info_t *info = link->priv;
+	dev_link_t **linkp;
+	int ret;
+
+	/* Locate device structure */
+	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+		if (*linkp == link)
+			break;
+
+	if (*linkp == NULL)
+		return;
+
+	del_timer(&link->release);
+	if (link->state & DEV_CONFIG)
+		btuart_release((u_long)link);
+
+	if (link->handle) {
+		ret = CardServices(DeregisterClient, link->handle);
+		if (ret != CS_SUCCESS)
+			cs_error(link->handle, DeregisterClient, ret);
+	}
+
+	/* Unlink device structure, free bits */
+	*linkp = link->next;
+
+	kfree(info);
+}
+
+
+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+{
+	int i;
+
+	i = CardServices(fn, handle, tuple);
+	if (i != CS_SUCCESS)
+		return CS_NO_MORE_ITEMS;
+
+	i = CardServices(GetTupleData, handle, tuple);
+	if (i != CS_SUCCESS)
+		return i;
+
+	return CardServices(ParseTuple, handle, tuple, parse);
+}
+
+
+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
+
+void btuart_config(dev_link_t *link)
+{
+	static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+	client_handle_t handle = link->handle;
+	btuart_info_t *info = link->priv;
+	tuple_t tuple;
+	u_short buf[256];
+	cisparse_t parse;
+	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+	config_info_t config;
+	int i, j, try, last_ret, last_fn;
+
+	tuple.TupleData = (cisdata_t *)buf;
+	tuple.TupleOffset = 0;
+	tuple.TupleDataMax = 255;
+	tuple.Attributes = 0;
+
+	/* Get configuration register information */
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	last_ret = first_tuple(handle, &tuple, &parse);
+	if (last_ret != CS_SUCCESS) {
+		last_fn = ParseTuple;
+		goto cs_failed;
+	}
+	link->conf.ConfigBase = parse.config.base;
+	link->conf.Present = parse.config.rmask[0];
+
+	/* Configure card */
+	link->state |= DEV_CONFIG;
+	i = CardServices(GetConfigurationInfo, handle, &config);
+	link->conf.Vcc = config.Vcc;
+
+	/* First pass: look for a config entry that looks normal. */
+	tuple.TupleData = (cisdata_t *) buf;
+	tuple.TupleOffset = 0;
+	tuple.TupleDataMax = 255;
+	tuple.Attributes = 0;
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	/* Two tries: without IO aliases, then with aliases */
+	for (try = 0; try < 2; try++) {
+		i = first_tuple(handle, &tuple, &parse);
+		while (i != CS_NO_MORE_ITEMS) {
+			if (i != CS_SUCCESS)
+				goto next_entry;
+			if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
+				link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+			if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
+				link->conf.ConfigIndex = cf->index;
+				link->io.BasePort1 = cf->io.win[0].base;
+				link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
+				i = CardServices(RequestIO, link->handle, &link->io);
+				if (i == CS_SUCCESS)
+					goto found_port;
+			}
+next_entry:
+			i = next_tuple(handle, &tuple, &parse);
+		}
+	}
+
+	/* Second pass: try to find an entry that isn't picky about
+	   its base address, then try to grab any standard serial port
+	   address, and finally try to get any free port. */
+	i = first_tuple(handle, &tuple, &parse);
+	while (i != CS_NO_MORE_ITEMS) {
+		if ((i == CS_SUCCESS) && (cf->io.nwin > 0)
+		    && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
+			link->conf.ConfigIndex = cf->index;
+			for (j = 0; j < 5; j++) {
+				link->io.BasePort1 = base[j];
+				link->io.IOAddrLines = base[j] ? 16 : 3;
+				i = CardServices(RequestIO, link->handle, &link->io);
+				if (i == CS_SUCCESS)
+					goto found_port;
+			}
+		}
+		i = next_tuple(handle, &tuple, &parse);
+	}
+
+found_port:
+	if (i != CS_SUCCESS) {
+		printk(KERN_NOTICE "btuart_cs: No usable port range found. Giving up.\n");
+		cs_error(link->handle, RequestIO, i);
+		goto failed;
+	}
+
+	i = CardServices(RequestIRQ, link->handle, &link->irq);
+	if (i != CS_SUCCESS) {
+		cs_error(link->handle, RequestIRQ, i);
+		link->irq.AssignedIRQ = 0;
+	}
+
+	i = CardServices(RequestConfiguration, link->handle, &link->conf);
+	if (i != CS_SUCCESS) {
+		cs_error(link->handle, RequestConfiguration, i);
+		goto failed;
+	}
+
+	MOD_INC_USE_COUNT;
+
+	if (btuart_open(info) != 0)
+		goto failed;
+
+	strcpy(info->node.dev_name, info->hdev.name);
+	link->dev = &info->node;
+	link->state &= ~DEV_CONFIG_PENDING;
+
+	return;
+
+cs_failed:
+	cs_error(link->handle, last_fn, last_ret);
+
+failed:
+	btuart_release((u_long) link);
+}
+
+
+void btuart_release(u_long arg)
+{
+	dev_link_t *link = (dev_link_t *)arg;
+	btuart_info_t *info = link->priv;
+
+	if (link->state & DEV_PRESENT)
+		btuart_close(info);
+
+	MOD_DEC_USE_COUNT;
+
+	link->dev = NULL;
+
+	CardServices(ReleaseConfiguration, link->handle);
+	CardServices(ReleaseIO, link->handle, &link->io);
+	CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+	link->state &= ~DEV_CONFIG;
+}
+
+
+int btuart_event(event_t event, int priority, event_callback_args_t *args)
+{
+	dev_link_t *link = args->client_data;
+	btuart_info_t *info = link->priv;
+
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG) {
+			btuart_close(info);
+			mod_timer(&link->release, jiffies + HZ / 20);
+		}
+		break;
+	case CS_EVENT_CARD_INSERTION:
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		btuart_config(link);
+		break;
+	case CS_EVENT_PM_SUSPEND:
+		link->state |= DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		if (link->state & DEV_CONFIG)
+			CardServices(ReleaseConfiguration, link->handle);
+		break;
+	case CS_EVENT_PM_RESUME:
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		if (DEV_OK(link))
+			CardServices(RequestConfiguration, link->handle, &link->conf);
+		break;
+	}
+
+	return 0;
+}
+
+
+
+/* ======================== Module initialization ======================== */
+
+
+int __init init_btuart_cs(void)
+{
+	servinfo_t serv;
+	int err;
+
+	CardServices(GetCardServicesInfo, &serv);
+	if (serv.Revision != CS_RELEASE_CODE) {
+		printk(KERN_NOTICE "btuart_cs: Card Services release does not match!\n");
+		return -1;
+	}
+
+	err = register_pccard_driver(&dev_info, &btuart_attach, &btuart_detach);
+
+	return err;
+}
+
+
+void __exit exit_btuart_cs(void)
+{
+	unregister_pccard_driver(&dev_info);
+
+	while (dev_list != NULL)
+		btuart_detach(dev_list);
+}
+
+
+module_init(init_btuart_cs);
+module_exit(exit_btuart_cs);
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_bcsp.c linux-2.4.21/drivers/bluetooth/hci_bcsp.c
--- linux-2.4.20/drivers/bluetooth/hci_bcsp.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/bluetooth/hci_bcsp.c	2002-12-18 18:58:06.000000000 +0000
@@ -0,0 +1,710 @@
+/* 
+   BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ).
+   Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com>
+
+   Based on
+       hci_h4.c  by Maxim Krasnyansky <maxk@qualcomm.com>
+       ABCSP     by Carl Orsborn <cjo@csr.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * $Id: hci_bcsp.c,v 1.2 2002/09/26 05:05:14 maxk Exp $
+ */
+
+#define VERSION "0.1"
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/poll.h>
+
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/ioctl.h>
+#include <linux/skbuff.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include "hci_uart.h"
+#include "hci_bcsp.h"
+
+#ifndef HCI_UART_DEBUG
+#undef  BT_DBG
+#define BT_DBG( A... )
+#undef  BT_DMP
+#define BT_DMP( A... )
+#endif
+
+/* ---- BCSP CRC calculation ---- */
+
+/* Table for calculating CRC for polynomial 0x1021, LSB processed first,
+initial value 0xffff, bits shifted in reverse order. */
+
+static const u16 crc_table[] = {
+	0x0000, 0x1081, 0x2102, 0x3183,
+	0x4204, 0x5285, 0x6306, 0x7387,
+	0x8408, 0x9489, 0xa50a, 0xb58b,
+	0xc60c, 0xd68d, 0xe70e, 0xf78f
+};
+
+/* Initialise the crc calculator */
+#define BCSP_CRC_INIT(x) x = 0xffff
+
+/*
+   Update crc with next data byte
+
+   Implementation note
+        The data byte is treated as two nibbles.  The crc is generated
+        in reverse, i.e., bits are fed into the register from the top.
+*/
+static void bcsp_crc_update(u16 *crc, u8 d)
+{
+	u16 reg = *crc;
+
+	reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f];
+	reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f];
+
+	*crc = reg;
+}
+
+/*
+   Get reverse of generated crc
+
+   Implementation note
+        The crc generator (bcsp_crc_init() and bcsp_crc_update())
+        creates a reversed crc, so it needs to be swapped back before
+        being passed on.
+*/
+static u16 bcsp_crc_reverse(u16 crc)
+{
+	u16 b, rev;
+
+	for (b = 0, rev = 0; b < 16; b++) {
+		rev = rev << 1;
+		rev |= (crc & 1);
+		crc = crc >> 1;
+	}
+	return (rev);
+}
+
+/* ---- BCSP core ---- */
+
+static void bcsp_slip_msgdelim(struct sk_buff *skb)
+{
+	const char pkt_delim = 0xc0;
+	memcpy(skb_put(skb, 1), &pkt_delim, 1);
+}
+
+static void bcsp_slip_one_byte(struct sk_buff *skb, u8 c)
+{
+	const char esc_c0[2] = { 0xdb, 0xdc };
+	const char esc_db[2] = { 0xdb, 0xdd };
+
+	switch (c) {
+	case 0xc0:
+		memcpy(skb_put(skb, 2), &esc_c0, 2);
+		break;
+	case 0xdb:
+		memcpy(skb_put(skb, 2), &esc_db, 2);
+		break;
+	default:
+		memcpy(skb_put(skb, 1), &c, 1);
+	}
+}
+
+static int bcsp_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+{
+	struct bcsp_struct *bcsp = hu->priv;
+
+	if (skb->len > 0xFFF) {
+		BT_ERR("Packet too long");
+		kfree_skb(skb);
+		return 0;
+	}
+
+	switch (skb->pkt_type) {
+	case HCI_ACLDATA_PKT:
+	case HCI_COMMAND_PKT:
+		skb_queue_tail(&bcsp->rel, skb);
+		break;
+
+	case HCI_SCODATA_PKT:
+		skb_queue_tail(&bcsp->unrel, skb);
+		break;
+		
+	default:
+		BT_ERR("Unknown packet type");
+		kfree_skb(skb);
+		break;
+	}
+	return 0;
+}
+
+static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
+		int len, int pkt_type)
+{
+	struct sk_buff *nskb;
+	u8  hdr[4], chan;
+	int rel, i;
+
+#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+	u16 BCSP_CRC_INIT(bcsp_txmsg_crc);
+#endif
+
+	switch (pkt_type) {
+	case HCI_ACLDATA_PKT:
+		chan = 6;	/* BCSP ACL channel */
+		rel = 1;	/* reliable channel */
+		break;
+	case HCI_COMMAND_PKT:
+		chan = 5;	/* BCSP cmd/evt channel */
+		rel = 1;	/* reliable channel */
+		break;
+	case HCI_SCODATA_PKT:
+		chan = 7;	/* BCSP SCO channel */
+		rel = 0;	/* unreliable channel */
+		break;
+	case BCSP_LE_PKT:
+		chan = 1;	/* BCSP LE channel */
+		rel = 0;	/* unreliable channel */
+		break;
+	case BCSP_ACK_PKT:
+		chan = 0;	/* BCSP internal channel */
+		rel = 0;	/* unreliable channel */
+		break;
+	default:
+		BT_ERR("Unknown packet type");
+		return NULL;
+	}
+
+	/* Max len of packet: (original len +4(bcsp hdr) +2(crc))*2
+	   (because bytes 0xc0 and 0xdb are escaped, worst case is
+	   when the packet is all made of 0xc0 and 0xdb :) )
+	   + 2 (0xc0 delimiters at start and end). */
+
+	nskb = alloc_skb((len + 6) * 2 + 2, GFP_ATOMIC);
+	if (!nskb)
+		return NULL;
+
+	nskb->pkt_type = pkt_type;
+
+	bcsp_slip_msgdelim(nskb);
+
+	hdr[0] = bcsp->rxseq_txack << 3;
+	bcsp->txack_req = 0;
+	BT_DBG("We request packet no %u to card", bcsp->rxseq_txack);
+
+	if (rel) {
+		hdr[0] |= 0x80 + bcsp->msgq_txseq;
+		BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq);
+		bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07;
+	}
+#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+	hdr[0] |= 0x40;
+#endif
+
+	hdr[1]  = (len << 4) & 0xFF;
+	hdr[1] |= chan;
+	hdr[2]  = len >> 4;
+	hdr[3]  = ~(hdr[0] + hdr[1] + hdr[2]);
+
+	/* Put BCSP header */
+	for (i = 0; i < 4; i++) {
+		bcsp_slip_one_byte(nskb, hdr[i]);
+#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+		bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]);
+#endif
+	}
+
+	/* Put payload */
+	for (i = 0; i < len; i++) {
+		bcsp_slip_one_byte(nskb, data[i]);
+#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+		bcsp_crc_update(&bcsp_txmsg_crc, data[i]);
+#endif
+	}
+
+#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+	/* Put CRC */
+	bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc);
+	bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff));
+	bcsp_slip_one_byte(nskb, (u8) (bcsp_txmsg_crc & 0x00ff));
+#endif
+
+	bcsp_slip_msgdelim(nskb);
+	return nskb;
+}
+
+/* This is a rewrite of pkt_avail in ABCSP */
+static struct sk_buff *bcsp_dequeue(struct hci_uart *hu)
+{
+	struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv;
+	unsigned long flags;
+	struct sk_buff *skb;
+	
+	/* First of all, check for unreliable messages in the queue,
+	   since they have priority */
+
+	if ((skb = skb_dequeue(&bcsp->unrel)) != NULL) {
+		struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type);
+		if (nskb) {
+			kfree_skb(skb);
+			return nskb;
+		} else {
+			skb_queue_head(&bcsp->unrel, skb);
+			BT_ERR("Could not dequeue pkt because alloc_skb failed");
+		}
+	}
+
+	/* Now, try to send a reliable pkt. We can only send a
+	   reliable packet if the number of packets sent but not yet ack'ed
+	   is < than the winsize */
+
+	spin_lock_irqsave(&bcsp->unack.lock, flags);
+
+	if (bcsp->unack.qlen < BCSP_TXWINSIZE && (skb = skb_dequeue(&bcsp->rel)) != NULL) {
+		struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type);
+		if (nskb) {
+			__skb_queue_tail(&bcsp->unack, skb);
+			mod_timer(&bcsp->tbcsp, jiffies + HZ / 4);
+			spin_unlock_irqrestore(&bcsp->unack.lock, flags);
+			return nskb;
+		} else {
+			skb_queue_head(&bcsp->rel, skb);
+			BT_ERR("Could not dequeue pkt because alloc_skb failed");
+		}
+	}
+
+	spin_unlock_irqrestore(&bcsp->unack.lock, flags);
+
+
+	/* We could not send a reliable packet, either because there are
+	   none or because there are too many unack'ed pkts. Did we receive
+	   any packets we have not acknowledged yet ? */
+
+	if (bcsp->txack_req) {
+		/* if so, craft an empty ACK pkt and send it on BCSP unreliable
+		   channel 0 */
+		struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, NULL, 0, BCSP_ACK_PKT);
+		return nskb;
+	}
+
+	/* We have nothing to send */
+	return NULL;
+}
+
+static int bcsp_flush(struct hci_uart *hu)
+{
+	BT_DBG("hu %p", hu);
+	return 0;
+}
+
+/* Remove ack'ed packets */
+static void bcsp_pkt_cull(struct bcsp_struct *bcsp)
+{
+	unsigned long flags;
+	struct sk_buff *skb;
+	int i, pkts_to_be_removed;
+	u8 seqno;
+
+	spin_lock_irqsave(&bcsp->unack.lock, flags);
+
+	pkts_to_be_removed = bcsp->unack.qlen;
+	seqno = bcsp->msgq_txseq;
+
+	while (pkts_to_be_removed) {
+		if (bcsp->rxack == seqno)
+			break;
+		pkts_to_be_removed--;
+		seqno = (seqno - 1) & 0x07;
+	}
+
+	if (bcsp->rxack != seqno)
+		BT_ERR("Peer acked invalid packet");
+
+	BT_DBG("Removing %u pkts out of %u, up to seqno %u",
+	       pkts_to_be_removed, bcsp->unack.qlen, (seqno - 1) & 0x07);
+
+	for (i = 0, skb = ((struct sk_buff *) &bcsp->unack)->next; i < pkts_to_be_removed
+			&& skb != (struct sk_buff *) &bcsp->unack; i++) {
+		struct sk_buff *nskb;
+
+		nskb = skb->next;
+		__skb_unlink(skb, &bcsp->unack);
+		kfree_skb(skb);
+		skb = nskb;
+	}
+	if (bcsp->unack.qlen == 0)
+		del_timer(&bcsp->tbcsp);
+	spin_unlock_irqrestore(&bcsp->unack.lock, flags);
+
+	if (i != pkts_to_be_removed)
+		BT_ERR("Removed only %u out of %u pkts", i, pkts_to_be_removed);
+}
+
+/* Handle BCSP link-establishment packets. When we
+   detect a "sync" packet, symptom that the BT module has reset,
+   we do nothing :) (yet) */
+static void bcsp_handle_le_pkt(struct hci_uart *hu)
+{
+	struct bcsp_struct *bcsp = hu->priv;
+	u8 conf_pkt[4]     = { 0xad, 0xef, 0xac, 0xed };
+	u8 conf_rsp_pkt[4] = { 0xde, 0xad, 0xd0, 0xd0 };
+	u8 sync_pkt[4]     = { 0xda, 0xdc, 0xed, 0xed };
+
+	/* spot "conf" pkts and reply with a "conf rsp" pkt */
+	if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 &&
+			!memcmp(&bcsp->rx_skb->data[4], conf_pkt, 4)) {
+		struct sk_buff *nskb = alloc_skb(4, GFP_ATOMIC);
+
+		BT_DBG("Found a LE conf pkt");
+		if (!nskb)
+			return;
+		memcpy(skb_put(nskb, 4), conf_rsp_pkt, 4);
+		nskb->pkt_type = BCSP_LE_PKT;
+
+		skb_queue_head(&bcsp->unrel, nskb);
+		hci_uart_tx_wakeup(hu);
+	}
+	/* Spot "sync" pkts. If we find one...disaster! */
+	else if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 &&
+			!memcmp(&bcsp->rx_skb->data[4], sync_pkt, 4)) {
+		BT_ERR("Found a LE sync pkt, card has reset");
+	}
+}
+
+static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char byte)
+{
+	const u8 c0 = 0xc0, db = 0xdb;
+
+	switch (bcsp->rx_esc_state) {
+	case BCSP_ESCSTATE_NOESC:
+		switch (byte) {
+		case 0xdb:
+			bcsp->rx_esc_state = BCSP_ESCSTATE_ESC;
+			break;
+		default:
+			memcpy(skb_put(bcsp->rx_skb, 1), &byte, 1);
+			if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && 
+					bcsp->rx_state != BCSP_W4_CRC)
+				bcsp_crc_update(&bcsp->message_crc, byte);
+			bcsp->rx_count--;
+		}
+		break;
+
+	case BCSP_ESCSTATE_ESC:
+		switch (byte) {
+		case 0xdc:
+			memcpy(skb_put(bcsp->rx_skb, 1), &c0, 1);
+			if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && 
+					bcsp->rx_state != BCSP_W4_CRC)
+				bcsp_crc_update(&bcsp-> message_crc, 0xc0);
+			bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
+			bcsp->rx_count--;
+			break;
+
+		case 0xdd:
+			memcpy(skb_put(bcsp->rx_skb, 1), &db, 1);
+			if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && 
+					bcsp->rx_state != BCSP_W4_CRC) 
+				bcsp_crc_update(&bcsp-> message_crc, 0xdb);
+			bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
+			bcsp->rx_count--;
+			break;
+
+		default:
+			BT_ERR ("Invalid byte %02x after esc byte", byte);
+			kfree_skb(bcsp->rx_skb);
+			bcsp->rx_skb = NULL;
+			bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+			bcsp->rx_count = 0;
+		}
+	}
+}
+
+static inline void bcsp_complete_rx_pkt(struct hci_uart *hu)
+{
+	struct bcsp_struct *bcsp = hu->priv;
+	int pass_up;
+
+	if (bcsp->rx_skb->data[0] & 0x80) {	/* reliable pkt */
+		BT_DBG("Received seqno %u from card", bcsp->rxseq_txack);
+		bcsp->rxseq_txack++;
+		bcsp->rxseq_txack %= 0x8;
+		bcsp->txack_req    = 1;
+
+		/* If needed, transmit an ack pkt */
+		hci_uart_tx_wakeup(hu);
+	}
+
+	bcsp->rxack = (bcsp->rx_skb->data[0] >> 3) & 0x07;
+	BT_DBG("Request for pkt %u from card", bcsp->rxack);
+
+	bcsp_pkt_cull(bcsp);
+	if ((bcsp->rx_skb->data[1] & 0x0f) == 6 &&
+			bcsp->rx_skb->data[0] & 0x80) {
+		bcsp->rx_skb->pkt_type = HCI_ACLDATA_PKT;
+		pass_up = 1;
+	} else if ((bcsp->rx_skb->data[1] & 0x0f) == 5 &&
+			bcsp->rx_skb->data[0] & 0x80) {
+		bcsp->rx_skb->pkt_type = HCI_EVENT_PKT;
+		pass_up = 1;
+	} else if ((bcsp->rx_skb->data[1] & 0x0f) == 7) {
+		bcsp->rx_skb->pkt_type = HCI_SCODATA_PKT;
+		pass_up = 1;
+	} else if ((bcsp->rx_skb->data[1] & 0x0f) == 1 &&
+			!(bcsp->rx_skb->data[0] & 0x80)) {
+		bcsp_handle_le_pkt(hu);
+		pass_up = 0;
+	} else
+		pass_up = 0;
+
+	if (!pass_up) {
+		if ((bcsp->rx_skb->data[1] & 0x0f) != 0 &&
+	    		(bcsp->rx_skb->data[1] & 0x0f) != 1) {
+			BT_ERR ("Packet for unknown channel (%u %s)",
+				bcsp->rx_skb->data[1] & 0x0f,
+				bcsp->rx_skb->data[0] & 0x80 ? 
+				"reliable" : "unreliable");
+		}
+		kfree_skb(bcsp->rx_skb);
+	} else {
+		/* Pull out BCSP hdr */
+		skb_pull(bcsp->rx_skb, 4);
+
+		hci_recv_frame(bcsp->rx_skb);
+	}
+	bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+	bcsp->rx_skb = NULL;
+}
+
+/* Recv data */
+static int bcsp_recv(struct hci_uart *hu, void *data, int count)
+{
+	struct bcsp_struct *bcsp = hu->priv;
+	register unsigned char *ptr;
+
+	BT_DBG("hu %p count %d rx_state %ld rx_count %ld", 
+		hu, count, bcsp->rx_state, bcsp->rx_count);
+
+	ptr = data;
+	while (count) {
+		if (bcsp->rx_count) {
+			if (*ptr == 0xc0) {
+				BT_ERR("Short BCSP packet");
+				kfree_skb(bcsp->rx_skb);
+				bcsp->rx_state = BCSP_W4_PKT_START;
+				bcsp->rx_count = 0;
+			} else
+				bcsp_unslip_one_byte(bcsp, *ptr);
+
+			ptr++; count--;
+			continue;
+		}
+
+		switch (bcsp->rx_state) {
+		case BCSP_W4_BCSP_HDR:
+			if ((0xff & (u8) ~ (bcsp->rx_skb->data[0] + bcsp->rx_skb->data[1] +
+					bcsp->rx_skb->data[2])) != bcsp->rx_skb->data[3]) {
+				BT_ERR("Error in BCSP hdr checksum");
+				kfree_skb(bcsp->rx_skb);
+				bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+				bcsp->rx_count = 0;
+				continue;
+			}
+			if (bcsp->rx_skb->data[0] & 0x80	/* reliable pkt */
+			    		&& (bcsp->rx_skb->data[0] & 0x07) != bcsp->rxseq_txack) {
+				BT_ERR ("Out-of-order packet arrived, got %u expected %u",
+					bcsp->rx_skb->data[0] & 0x07, bcsp->rxseq_txack);
+
+				kfree_skb(bcsp->rx_skb);
+				bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+				bcsp->rx_count = 0;
+				continue;
+			}
+			bcsp->rx_state = BCSP_W4_DATA;
+			bcsp->rx_count = (bcsp->rx_skb->data[1] >> 4) + 
+					(bcsp->rx_skb->data[2] << 4);	/* May be 0 */
+			continue;
+
+		case BCSP_W4_DATA:
+			if (bcsp->rx_skb->data[0] & 0x40) {	/* pkt with crc */
+				bcsp->rx_state = BCSP_W4_CRC;
+				bcsp->rx_count = 2;
+			} else
+				bcsp_complete_rx_pkt(hu);
+			continue;
+
+		case BCSP_W4_CRC:
+			if (bcsp_crc_reverse(bcsp->message_crc) !=
+					(bcsp->rx_skb->data[bcsp->rx_skb->len - 2] << 8) +
+					bcsp->rx_skb->data[bcsp->rx_skb->len - 1]) {
+
+				BT_ERR ("Checksum failed: computed %04x received %04x",
+					bcsp_crc_reverse(bcsp->message_crc),
+				     	(bcsp->rx_skb-> data[bcsp->rx_skb->len - 2] << 8) +
+				     	bcsp->rx_skb->data[bcsp->rx_skb->len - 1]);
+
+				kfree_skb(bcsp->rx_skb);
+				bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+				bcsp->rx_count = 0;
+				continue;
+			}
+			skb_trim(bcsp->rx_skb, bcsp->rx_skb->len - 2);
+			bcsp_complete_rx_pkt(hu);
+			continue;
+
+		case BCSP_W4_PKT_DELIMITER:
+			switch (*ptr) {
+			case 0xc0:
+				bcsp->rx_state = BCSP_W4_PKT_START;
+				break;
+			default:
+				/*BT_ERR("Ignoring byte %02x", *ptr);*/
+				break;
+			}
+			ptr++; count--;
+			break;
+
+		case BCSP_W4_PKT_START:
+			switch (*ptr) {
+			case 0xc0:
+				ptr++; count--;
+				break;
+
+			default:
+				bcsp->rx_state = BCSP_W4_BCSP_HDR;
+				bcsp->rx_count = 4;
+				bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
+				BCSP_CRC_INIT(bcsp->message_crc);
+				
+				/* Do not increment ptr or decrement count
+				 * Allocate packet. Max len of a BCSP pkt= 
+				 * 0xFFF (payload) +4 (header) +2 (crc) */
+
+				bcsp->rx_skb = bluez_skb_alloc(0x1005, GFP_ATOMIC);
+				if (!bcsp->rx_skb) {
+					BT_ERR("Can't allocate mem for new packet");
+					bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+					bcsp->rx_count = 0;
+					return 0;
+				}
+				bcsp->rx_skb->dev = (void *) &hu->hdev;
+				break;
+			}
+			break;
+		}
+	}
+	return count;
+}
+
+	/* Arrange to retransmit all messages in the relq. */
+static void bcsp_timed_event(unsigned long arg)
+{
+	struct hci_uart *hu = (struct hci_uart *) arg;
+	struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv;
+	struct sk_buff *skb;
+	unsigned long flags;
+
+	BT_ERR("Timeout, retransmitting %u pkts", bcsp->unack.qlen);
+	spin_lock_irqsave(&bcsp->unack.lock, flags);
+
+	while ((skb = __skb_dequeue_tail(&bcsp->unack)) != NULL) {
+		bcsp->msgq_txseq = (bcsp->msgq_txseq - 1) & 0x07;
+		skb_queue_head(&bcsp->rel, skb);
+	}
+
+	spin_unlock_irqrestore(&bcsp->unack.lock, flags);
+
+	hci_uart_tx_wakeup(hu);
+}
+
+static int bcsp_open(struct hci_uart *hu)
+{
+	struct bcsp_struct *bcsp;
+
+	BT_DBG("hu %p", hu);
+
+	bcsp = kmalloc(sizeof(*bcsp), GFP_ATOMIC);
+	if (!bcsp)
+		return -ENOMEM;
+	memset(bcsp, 0, sizeof(*bcsp));
+
+	hu->priv = bcsp;
+	skb_queue_head_init(&bcsp->unack);
+	skb_queue_head_init(&bcsp->rel);
+	skb_queue_head_init(&bcsp->unrel);
+
+	init_timer(&bcsp->tbcsp);
+	bcsp->tbcsp.function = bcsp_timed_event;
+	bcsp->tbcsp.data     = (u_long) hu;
+
+	bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+
+	return 0;
+}
+
+static int bcsp_close(struct hci_uart *hu)
+{
+	struct bcsp_struct *bcsp = hu->priv;
+	hu->priv = NULL;
+
+	BT_DBG("hu %p", hu);
+
+	skb_queue_purge(&bcsp->unack);
+	skb_queue_purge(&bcsp->rel);
+	skb_queue_purge(&bcsp->unrel);
+	del_timer(&bcsp->tbcsp);
+
+	kfree(bcsp);
+	return 0;
+}
+
+static struct hci_uart_proto bcsp = {
+	id:      HCI_UART_BCSP,
+	open:    bcsp_open,
+	close:   bcsp_close,
+	enqueue: bcsp_enqueue,
+	dequeue: bcsp_dequeue,
+	recv:    bcsp_recv,
+	flush:   bcsp_flush
+};
+
+int bcsp_init(void)
+{
+	return hci_uart_register_proto(&bcsp);
+}
+
+int bcsp_deinit(void)
+{
+	return hci_uart_unregister_proto(&bcsp);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_bcsp.h linux-2.4.21/drivers/bluetooth/hci_bcsp.h
--- linux-2.4.20/drivers/bluetooth/hci_bcsp.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/bluetooth/hci_bcsp.h	2002-12-18 18:58:10.000000000 +0000
@@ -0,0 +1,70 @@
+/* 
+   BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ).
+   Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com>
+
+   Based on
+       hci_h4.c  by Maxim Krasnyansky <maxk@qualcomm.com>
+       ABCSP     by Carl Orsborn <cjo@csr.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/* 
+ * $Id: hci_bcsp.h,v 1.2 2002/09/26 05:05:14 maxk Exp $
+ */
+
+#ifndef __HCI_BCSP_H__
+#define __HCI_BCSP_H__
+
+#define BCSP_TXWINSIZE  4
+
+#define BCSP_ACK_PKT    0x05
+#define BCSP_LE_PKT     0x06
+
+struct bcsp_struct {
+	struct sk_buff_head unack;	/* Unack'ed packets queue */
+	struct sk_buff_head rel;	/* Reliable packets queue */
+	struct sk_buff_head unrel;	/* Unreliable packets queue */
+
+	unsigned long rx_count;
+	struct  sk_buff *rx_skb;
+	u8      rxseq_txack;		/* rxseq == txack. */
+	u8      rxack;			/* Last packet sent by us that the peer ack'ed */
+	struct  timer_list tbcsp;
+	
+	enum {
+		BCSP_W4_PKT_DELIMITER,
+		BCSP_W4_PKT_START,
+		BCSP_W4_BCSP_HDR,
+		BCSP_W4_DATA,
+		BCSP_W4_CRC
+	} rx_state;
+
+	enum {
+		BCSP_ESCSTATE_NOESC,
+		BCSP_ESCSTATE_ESC
+	} rx_esc_state;
+
+	u16     message_crc;
+	u8      txack_req;		/* Do we need to send ack's to the peer? */
+
+	/* Reliable packet sequence number - used to assign seq to each rel pkt. */
+	u8      msgq_txseq;
+};
+
+#endif	/* __HCI_BCSP_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_h4.c linux-2.4.21/drivers/bluetooth/hci_h4.c
--- linux-2.4.20/drivers/bluetooth/hci_h4.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/drivers/bluetooth/hci_h4.c	2002-12-18 18:58:04.000000000 +0000
@@ -25,9 +25,9 @@
 /*
  * BlueZ HCI UART(H4) protocol.
  *
- * $Id: hci_h4.c,v 1.2 2002/04/17 17:37:20 maxk Exp $    
+ * $Id: hci_h4.c,v 1.3 2002/09/09 01:17:32 maxk Exp $    
  */
-#define VERSION "1.1"
+#define VERSION "1.2"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -64,63 +64,61 @@
 #endif
 
 /* Initialize protocol */
-static int h4_open(struct n_hci *n_hci)
+static int h4_open(struct hci_uart *hu)
 {
 	struct h4_struct *h4;
 	
-	BT_DBG("n_hci %p", n_hci);
+	BT_DBG("hu %p", hu);
 	
 	h4 = kmalloc(sizeof(*h4), GFP_ATOMIC);
 	if (!h4)
 		return -ENOMEM;
 	memset(h4, 0, sizeof(*h4));
 
-	n_hci->priv = h4;
+	skb_queue_head_init(&h4->txq);
+
+	hu->priv = h4;
 	return 0;
 }
 
 /* Flush protocol data */
-static int h4_flush(struct n_hci *n_hci)
+static int h4_flush(struct hci_uart *hu)
 {
-	BT_DBG("n_hci %p", n_hci);
+	struct h4_struct *h4 = hu->priv;
+
+	BT_DBG("hu %p", hu);
+	skb_queue_purge(&h4->txq);
 	return 0;
 }
 
 /* Close protocol */
-static int h4_close(struct n_hci *n_hci)
+static int h4_close(struct hci_uart *hu)
 {
-	struct h4_struct *h4 = n_hci->priv;
-	n_hci->priv = NULL;
+	struct h4_struct *h4 = hu->priv;
+	hu->priv = NULL;
 
-	BT_DBG("n_hci %p", n_hci);
+	BT_DBG("hu %p", hu);
 
+	skb_queue_purge(&h4->txq);
 	if (h4->rx_skb)
 		kfree_skb(h4->rx_skb);
 
+	hu->priv = NULL;
 	kfree(h4);
 	return 0;
 }
 
-/* Send data */
-static int h4_send(struct n_hci *n_hci, void *data, int len)
+/* Enqueue frame for transmittion (padding, crc, etc) */
+static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb)
 {
-	struct tty_struct *tty = n_hci->tty;
-	
-	BT_DBG("n_hci %p len %d", n_hci, len);
-
-	/* Send frame to TTY driver */
-	tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
-	return tty->driver.write(tty, 0, data, len);
-}
+	struct h4_struct *h4 = hu->priv;
 
-/* Init frame before queueing (padding, crc, etc) */
-static struct sk_buff* h4_preq(struct n_hci *n_hci, struct sk_buff *skb)
-{
-	BT_DBG("n_hci %p skb %p", n_hci, skb);
+	BT_DBG("hu %p skb %p", hu, skb);
 
 	/* Prepend skb with frame type */
 	memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
-	return skb;
+	skb_queue_tail(&h4->txq, skb);
+	return 0;
 }
 
 static inline int h4_check_data_len(struct h4_struct *h4, int len)
@@ -132,7 +130,7 @@
 		BT_DMP(h4->rx_skb->data, h4->rx_skb->len);
 		hci_recv_frame(h4->rx_skb);
 	} else if (len > room) {
-		BT_ERR("Data length is to large");
+		BT_ERR("Data length is too large");
 		kfree_skb(h4->rx_skb);
 	} else {
 		h4->rx_state = H4_W4_DATA;
@@ -147,16 +145,17 @@
 }
 
 /* Recv data */
-static int h4_recv(struct n_hci *n_hci, void *data, int count)
+static int h4_recv(struct hci_uart *hu, void *data, int count)
 {
-	struct h4_struct *h4 = n_hci->priv;
+	struct h4_struct *h4 = hu->priv;
 	register char *ptr;
 	hci_event_hdr *eh;
 	hci_acl_hdr   *ah;
 	hci_sco_hdr   *sh;
 	register int len, type, dlen;
 
-	BT_DBG("n_hci %p count %d rx_state %ld rx_count %ld", n_hci, count, h4->rx_state, h4->rx_count);
+	BT_DBG("hu %p count %d rx_state %ld rx_count %ld", 
+			hu, count, h4->rx_state, h4->rx_count);
 
 	ptr = data;
 	while (count) {
@@ -204,7 +203,7 @@
 
 				h4_check_data_len(h4, sh->dlen);
 				continue;
-			};
+			}
 		}
 
 		/* H4_W4_PACKET_TYPE */
@@ -232,7 +231,7 @@
 
 		default:
 			BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
-			n_hci->hdev.stat.err_rx++;
+			hu->hdev.stat.err_rx++;
 			ptr++; count--;
 			continue;
 		};
@@ -246,20 +245,26 @@
 			h4->rx_count = 0;
 			return 0;
 		}
-		h4->rx_skb->dev = (void *) &n_hci->hdev;
+		h4->rx_skb->dev = (void *) &hu->hdev;
 		h4->rx_skb->pkt_type = type;
 	}
 	return count;
 }
 
+static struct sk_buff *h4_dequeue(struct hci_uart *hu)
+{
+	struct h4_struct *h4 = hu->priv;
+	return skb_dequeue(&h4->txq);
+}
+
 static struct hci_uart_proto h4p = {
-	id:    HCI_UART_H4,
-	open:  h4_open,
-	close: h4_close,
-	send:  h4_send,
-	recv:  h4_recv,
-	preq:  h4_preq,
-	flush: h4_flush,
+	id:      HCI_UART_H4,
+	open:    h4_open,
+	close:   h4_close,
+	recv:    h4_recv,
+	enqueue: h4_enqueue,
+	dequeue: h4_dequeue,
+	flush:   h4_flush,
 };
 	      
 int h4_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_h4.h linux-2.4.21/drivers/bluetooth/hci_h4.h
--- linux-2.4.20/drivers/bluetooth/hci_h4.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/drivers/bluetooth/hci_h4.h	2002-12-18 18:58:05.000000000 +0000
@@ -23,7 +23,7 @@
 */
 
 /*
- * $Id: hci_h4.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $
+ * $Id: hci_h4.h,v 1.2 2002/09/09 01:17:32 maxk Exp $
  */
 
 #ifdef __KERNEL__
@@ -31,6 +31,7 @@
 	unsigned long rx_state;
 	unsigned long rx_count;
 	struct sk_buff *rx_skb;
+	struct sk_buff_head txq;
 };
 
 /* H4 receiver States */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_ldisc.c linux-2.4.21/drivers/bluetooth/hci_ldisc.c
--- linux-2.4.20/drivers/bluetooth/hci_ldisc.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/bluetooth/hci_ldisc.c	2002-12-18 18:58:06.000000000 +0000
@@ -25,14 +25,15 @@
 /*
  * BlueZ HCI UART driver.
  *
- * $Id: hci_ldisc.c,v 1.2 2002/04/17 17:37:20 maxk Exp $    
+ * $Id: hci_ldisc.c,v 1.5 2002/10/02 18:37:20 maxk Exp $    
  */
-#define VERSION "2.0"
+#define VERSION "2.1"
 
 #include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/version.h>
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
@@ -87,16 +88,86 @@
 	return 0;
 }
 
-static struct hci_uart_proto *n_hci_get_proto(unsigned int id)
+static struct hci_uart_proto *hci_uart_get_proto(unsigned int id)
 {
 	if (id >= HCI_UART_MAX_PROTO)
 		return NULL;
 	return hup[id];
 }
 
+static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type)
+{
+	struct hci_dev *hdev = &hu->hdev;
+	
+	/* Update HCI stat counters */
+	switch (pkt_type) {
+	case HCI_COMMAND_PKT:
+		hdev->stat.cmd_tx++;
+		break;
+
+	case HCI_ACLDATA_PKT:
+		hdev->stat.acl_tx++;
+		break;
+
+	case HCI_SCODATA_PKT:
+		hdev->stat.cmd_tx++;
+		break;
+	}
+}
+
+static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
+{
+	struct sk_buff *skb = hu->tx_skb;
+	if (!skb)
+		skb = hu->proto->dequeue(hu);
+	else
+		hu->tx_skb = NULL;
+	return skb;
+}
+
+int hci_uart_tx_wakeup(struct hci_uart *hu)
+{
+	struct tty_struct *tty = hu->tty;
+	struct hci_dev *hdev = &hu->hdev;
+	struct sk_buff *skb;
+	
+	if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) {
+		set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
+		return 0;
+	}
+
+	BT_DBG("");
+
+restart:
+	clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
+
+	while ((skb = hci_uart_dequeue(hu))) {
+		int len;
+	
+		set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+		len = tty->driver.write(tty, 0, skb->data, skb->len);
+		hdev->stat.byte_tx += len;
+
+		skb_pull(skb, len);
+		if (skb->len) {
+			hu->tx_skb = skb;
+			break;
+		}
+	
+		hci_uart_tx_complete(hu, skb->pkt_type);
+		kfree_skb(skb);
+	} 
+	
+	if (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state))
+		goto restart;
+
+	clear_bit(HCI_UART_SENDING, &hu->tx_state);
+	return 0;
+}
+
 /* ------- Interface to HCI layer ------ */
 /* Initialize device */
-static int n_hci_open(struct hci_dev *hdev)
+static int hci_uart_open(struct hci_dev *hdev)
 {
 	BT_DBG("%s %p", hdev->name, hdev);
 
@@ -107,15 +178,16 @@
 }
 
 /* Reset device */
-static int n_hci_flush(struct hci_dev *hdev)
+static int hci_uart_flush(struct hci_dev *hdev)
 {
-	struct n_hci *n_hci  = (struct n_hci *) hdev->driver_data;
-	struct tty_struct *tty = n_hci->tty;
+	struct hci_uart *hu  = (struct hci_uart *) hdev->driver_data;
+	struct tty_struct *tty = hu->tty;
 
 	BT_DBG("hdev %p tty %p", hdev, tty);
 
-	/* Drop TX queue */
-	skb_queue_purge(&n_hci->txq);
+	if (hu->tx_skb) {
+		kfree_skb(hu->tx_skb); hu->tx_skb = NULL;
+	}
 
 	/* Flush any pending characters in the driver and discipline. */
 	if (tty->ldisc.flush_buffer)
@@ -124,80 +196,30 @@
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
 
-	if (n_hci->proto->flush)
-		n_hci->proto->flush(n_hci);
+	if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+		hu->proto->flush(hu);
 
 	return 0;
 }
 
 /* Close device */
-static int n_hci_close(struct hci_dev *hdev)
+static int hci_uart_close(struct hci_dev *hdev)
 {
 	BT_DBG("hdev %p", hdev);
 
 	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
 		return 0;
 
-	n_hci_flush(hdev);
-	return 0;
-}
-
-static int n_hci_tx_wakeup(struct n_hci *n_hci)
-{
-	struct hci_dev *hdev = &n_hci->hdev;
-	
-	if (test_and_set_bit(N_HCI_SENDING, &n_hci->tx_state)) {
-		set_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state);
-		return 0;
-	}
-
-	BT_DBG("");
-	do {
-		register struct sk_buff *skb;
-		register int len;
-
-		clear_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state);
-
-		if (!(skb = skb_dequeue(&n_hci->txq)))
-			break;
-
-		len = n_hci->proto->send(n_hci, skb->data, skb->len);
-		n_hci->hdev.stat.byte_tx += len;
-
-		if (len == skb->len) {
-			/* Complete frame was sent */
-
-			switch (skb->pkt_type) {
-			case HCI_COMMAND_PKT:
-				hdev->stat.cmd_tx++;
-				break;
-
-			case HCI_ACLDATA_PKT:
-				hdev->stat.acl_tx++;
-				break;
-
-			case HCI_SCODATA_PKT:
-				hdev->stat.cmd_tx++;
-				break;
-			};
-
-			kfree_skb(skb);
-		} else {
-			/* Subtract sent part and requeue  */
-			skb_pull(skb, len);
-			skb_queue_head(&n_hci->txq, skb);
-		}
-	} while (test_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state));
-	clear_bit(N_HCI_SENDING, &n_hci->tx_state);
+	hci_uart_flush(hdev);
 	return 0;
 }
 
 /* Send frames from HCI layer */
-static int n_hci_send_frame(struct sk_buff *skb)
+static int hci_uart_send_frame(struct sk_buff *skb)
 {
 	struct hci_dev* hdev = (struct hci_dev *) skb->dev;
 	struct tty_struct *tty;
-	struct n_hci *n_hci;
+	struct hci_uart *hu;
 
 	if (!hdev) {
 		BT_ERR("Frame for uknown device (hdev=NULL)");
@@ -207,66 +229,60 @@
 	if (!test_bit(HCI_RUNNING, &hdev->flags))
 		return -EBUSY;
 
-	n_hci = (struct n_hci *) hdev->driver_data;
-	tty = n_hci->tty;
+	hu = (struct hci_uart *) hdev->driver_data;
+	tty = hu->tty;
 
 	BT_DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len);
 
-	if (n_hci->proto->preq) {
-		skb = n_hci->proto->preq(n_hci, skb);
-		if (!skb)
-			return 0;
-	}
-	
-	skb_queue_tail(&n_hci->txq, skb);
-	n_hci_tx_wakeup(n_hci);
+	hu->proto->enqueue(hu, skb);
+
+	hci_uart_tx_wakeup(hu);
 	return 0;
 }
 
-static void n_hci_destruct(struct hci_dev *hdev)
+static void hci_uart_destruct(struct hci_dev *hdev)
 {
-	struct n_hci *n_hci;
+	struct hci_uart *hu;
 
 	if (!hdev) return;
 
 	BT_DBG("%s", hdev->name);
 
-	n_hci = (struct n_hci *) hdev->driver_data;
-	kfree(n_hci);
+	hu = (struct hci_uart *) hdev->driver_data;
+	kfree(hu);
 
 	MOD_DEC_USE_COUNT;
 }
 
 /* ------ LDISC part ------ */
-/* n_hci_tty_open
+/* hci_uart_tty_open
  * 
- *     Called when line discipline changed to N_HCI.
+ *     Called when line discipline changed to HCI_UART.
  *
  * Arguments:
  *     tty    pointer to tty info structure
  * Return Value:    
  *     0 if success, otherwise error code
  */
-static int n_hci_tty_open(struct tty_struct *tty)
+static int hci_uart_tty_open(struct tty_struct *tty)
 {
-	struct n_hci *n_hci = (void *)tty->disc_data;
+	struct hci_uart *hu = (void *) tty->disc_data;
 
 	BT_DBG("tty %p", tty);
 
-	if (n_hci)
+	if (hu)
 		return -EEXIST;
 
-	if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) {
+	if (!(hu = kmalloc(sizeof(struct hci_uart), GFP_KERNEL))) {
 		BT_ERR("Can't allocate controll structure");
 		return -ENFILE;
 	}
-	memset(n_hci, 0, sizeof(struct n_hci));
+	memset(hu, 0, sizeof(struct hci_uart));
 
-	tty->disc_data = n_hci;
-	n_hci->tty = tty;
+	tty->disc_data = hu;
+	hu->tty = tty;
 
-	spin_lock_init(&n_hci->rx_lock);
-	skb_queue_head_init(&n_hci->txq);
+	spin_lock_init(&hu->rx_lock);
 
 	/* Flush any pending characters in the driver and line discipline */
 	if (tty->ldisc.flush_buffer)
@@ -279,34 +295,34 @@
 	return 0;
 }
 
-/* n_hci_tty_close()
+/* hci_uart_tty_close()
  *
  *    Called when the line discipline is changed to something
  *    else, the tty is closed, or the tty detects a hangup.
  */
-static void n_hci_tty_close(struct tty_struct *tty)
+static void hci_uart_tty_close(struct tty_struct *tty)
 {
-	struct n_hci *n_hci = (void *)tty->disc_data;
+	struct hci_uart *hu = (void *)tty->disc_data;
 
 	BT_DBG("tty %p", tty);
 
 	/* Detach from the tty */
 	tty->disc_data = NULL;
 
-	if (n_hci) {
-		struct hci_dev *hdev = &n_hci->hdev;
-		n_hci_close(hdev);
+	if (hu) {
+		struct hci_dev *hdev = &hu->hdev;
+		hci_uart_close(hdev);
 
-		if (test_and_clear_bit(N_HCI_PROTO_SET, &n_hci->flags)) {
-			n_hci->proto->close(n_hci);
+		if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
+			hu->proto->close(hu);
 			hci_unregister_dev(hdev);
 		}
-				
+
 		MOD_DEC_USE_COUNT;
 	}
 }
 
-/* n_hci_tty_wakeup()
+/* hci_uart_tty_wakeup()
  *
  *    Callback for transmit wakeup. Called when low level
  *    device driver can accept more send data.
@@ -314,24 +330,25 @@
  * Arguments:        tty    pointer to associated tty instance data
  * Return Value:    None
  */
-static void n_hci_tty_wakeup( struct tty_struct *tty )
+static void hci_uart_tty_wakeup(struct tty_struct *tty)
 {
-	struct n_hci *n_hci = (void *)tty->disc_data;
+	struct hci_uart *hu = (void *)tty->disc_data;
 
 	BT_DBG("");
 
-	if (!n_hci)
+	if (!hu)
 		return;
 
-	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 
-	if (tty != n_hci->tty)
+	if (tty != hu->tty)
 		return;
 
-	n_hci_tx_wakeup(n_hci);
+	if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+		hci_uart_tx_wakeup(hu);
 }
 
-/* n_hci_tty_room()
+/* hci_uart_tty_room()
  * 
  *    Callback function from tty driver. Return the amount of 
  *    space left in the receiver's buffer to decide if remote
@@ -340,12 +357,12 @@
  * Arguments:        tty    pointer to associated tty instance data
  * Return Value:    number of bytes left in receive buffer
  */
-static int n_hci_tty_room (struct tty_struct *tty)
+static int hci_uart_tty_room (struct tty_struct *tty)
 {
 	return 65536;
 }
 
-/* n_hci_tty_receive()
+/* hci_uart_tty_receive()
  * 
  *     Called by tty low level driver when receive data is
  *     available.
@@ -357,42 +374,42 @@
  *     
  * Return Value:    None
  */
-static void n_hci_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count)
+static void hci_uart_tty_receive(struct tty_struct *tty, const __u8 *data, char *flags, int count)
 {
-	struct n_hci *n_hci = (void *)tty->disc_data;
+	struct hci_uart *hu = (void *)tty->disc_data;
 	
-	if (!n_hci || tty != n_hci->tty)
+	if (!hu || tty != hu->tty)
 		return;
 
-	if (!test_bit(N_HCI_PROTO_SET, &n_hci->flags))
+	if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
 		return;
 	
-	spin_lock(&n_hci->rx_lock);
-	n_hci->proto->recv(n_hci, (void *) data, count);
-	n_hci->hdev.stat.byte_rx += count;
-	spin_unlock(&n_hci->rx_lock);
+	spin_lock(&hu->rx_lock);
+	hu->proto->recv(hu, (void *) data, count);
+	hu->hdev.stat.byte_rx += count;
+	spin_unlock(&hu->rx_lock);
 
 	if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle)
 		tty->driver.unthrottle(tty);
 }
 
-static int n_hci_register_dev(struct n_hci *n_hci)
+static int hci_uart_register_dev(struct hci_uart *hu)
 {
 	struct hci_dev *hdev;
 
 	BT_DBG("");
 
 	/* Initialize and register HCI device */
-	hdev = &n_hci->hdev;
+	hdev = &hu->hdev;
 
 	hdev->type = HCI_UART;
-	hdev->driver_data = n_hci;
+	hdev->driver_data = hu;
 
-	hdev->open  = n_hci_open;
-	hdev->close = n_hci_close;
-	hdev->flush = n_hci_flush;
-	hdev->send  = n_hci_send_frame;
-	hdev->destruct = n_hci_destruct;
+	hdev->open  = hci_uart_open;
+	hdev->close = hci_uart_close;
+	hdev->flush = hci_uart_flush;
+	hdev->send  = hci_uart_send_frame;
+	hdev->destruct = hci_uart_destruct;
 
 	if (hci_register_dev(hdev) < 0) {
 		BT_ERR("Can't register HCI device %s", hdev->name);
@@ -402,30 +419,30 @@
 	return 0;
 }
 
-static int n_hci_set_proto(struct n_hci *n_hci, int id)
+static int hci_uart_set_proto(struct hci_uart *hu, int id)
 {
 	struct hci_uart_proto *p;
 	int err;	
 	
-	p = n_hci_get_proto(id);
+	p = hci_uart_get_proto(id);
 	if (!p)
 		return -EPROTONOSUPPORT;
 
-	err = p->open(n_hci);
+	err = p->open(hu);
 	if (err)
 		return err;
 
-	n_hci->proto = p;
+	hu->proto = p;
 
-	err = n_hci_register_dev(n_hci);
+	err = hci_uart_register_dev(hu);
 	if (err) {
-		p->close(n_hci);
+		p->close(hu);
 		return err;
 	}
 	return 0;
 }
 
-/* n_hci_tty_ioctl()
+/* hci_uart_tty_ioctl()
  *
  *    Process IOCTL system call for the tty device.
  *
@@ -438,24 +455,24 @@
  *
  * Return Value:    Command dependent
  */
-static int n_hci_tty_ioctl(struct tty_struct *tty, struct file * file,
+static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
                             unsigned int cmd, unsigned long arg)
 {
-	struct n_hci *n_hci = (void *)tty->disc_data;
+	struct hci_uart *hu = (void *)tty->disc_data;
 	int err = 0;
 
 	BT_DBG("");
 
 	/* Verify the status of the device */
-	if (!n_hci)
+	if (!hu)
 		return -EBADF;
 
 	switch (cmd) {
 	case HCIUARTSETPROTO:
-		if (!test_and_set_bit(N_HCI_PROTO_SET, &n_hci->flags)) {
-			err = n_hci_set_proto(n_hci, arg);
+		if (!test_and_set_bit(HCI_UART_PROTO_SET, &hu->flags)) {
+			err = hci_uart_set_proto(hu, arg);
 			if (err) {
-				clear_bit(N_HCI_PROTO_SET, &n_hci->flags);
+				clear_bit(HCI_UART_PROTO_SET, &hu->flags);
 				return err;
 			}
 			tty->low_latency = 1;
@@ -463,8 +480,8 @@
 			return -EBUSY;
 
 	case HCIUARTGETPROTO:
-		if (test_bit(N_HCI_PROTO_SET, &n_hci->flags))
-			return n_hci->proto->id;
+		if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+			return hu->proto->id;
 		return -EUNATCH;
 		
 	default:
@@ -478,15 +495,15 @@
 /*
  * We don't provide read/write/poll interface for user space.
  */
-static ssize_t n_hci_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr)
+static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr)
 {
 	return 0;
 }
-static ssize_t n_hci_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count)
+static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count)
 {
 	return 0;
 }
-static unsigned int n_hci_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait)
+static unsigned int hci_uart_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait)
 {
 	return 0;
 }
@@ -495,10 +512,14 @@
 int h4_init(void);
 int h4_deinit(void);
 #endif
+#ifdef CONFIG_BLUEZ_HCIUART_BCSP
+int bcsp_init(void);
+int bcsp_deinit(void);
+#endif
 
-int __init n_hci_init(void)
+int __init hci_uart_init(void)
 {
-	static struct tty_ldisc n_hci_ldisc;
+	static struct tty_ldisc hci_uart_ldisc;
 	int err;
 
 	BT_INFO("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", 
@@ -507,20 +528,20 @@
 
 	/* Register the tty discipline */
 
-	memset(&n_hci_ldisc, 0, sizeof (n_hci_ldisc));
-	n_hci_ldisc.magic       = TTY_LDISC_MAGIC;
-	n_hci_ldisc.name        = "n_hci";
-	n_hci_ldisc.open        = n_hci_tty_open;
-	n_hci_ldisc.close       = n_hci_tty_close;
-	n_hci_ldisc.read        = n_hci_tty_read;
-	n_hci_ldisc.write       = n_hci_tty_write;
-	n_hci_ldisc.ioctl       = n_hci_tty_ioctl;
-	n_hci_ldisc.poll        = n_hci_tty_poll;
-	n_hci_ldisc.receive_room= n_hci_tty_room;
-	n_hci_ldisc.receive_buf = n_hci_tty_receive;
-	n_hci_ldisc.write_wakeup= n_hci_tty_wakeup;
+	memset(&hci_uart_ldisc, 0, sizeof (hci_uart_ldisc));
+	hci_uart_ldisc.magic       = TTY_LDISC_MAGIC;
+	hci_uart_ldisc.name        = "n_hci";
+	hci_uart_ldisc.open        = hci_uart_tty_open;
+	hci_uart_ldisc.close       = hci_uart_tty_close;
+	hci_uart_ldisc.read        = hci_uart_tty_read;
+	hci_uart_ldisc.write       = hci_uart_tty_write;
+	hci_uart_ldisc.ioctl       = hci_uart_tty_ioctl;
+	hci_uart_ldisc.poll        = hci_uart_tty_poll;
+	hci_uart_ldisc.receive_room= hci_uart_tty_room;
+	hci_uart_ldisc.receive_buf = hci_uart_tty_receive;
+	hci_uart_ldisc.write_wakeup= hci_uart_tty_wakeup;
 
-	if ((err = tty_register_ldisc(N_HCI, &n_hci_ldisc))) {
+	if ((err = tty_register_ldisc(N_HCI, &hci_uart_ldisc))) {
 		BT_ERR("Can't register HCI line discipline (%d)", err);
 		return err;
 	}
@@ -528,25 +549,31 @@
 #ifdef CONFIG_BLUEZ_HCIUART_H4
 	h4_init();
 #endif
+#ifdef CONFIG_BLUEZ_HCIUART_BCSP
+	bcsp_init();
+#endif
 	
 	return 0;
 }
 
-void n_hci_cleanup(void)
+void hci_uart_cleanup(void)
 {
 	int err;
 
 #ifdef CONFIG_BLUEZ_HCIUART_H4
 	h4_deinit();
 #endif
+#ifdef CONFIG_BLUEZ_HCIUART_BCSP
+	bcsp_deinit();
+#endif
 
 	/* Release tty registration of line discipline */
 	if ((err = tty_register_ldisc(N_HCI, NULL)))
 		BT_ERR("Can't unregister HCI line discipline (%d)", err);
 }
 
-module_init(n_hci_init);
-module_exit(n_hci_cleanup);
+module_init(hci_uart_init);
+module_exit(hci_uart_cleanup);
 
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
 MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_uart.h linux-2.4.21/drivers/bluetooth/hci_uart.h
--- linux-2.4.20/drivers/bluetooth/hci_uart.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/drivers/bluetooth/hci_uart.h	2002-12-18 18:58:09.000000000 +0000
@@ -23,10 +23,10 @@
 */
 
 /*
- * $Id: hci_uart.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $
+ * $Id: hci_uart.h,v 1.2 2002/09/09 01:17:32 maxk Exp $
  */
 
-#ifndef N_HCI
+#ifndef N_HCI 
 #define N_HCI	15
 #endif
 
@@ -42,19 +42,19 @@
 #define HCI_UART_NCSP	2
 
 #ifdef __KERNEL__
-struct n_hci;
+struct hci_uart;
 
 struct hci_uart_proto {
 	unsigned int id;
-	int (*open)(struct n_hci *n_hci);
-	int (*recv)(struct n_hci *n_hci, void *data, int len);
-	int (*send)(struct n_hci *n_hci, void *data, int len);
-	int (*close)(struct n_hci *n_hci);
-	int (*flush)(struct n_hci *n_hci);
-	struct sk_buff* (*preq)(struct n_hci *n_hci, struct sk_buff *skb);
+	int (*open)(struct hci_uart *hu);
+	int (*close)(struct hci_uart *hu);
+	int (*flush)(struct hci_uart *hu);
+	int (*recv)(struct hci_uart *hu, void *data, int len);
+	int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb);
+	struct sk_buff *(*dequeue)(struct hci_uart *hu);
 };
 
-struct n_hci {
+struct hci_uart {
 	struct tty_struct  *tty;
 	struct hci_dev     hdev;
 	unsigned long      flags;
@@ -62,19 +62,20 @@
 	struct hci_uart_proto *proto;
 	void               *priv;
 	
-	struct sk_buff_head txq;
-	unsigned long       tx_state;
-	spinlock_t          rx_lock;
+	struct sk_buff     *tx_skb;
+	unsigned long      tx_state;
+	spinlock_t         rx_lock;
 };
 
-/* N_HCI flag bits */
-#define N_HCI_PROTO_SET		0x00
+/* HCI_UART flag bits */
+#define HCI_UART_PROTO_SET		0
 
 /* TX states  */
-#define N_HCI_SENDING		1
-#define N_HCI_TX_WAKEUP		2
+#define HCI_UART_SENDING		1
+#define HCI_UART_TX_WAKEUP		2
 
 int hci_uart_register_proto(struct hci_uart_proto *p);
 int hci_uart_unregister_proto(struct hci_uart_proto *p);
+int hci_uart_tx_wakeup(struct hci_uart *hu);
 
 #endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_usb.c linux-2.4.21/drivers/bluetooth/hci_usb.c
--- linux-2.4.20/drivers/bluetooth/hci_usb.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/bluetooth/hci_usb.c	2002-12-18 18:58:07.000000000 +0000
@@ -214,7 +214,7 @@
 
 	err = hci_usb_enable_intr(husb);
 	if (!err) {
-		for (i = 0; i < HCI_MAX_BULK_TX; i++)
+		for (i = 0; i < HCI_MAX_BULK_RX; i++)
 			hci_usb_rx_submit(husb, NULL);
 	} else {
 		clear_bit(HCI_RUNNING, &hdev->flags);
@@ -389,7 +389,7 @@
 }
 
 /* Send frames from HCI layer */
-int hci_usb_send_frame(struct sk_buff *skb)
+static int hci_usb_send_frame(struct sk_buff *skb)
 {
 	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
 	struct hci_usb *husb;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/Config.in linux-2.4.21/drivers/char/Config.in
--- linux-2.4.20/drivers/char/Config.in	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/char/Config.in	2002-12-18 18:58:04.000000000 +0000
@@ -73,6 +73,14 @@
      tristate '    Stallion EasyIO or EC8/32 support' CONFIG_STALLION
      tristate '    Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION
    fi
+   if [ "$CONFIG_PARISC" = "y" ]; then
+     if [ "$CONFIG_PDC_CONSOLE" != "y" ]; then
+       bool '  Serial MUX support' CONFIG_SERIAL_MUX CONFIG_SERIAL_NONSTANDARD
+     fi
+     if [ "$CONFIG_SERIAL_MUX" != "y" ]; then
+       bool '  PDC software console support' CONFIG_PDC_CONSOLE CONFIG_SERIAL_NONSTANDARD
+     fi
+   fi
    if [ "$CONFIG_MIPS" = "y" ]; then
      bool '  TX3912/PR31700 serial port support' CONFIG_SERIAL_TX3912
      dep_bool '     Console on TX3912/PR31700 serial port' CONFIG_SERIAL_TX3912_CONSOLE $CONFIG_SERIAL_TX3912
@@ -147,6 +155,7 @@
       bool '  Support for console on line printer' CONFIG_LP_CONSOLE
    fi
    dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT
+   dep_tristate 'Texas Instruments parallel link cable support' CONFIG_TIPAR $CONFIG_PARPORT
 fi
 
 if [ "$CONFIG_PPC64" ] ; then 
@@ -216,6 +225,7 @@
    tristate '  Mixcom Watchdog' CONFIG_MIXCOMWD 
    tristate '  SBC-60XX Watchdog Timer' CONFIG_60XX_WDT
    dep_tristate '  SC1200 Watchdog Timer (EXPERIMENTAL)' CONFIG_SC1200_WDT $CONFIG_EXPERIMENTAL
+   tristate '  NatSemi SCx200 Watchdog' CONFIG_SCx200_WDT
    tristate '  Software Watchdog' CONFIG_SOFT_WATCHDOG
    tristate '  W83877F (EMACS) Watchdog Timer' CONFIG_W83877F_WDT
    tristate '  WDT Watchdog timer' CONFIG_WDT
@@ -239,6 +249,7 @@
    fi
    tristate 'NetWinder flash support' CONFIG_NWFLASH
 fi
+dep_tristate 'NatSemi SCx200 GPIO Support' CONFIG_SCx200_GPIO $CONFIG_SCx200
 
 if [ "$CONFIG_X86" = "y" -o "$CONFIG_X86_64" = "y" ]; then
    dep_tristate 'AMD 768 Random Number Generator support' CONFIG_AMD_RNG $CONFIG_PCI
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/Makefile linux-2.4.21/drivers/char/Makefile
--- linux-2.4.20/drivers/char/Makefile	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/char/Makefile	2002-12-18 18:58:07.000000000 +0000
@@ -204,6 +204,7 @@
 obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o
 obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o
 obj-$(CONFIG_PRINTER) += lp.o
+obj-$(CONFIG_TIPAR) += tipar.o
 
 ifeq ($(CONFIG_INPUT),y)
 obj-y += joystick/js.o
@@ -254,6 +255,7 @@
 obj-$(CONFIG_DZ) += dz.o
 obj-$(CONFIG_NWBUTTON) += nwbutton.o
 obj-$(CONFIG_NWFLASH) += nwflash.o
+obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o
 
 # Only one watchdog can succeed. We probe the hardware watchdog
 # drivers first, then the softdog driver.  This means if your hardware
@@ -280,6 +282,7 @@
 #obj-$(CONFIG_ALIM1535_WDT) += alim1535d_wdt.o
 obj-$(CONFIG_INDYDOG) += indydog.o
 obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
+obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
 obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
 obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
 obj-$(CONFIG_AMD7XX_TCO) += amd7xx_tco.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/agp/agp.h linux-2.4.21/drivers/char/agp/agp.h
--- linux-2.4.20/drivers/char/agp/agp.h	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/char/agp/agp.h	2002-12-18 18:58:07.000000000 +0000
@@ -87,6 +87,7 @@
 	u32 *gatt_table;
 	u32 *gatt_table_real;
 	unsigned long scratch_page;
+	unsigned long scratch_page_real;
 	unsigned long gart_bus_addr;
 	unsigned long gatt_bus_addr;
 	u32 mode;
@@ -99,7 +100,6 @@
 	int needs_scratch_page;
 	int aperture_size_idx;
 	int num_aperture_sizes;
-	int num_of_masks;
 	int capndx;
 	int cant_use_aperture;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/agp/agpgart_be.c linux-2.4.21/drivers/char/agp/agpgart_be.c
--- linux-2.4.20/drivers/char/agp/agpgart_be.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/char/agp/agpgart_be.c	2002-12-18 18:58:03.000000000 +0000
@@ -209,7 +209,6 @@
 	}
 	if (curr->page_count != 0) {
 		for (i = 0; i < curr->page_count; i++) {
-			curr->memory[i] &= ~(0x00000fff);
 			agp_bridge.agp_destroy_page((unsigned long)
 					 phys_to_virt(curr->memory[i]));
 		}
@@ -262,10 +261,7 @@
 			agp_free_memory(new);
 			return NULL;
 		}
-		new->memory[i] =
-		    agp_bridge.mask_memory(
-				   virt_to_phys((void *) new->memory[i]),
-						  type);
+		new->memory[i] = virt_to_phys((void *) new->memory[i]);
 		new->page_count++;
 	}
 
@@ -311,9 +307,6 @@
 
 int agp_copy_info(agp_kern_info * info)
 {
-	unsigned long page_mask = 0;
-	int i;
-
 	memset(info, 0, sizeof(agp_kern_info));
 	if (agp_bridge.type == NOT_SUPPORTED) {
 		info->chipset = agp_bridge.type;
@@ -329,11 +322,7 @@
 	info->max_memory = agp_bridge.max_memory_agp;
 	info->current_memory = atomic_read(&agp_bridge.current_memory_agp);
 	info->cant_use_aperture = agp_bridge.cant_use_aperture;
-
-	for(i = 0; i < agp_bridge.num_of_masks; i++)
-		page_mask |= agp_bridge.mask_memory(page_mask, i);
-
-	info->page_mask = ~page_mask;
+	info->page_mask = ~0UL;
 	return 0;
 }
 
@@ -731,7 +720,8 @@
 		mem->is_flushed = TRUE;
 	}
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		agp_bridge.gatt_table[j] = mem->memory[i];
+		agp_bridge.gatt_table[j] =
+			agp_bridge.mask_memory(mem->memory[i], mem->type);
 	}
 
 	agp_bridge.tlb_flush(mem);
@@ -976,7 +966,8 @@
    	CACHE_FLUSH();
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 		OUTREG32(intel_i810_private.registers,
-			 I810_PTE_BASE + (j * 4), mem->memory[i]);
+			 I810_PTE_BASE + (j * 4),
+			 agp_bridge.mask_memory(mem->memory[i], mem->type));
 	}
 	CACHE_FLUSH();
 
@@ -1042,10 +1033,7 @@
 			agp_free_memory(new);
 			return NULL;
 		}
-		new->memory[0] =
-		    agp_bridge.mask_memory(
-				   virt_to_phys((void *) new->memory[0]),
-						  type);
+		new->memory[0] = virt_to_phys((void *) new->memory[0]);
 		new->page_count = 1;
 	   	new->num_scratch_pages = 1;
 	   	new->type = AGP_PHYS_MEMORY;
@@ -1079,7 +1067,6 @@
 	intel_i810_private.i810_dev = i810_dev;
 
 	agp_bridge.masks = intel_i810_masks;
-	agp_bridge.num_of_masks = 2;
 	agp_bridge.aperture_sizes = (void *) intel_i810_sizes;
 	agp_bridge.size_type = FIXED_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 2;
@@ -1282,7 +1269,8 @@
 	CACHE_FLUSH();
 
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++)
-		OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),mem->memory[i]);
+		OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),
+			 agp_bridge.mask_memory(mem->memory[i], mem->type));
 
 	CACHE_FLUSH();
 
@@ -1343,7 +1331,7 @@
 			return(NULL);
 		}
 
-		nw->memory[0] = agp_bridge.mask_memory(virt_to_phys((void *) nw->memory[0]),type);
+		nw->memory[0] = virt_to_phys((void *) nw->memory[0]);
 		nw->page_count = 1;
 		nw->num_scratch_pages = 1;
 		nw->type = AGP_PHYS_MEMORY;
@@ -1359,7 +1347,6 @@
 	intel_i830_private.i830_dev = i830_dev;
 
 	agp_bridge.masks = intel_i810_masks;
-	agp_bridge.num_of_masks = 3;
 	agp_bridge.aperture_sizes = (void *) intel_i830_sizes;
 	agp_bridge.size_type = FIXED_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 2;
@@ -1841,7 +1828,6 @@
 static int __init intel_generic_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_generic_sizes;
 	agp_bridge.size_type = U16_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -1874,7 +1860,6 @@
 static int __init intel_815_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_815_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 2;
@@ -1907,7 +1892,6 @@
 static int __init intel_820_setup (struct pci_dev *pdev)
 {
        agp_bridge.masks = intel_generic_masks;
-       agp_bridge.num_of_masks = 1;
        agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
        agp_bridge.size_type = U8_APER_SIZE;
        agp_bridge.num_aperture_sizes = 7;
@@ -1940,7 +1924,6 @@
 static int __init intel_830mp_setup (struct pci_dev *pdev)
 {
        agp_bridge.masks = intel_generic_masks;
-       agp_bridge.num_of_masks = 1;
        agp_bridge.aperture_sizes = (void *) intel_830mp_sizes;
        agp_bridge.size_type = U8_APER_SIZE;
        agp_bridge.num_aperture_sizes = 4;
@@ -1972,7 +1955,6 @@
 static int __init intel_840_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2005,7 +1987,6 @@
 static int __init intel_845_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2038,7 +2019,6 @@
 static int __init intel_850_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2071,7 +2051,6 @@
 static int __init intel_860_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2191,7 +2170,6 @@
 static int __init via_generic_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = via_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) via_generic_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2305,7 +2283,6 @@
 static int __init sis_generic_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = sis_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) sis_generic_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2643,7 +2620,8 @@
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 		addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr;
 		cur_gatt = GET_GATT(addr);
-		cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i];
+		cur_gatt[GET_GATT_OFF(addr)] =
+			agp_bridge.mask_memory(mem->memory[i], mem->type);
 	}
 	agp_bridge.tlb_flush(mem);
 	return 0;
@@ -2689,7 +2667,6 @@
 static int __init amd_irongate_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = amd_irongate_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) amd_irongate_sizes;
 	agp_bridge.size_type = LVL2_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2790,7 +2767,7 @@
 	}
 
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		addr = mem->memory[i];
+		addr = agp_bridge.mask_memory(mem->memory[i], mem->type);
 
 		tmp = addr;
 		BUG_ON(tmp & 0xffffff0000000ffc);
@@ -3155,7 +3132,6 @@
 static int __init amd_8151_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = amd_8151_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) amd_8151_sizes;
 	agp_bridge.size_type = U32_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -3393,7 +3369,6 @@
 static int __init ali_generic_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = ali_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) ali_generic_sizes;
 	agp_bridge.size_type = U32_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -3807,7 +3782,8 @@
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 		addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr;
 		cur_gatt = SVRWRKS_GET_GATT(addr);
-		cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i];
+		cur_gatt[GET_GATT_OFF(addr)] =
+			agp_bridge.mask_memory(mem->memory[i], mem->type);
 	}
 	agp_bridge.tlb_flush(mem);
 	return 0;
@@ -3964,7 +3940,6 @@
 	serverworks_private.svrwrks_dev = pdev;
 
 	agp_bridge.masks = serverworks_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) serverworks_sizes;
 	agp_bridge.size_type = LVL2_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -4362,7 +4337,6 @@
 static int __init hp_zx1_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = hp_zx1_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.dev_private_data = NULL;
 	agp_bridge.size_type = FIXED_APER_SIZE;
 	agp_bridge.needs_scratch_page = FALSE;
@@ -4485,12 +4459,6 @@
 		"AMD",
 		"761",
 		amd_irongate_setup },
-	{ PCI_DEVICE_ID_AMD_762_0,
-		PCI_VENDOR_ID_AMD,
-		AMD_762,
-		"AMD",
-		"760MP",
-		amd_irongate_setup },
 	{ 0,
 		PCI_VENDOR_ID_AMD,
 		AMD_GENERIC,
@@ -4556,7 +4524,7 @@
 		 INTEL_I845_G,
 		 "Intel",
 		 "i845G",
-		 intel_830mp_setup },
+		 intel_845_setup },
 	{ PCI_DEVICE_ID_INTEL_840_0,
 		PCI_VENDOR_ID_INTEL,
 		INTEL_I840,
@@ -4714,6 +4682,12 @@
 		"Via",
 		"Apollo Pro KT266",
 		via_generic_setup },
+        { PCI_DEVICE_ID_VIA_8377_0,
+		PCI_VENDOR_ID_VIA,
+		VIA_APOLLO_KT400,
+		"Via",
+		"Apollo Pro KT400",
+		via_generic_setup },
 	{ 0,
 		PCI_VENDOR_ID_VIA,
 		VIA_GENERIC,
@@ -5077,17 +5051,17 @@
 	}
 
 	if (agp_bridge.needs_scratch_page == TRUE) {
-		agp_bridge.scratch_page = agp_bridge.agp_alloc_page();
+		unsigned long addr;
+		addr = agp_bridge.agp_alloc_page();
 
-		if (agp_bridge.scratch_page == 0) {
+		if (addr == 0) {
 			printk(KERN_ERR PFX "unable to get memory for "
 			       "scratch page.\n");
 			return -ENOMEM;
 		}
+		agp_bridge.scratch_page_real = virt_to_phys((void *) addr);
 		agp_bridge.scratch_page =
-		    virt_to_phys((void *) agp_bridge.scratch_page);
-		agp_bridge.scratch_page =
-		    agp_bridge.mask_memory(agp_bridge.scratch_page, 0);
+		    agp_bridge.mask_memory(agp_bridge.scratch_page_real, 0);
 	}
 
 	size_value = agp_bridge.fetch_size();
@@ -5129,9 +5103,8 @@
 
 err_out:
 	if (agp_bridge.needs_scratch_page == TRUE) {
-		agp_bridge.scratch_page &= ~(0x00000fff);
 		agp_bridge.agp_destroy_page((unsigned long)
-				 phys_to_virt(agp_bridge.scratch_page));
+				 phys_to_virt(agp_bridge.scratch_page_real));
 	}
 	if (got_gatt)
 		agp_bridge.free_gatt_table();
@@ -5149,9 +5122,8 @@
 	vfree(agp_bridge.key_list);
 
 	if (agp_bridge.needs_scratch_page == TRUE) {
-		agp_bridge.scratch_page &= ~(0x00000fff);
 		agp_bridge.agp_destroy_page((unsigned long)
-				 phys_to_virt(agp_bridge.scratch_page));
+				 phys_to_virt(agp_bridge.scratch_page_real));
 	}
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/amd768_rng.c linux-2.4.21/drivers/char/amd768_rng.c
--- linux-2.4.20/drivers/char/amd768_rng.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/drivers/char/amd768_rng.c	2002-12-18 18:58:03.000000000 +0000
@@ -5,7 +5,7 @@
  	derived from
  
 	Hardware driver for Intel i810 Random Number Generator (RNG)
-	Copyright 2000,2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+	Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
 
 	Please read Documentation/i810_rng.txt for details on use.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/cyclades.c linux-2.4.21/drivers/char/cyclades.c
--- linux-2.4.20/drivers/char/cyclades.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/char/cyclades.c	2002-12-18 18:58:04.000000000 +0000
@@ -4957,7 +4957,7 @@
   struct pci_dev	*pdev = NULL;
   unsigned char		cyy_rev_id;
   unsigned char         cy_pci_irq = 0;
-  uclong		cy_pci_phys0, cy_pci_phys1, cy_pci_phys2;
+  uclong		cy_pci_phys0, cy_pci_phys2;
   uclong		cy_pci_addr0, cy_pci_addr2;
   unsigned short        i,j,cy_pci_nchan, plx_ver;
   unsigned short        device_id,dev_index = 0;
@@ -4965,8 +4965,7 @@
   uclong		Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0;
   uclong		Ze_phys0[NR_CARDS], Ze_phys2[NR_CARDS];
   unsigned char         Ze_irq[NR_CARDS];
-  struct resource *resource;
-  unsigned long res_start, res_len;
+  struct pci_dev	*Ze_pdev[NR_CARDS];
 
         for (i = 0; i < NR_CARDS; i++) {
                 /* look for a Cyclades card by vendor and device id */
@@ -4988,7 +4987,6 @@
                 /* read PCI configuration area */
 		cy_pci_irq = pdev->irq;
 		cy_pci_phys0 = pci_resource_start(pdev, 0);
-		cy_pci_phys1 = pci_resource_start(pdev, 1);
 		cy_pci_phys2 = pci_resource_start(pdev, 2);
 		pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
 
@@ -5014,14 +5012,11 @@
 		/* Although we don't use this I/O region, we should
 		   request it from the kernel anyway, to avoid problems
 		   with other drivers accessing it. */
-		resource = request_region(cy_pci_phys1, CyPCI_Yctl, "Cyclom-Y");
-		if (resource == NULL) {
-		    printk(KERN_ERR "cyclades: failed to allocate IO "
-				    "resource at 0x%lx\n", cy_pci_phys1);
+		if (pci_request_regions(pdev, "Cyclom-Y") != 0) {
+		    printk(KERN_ERR "cyclades: failed to reserve PCI "
+				    "resources\n");
 		    continue;
 		}
-		res_start = cy_pci_phys1;
-		res_len = CyPCI_Yctl;
 
 #if defined(__alpha__)
                 if (device_id  == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
@@ -5092,10 +5087,7 @@
                 cy_card[j].bus_index = 1;
                 cy_card[j].first_line = cy_next_channel;
                 cy_card[j].num_chips = cy_pci_nchan/4;
-		cy_card[j].resource = resource;
-		cy_card[j].res_start = res_start;
-		cy_card[j].res_len = res_len;
-		resource = NULL;	/* For next card */
+		cy_card[j].pdev = pdev;
 
                 /* enable interrupts in the PCI interface */
 		plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f;
@@ -5175,16 +5167,13 @@
 		/* Although we don't use this I/O region, we should
 		   request it from the kernel anyway, to avoid problems
 		   with other drivers accessing it. */
-		resource = request_region(cy_pci_phys1, CyPCI_Zctl, 
-					  "Cyclades-Z");
-		if (resource == NULL) {
-		    printk(KERN_ERR "cyclades: failed to allocate IO "
-				    "resource at 0x%lx\n", cy_pci_phys1);
-		    continue;
-		}
-		res_start = cy_pci_phys1;
-		res_len = CyPCI_Zctl;
 
+		if (pci_request_regions(pdev, "Cyclades-Z") != 0) {
+			printk(KERN_ERR "cyclades: failed to reserve PCI "
+				    "resources\n");
+  			continue;
+  		}
+  
 		if (mailbox == ZE_V1) {
 		    cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Ze_win);
 		    if (ZeIndex == NR_CARDS) {
@@ -5198,6 +5187,7 @@
 			Ze_addr0[ZeIndex] = cy_pci_addr0;
 			Ze_addr2[ZeIndex] = cy_pci_addr2;
 			Ze_irq[ZeIndex] = cy_pci_irq;
+			Ze_pdev[ZeIndex] = pdev;
 			ZeIndex++;
 		    }
 		    i--;
@@ -5282,10 +5272,7 @@
                 cy_card[j].bus_index = 1;
                 cy_card[j].first_line = cy_next_channel;
                 cy_card[j].num_chips = -1;
-		cy_card[j].resource = resource;
-		cy_card[j].res_start = res_start;
-		cy_card[j].res_len = res_len;
-		resource = NULL;	/* For next card */
+		cy_card[j].pdev = pdev;
 
                 /* print message */
 #ifdef CONFIG_CYZ_INTR
@@ -5313,12 +5300,14 @@
 	    cy_pci_addr0 = Ze_addr0[0];
 	    cy_pci_addr2 = Ze_addr2[0];
 	    cy_pci_irq = Ze_irq[0];
+	    pdev = Ze_pdev[0];
 	    for (j = 0 ; j < ZeIndex-1 ; j++) {
 		Ze_phys0[j] = Ze_phys0[j+1];
 		Ze_phys2[j] = Ze_phys2[j+1];
 		Ze_addr0[j] = Ze_addr0[j+1];
 		Ze_addr2[j] = Ze_addr2[j+1];
 		Ze_irq[j] = Ze_irq[j+1];
+		Ze_pdev[j] = Ze_pdev[j+1];
 	    }
 	    ZeIndex--;
 		mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 *) 
@@ -5376,6 +5365,7 @@
                 cy_card[j].bus_index = 1;
                 cy_card[j].first_line = cy_next_channel;
                 cy_card[j].num_chips = -1;
+		cy_card[j].pdev = pdev;
 
                 /* print message */
 #ifdef CONFIG_CYZ_INTR
@@ -5812,10 +5802,8 @@
 #endif /* CONFIG_CYZ_INTR */
 	    )
 		free_irq(cy_card[i].irq, &cy_card[i]);
-	    if (cy_card[i].resource) {
-		cy_card[i].resource = NULL;
-		release_region(cy_card[i].res_start, cy_card[i].res_len);
-	    }
+	    if (cy_card[i].pdev)
+	    	pci_release_regions(cy_card[i].pdev);
         }
     }
     if (tmp_buf) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/drm_agpsupport.h linux-2.4.21/drivers/char/drm/drm_agpsupport.h
--- linux-2.4.20/drivers/char/drm/drm_agpsupport.h	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/char/drm/drm_agpsupport.h	2002-12-18 18:58:01.000000000 +0000
@@ -279,6 +279,8 @@
 			break;
 		case VIA_APOLLO_KT133:	head->chipset = "VIA Apollo KT133";
 			break;
+		case VIA_APOLLO_KT400:  head->chipset = "VIA Apollo KT400";
+			break;
 		case VIA_APOLLO_PRO: 	head->chipset = "VIA Apollo Pro";
 			break;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/drm_auth.h linux-2.4.21/drivers/char/drm/drm_auth.h
--- linux-2.4.20/drivers/char/drm/drm_auth.h	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/char/drm/drm_auth.h	2002-12-18 18:58:11.000000000 +0000
@@ -63,6 +63,7 @@
 	hash	     = DRM(hash_magic)(magic);
 	entry	     = DRM(alloc)(sizeof(*entry), DRM_MEM_MAGIC);
 	if (!entry) return -ENOMEM;
+	memset(entry, 0, sizeof(*entry));
 	entry->magic = magic;
 	entry->priv  = priv;
 	entry->next  = NULL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm-4.0/agpsupport.c linux-2.4.21/drivers/char/drm-4.0/agpsupport.c
--- linux-2.4.20/drivers/char/drm-4.0/agpsupport.c	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.21/drivers/char/drm-4.0/agpsupport.c	2002-12-18 18:58:11.000000000 +0000
@@ -275,6 +275,8 @@
 			break;
 		case VIA_APOLLO_KT133:	head->chipset = "VIA Apollo KT133"; 
 			break;
+		case VIA_APOLLO_KT400:  head->chipset = "VIA Apollo KT400";
+			break;
 #endif
 
 		case VIA_APOLLO_PRO: 	head->chipset = "VIA Apollo Pro";
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/efirtc.c linux-2.4.21/drivers/char/efirtc.c
--- linux-2.4.20/drivers/char/efirtc.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/char/efirtc.c	2002-12-18 18:58:10.000000000 +0000
@@ -40,7 +40,7 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
-#define EFI_RTC_VERSION		"0.3"
+#define EFI_RTC_VERSION		"0.4"
 
 #define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
 /*
@@ -315,14 +315,14 @@
 	spin_unlock_irqrestore(&efi_rtc_lock,flags);
 
 	p += sprintf(p,
-		     "Time          : %u:%u:%u.%09u\n"
-		     "Date          : %u-%u-%u\n"
-		     "Daylight      : %u\n",
+		     "Time           : %u:%u:%u.%09u\n"
+		     "Date           : %u-%u-%u\n"
+		     "Daylight       : %u\n",
 		     eft.hour, eft.minute, eft.second, eft.nanosecond, 
 		     eft.year, eft.month, eft.day,
 		     eft.daylight);
 
-	if ( eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
+	if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
 		p += sprintf(p, "Timezone       : unspecified\n");
 	else
 		/* XXX fixme: convert to string? */
@@ -341,7 +341,7 @@
 		     enabled == 1 ? "yes" : "no",
 		     pending == 1 ? "yes" : "no");
 
-	if ( eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
+	if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
 		p += sprintf(p, "Timezone       : unspecified\n");
 	else
 		/* XXX fixme: convert to string? */
@@ -375,12 +375,25 @@
 static int __init 
 efi_rtc_init(void)
 {
-	printk(KERN_INFO "EFI Time Services Driver v%s\n", EFI_RTC_VERSION);
+	int ret;
+	struct proc_dir_entry *dir;
 
-	misc_register(&efi_rtc_dev);
+	printk(KERN_INFO "EFI Time Services Driver v%s\n", EFI_RTC_VERSION);
 
-	create_proc_read_entry ("driver/efirtc", 0, NULL, efi_rtc_read_proc, NULL);
+	ret = misc_register(&efi_rtc_dev);
+	if (ret) {
+		printk(KERN_ERR "efirtc: can't misc_register on minor=%d\n",
+				EFI_RTC_MINOR);
+		return ret;
+	}
 
+	dir = create_proc_read_entry ("driver/efirtc", 0, NULL,
+			              efi_rtc_read_proc, NULL);
+	if (dir == NULL) {
+		printk(KERN_ERR "efirtc: can't create /proc/driver/efirtc.\n");
+		misc_deregister(&efi_rtc_dev);
+		return -1;
+	}
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/epca.c linux-2.4.21/drivers/char/epca.c
--- linux-2.4.20/drivers/char/epca.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/drivers/char/epca.c	2002-12-18 18:58:02.000000000 +0000
@@ -2023,7 +2023,8 @@
 	    (*(ushort *)((ulong)memaddr + XEPORTS) < 3))
 		shrinkmem = 1;
 	if (bd->type < PCIXEM)
-		request_region((int)bd->port, 4, board_desc[bd->type]);
+		if (!request_region((int)bd->port, 4, board_desc[bd->type]))
+			return;		
 
 	memwinon(bd, 0);
 
@@ -2187,9 +2188,13 @@
 		if (!(ch->tmp_buf))
 		{
 			printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i);
-
+			release_region((int)bd->port, 4);
+			while(i-- > 0)
+				kfree((ch--)->tmp_buf);
+			return;
 		}
-		memset((void *)ch->tmp_buf,0,ch->txbufsize);
+		else 
+			memset((void *)ch->tmp_buf,0,ch->txbufsize);
 	} /* End for each port */
 
 	printk(KERN_INFO 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/i810_rng.c linux-2.4.21/drivers/char/i810_rng.c
--- linux-2.4.20/drivers/char/i810_rng.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/drivers/char/i810_rng.c	2002-12-18 18:58:08.000000000 +0000
@@ -1,7 +1,7 @@
 /*
 
 	Hardware driver for Intel i810 Random Number Generator (RNG)
-	Copyright 2000,2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+	Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
 
 	Driver Web site:  http://sourceforge.net/projects/gkernel/
@@ -27,6 +27,7 @@
 #include <linux/miscdevice.h>
 #include <linux/smp_lock.h>
 #include <linux/mm.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -243,8 +244,13 @@
 		if (filp->f_flags & O_NONBLOCK)
 			return ret ? : -EAGAIN;
 
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(1);
+		if (current->need_resched)
+		{
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(1);
+		}
+		else
+			udelay(200);
 
 		if (signal_pending (current))
 			return ret ? : -ERESTARTSYS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/isicom.c linux-2.4.21/drivers/char/isicom.c
--- linux-2.4.20/drivers/char/isicom.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/drivers/char/isicom.c	2002-12-18 18:58:02.000000000 +0000
@@ -2016,7 +2016,7 @@
 	retval=misc_register(&isiloader_device);
 	if (retval<0) {
 		printk(KERN_ERR "ISICOM: Unable to register firmware loader driver.\n");
-		return -EIO;
+		return retval;
 	}
 	
 	if (!isicom_init()) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/joystick/pcigame.c linux-2.4.21/drivers/char/joystick/pcigame.c
--- linux-2.4.20/drivers/char/joystick/pcigame.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/char/joystick/pcigame.c	2002-12-18 18:58:03.000000000 +0000
@@ -195,7 +195,7 @@
 
 int __init pcigame_init(void)
 {
-	pci_module_init(&pcigame_driver);
+	pci_register_driver(&pcigame_driver);
 	/* Needed by other modules */
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/pcmcia/serial_cs.c linux-2.4.21/drivers/char/pcmcia/serial_cs.c
--- linux-2.4.20/drivers/char/pcmcia/serial_cs.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.21/drivers/char/pcmcia/serial_cs.c	2002-12-18 18:58:08.000000000 +0000
@@ -2,7 +2,7 @@
 
     A driver for PCMCIA serial devices
 
-    serial_cs.c 1.128 2001/10/18 12:18:35
+    serial_cs.c 1.138 2002/10/25 06:24:52
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -28,7 +28,7 @@
     and other provisions required by the GPL.  If you do not delete
     the provisions above, a recipient may use your version of this
     file under either the MPL or the GPL.
-    
+
 ======================================================================*/
 
 #include <linux/module.h>
@@ -69,14 +69,14 @@
 static int irq_list[4] = { -1 };
 MODULE_PARM(irq_list, "1-4i");
 
-/* Enable the speaker? */
-INT_MODULE_PARM(do_sound, 1);
+INT_MODULE_PARM(do_sound, 1);		/* Enable the speaker? */
+INT_MODULE_PARM(buggy_uart, 0);		/* Skip strict UART tests? */
 
 #ifdef PCMCIA_DEBUG
 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"serial_cs.c 1.128 2001/10/18 12:18:35 (David Hinds)";
+"serial_cs.c 1.138 2002/10/25 06:24:52 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -95,6 +95,7 @@
     { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 },
     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
+    { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D2, 2 },
     { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS422, 2 },
     { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS422, 4 },
@@ -148,7 +149,7 @@
     client_reg_t client_reg;
     dev_link_t *link;
     int i, ret;
-    
+
     DEBUG(0, "serial_attach()\n");
 
     /* Create new serial device */
@@ -160,7 +161,7 @@
     link->release.function = &serial_release;
     link->release.data = (u_long)link;
     link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-    link->io.NumPorts1 = 8;
+    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
     link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
     if (irq_list[0] == -1)
@@ -169,13 +170,12 @@
 	for (i = 0; i < 4; i++)
 	    link->irq.IRQInfo2 |= 1 << irq_list[i];
     link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
     if (do_sound) {
 	link->conf.Attributes |= CONF_ENABLE_SPKR;
 	link->conf.Status = CCSR_AUDIO_ENA;
     }
     link->conf.IntType = INT_MEMORY_AND_IO;
-    
+
     /* Register with Card Services */
     link->next = dev_list;
     dev_list = link;
@@ -194,7 +194,7 @@
 	serial_detach(link);
 	return NULL;
     }
-    
+
     return link;
 } /* serial_attach */
 
@@ -214,7 +214,7 @@
     int ret;
 
     DEBUG(0, "serial_detach(0x%p)\n", link);
-    
+
     /* Locate device structure */
     for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
 	if (*linkp == link) break;
@@ -224,17 +224,17 @@
     del_timer(&link->release);
     if (link->state & DEV_CONFIG)
 	serial_release((u_long)link);
-    
+
     if (link->handle) {
 	ret = CardServices(DeregisterClient, link->handle);
 	if (ret != CS_SUCCESS)
 	    cs_error(link->handle, DeregisterClient, ret);
     }
-    
+
     /* Unlink device structure, free bits */
     *linkp = link->next;
     kfree(info);
-    
+
 } /* serial_detach */
 
 /*====================================================================*/
@@ -243,18 +243,20 @@
 {
     struct serial_struct serial;
     int line;
-    
+
     memset(&serial, 0, sizeof(serial));
     serial.port = port;
     serial.irq = irq;
     serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ;
+    if (buggy_uart)
+	serial.flags |= ASYNC_BUGGY_UART;
     line = register_serial(&serial);
     if (line < 0) {
 	printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx,"
 	       " irq %d failed\n", (u_long)serial.port, serial.irq);
 	return -1;
     }
-    
+
     info->line[info->ndev] = line;
     sprintf(info->node[info->ndev].dev_name, "ttyS%d", line);
     info->node[info->ndev].major = TTY_MAJOR;
@@ -262,7 +264,7 @@
     if (info->ndev > 0)
 	info->node[info->ndev-1].next = &info->node[info->ndev];
     info->ndev++;
-    
+
     return 0;
 }
 
@@ -313,7 +315,10 @@
 	    return setup_serial(info, port, config.AssignedIRQ);
     }
     link->conf.Vcc = config.Vcc;
-    
+
+    link->io.NumPorts1 = 8;
+    link->io.NumPorts2 = 0;
+
     /* First pass: look for a config entry that looks normal. */
     tuple.TupleData = (cisdata_t *)buf;
     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
@@ -340,7 +345,7 @@
 	    i = next_tuple(handle, &tuple, &parse);
 	}
     }
-    
+
     /* Second pass: try to find an entry that isn't picky about
        its base address, then try to grab any standard serial port
        address, and finally try to get any free port. */
@@ -352,8 +357,7 @@
 	    for (j = 0; j < 5; j++) {
 		link->io.BasePort1 = base[j];
 		link->io.IOAddrLines = base[j] ? 16 : 3;
-		i = CardServices(RequestIO, link->handle,
-				 &link->io);
+		i = CardServices(RequestIO, link->handle, &link->io);
 		if (i == CS_SUCCESS) goto found_port;
 	    }
 	}
@@ -365,7 +369,7 @@
 	cs_error(link->handle, RequestIO, i);
 	return -1;
     }
-    
+
     i = CardServices(RequestIRQ, link->handle, &link->irq);
     if (i != CS_SUCCESS) {
 	cs_error(link->handle, RequestIRQ, i);
@@ -390,8 +394,12 @@
     u_char buf[256];
     cisparse_t parse;
     cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+    config_info_t config;
     int i, base2 = 0;
 
+    CardServices(GetConfigurationInfo, handle, &config);
+    link->conf.Vcc = config.Vcc;
+
     tuple.TupleData = (cisdata_t *)buf;
     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
     tuple.Attributes = 0;
@@ -433,12 +441,12 @@
 	    i = next_tuple(handle, &tuple, &parse);
 	}
     }
-    
+
     if (i != CS_SUCCESS) {
-	cs_error(link->handle, RequestIO, i);
-	return -1;
+	/* At worst, try to configure as a single port */
+	return simple_config(link);
     }
-    
+
     i = CardServices(RequestIRQ, link->handle, &link->irq);
     if (i != CS_SUCCESS) {
 	cs_error(link->handle, RequestIRQ, i);
@@ -454,14 +462,27 @@
 	cs_error(link->handle, RequestConfiguration, i);
 	return -1;
     }
-    
+
+    /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
+       8 registers are for the UART, the others are extra registers */
+    if (info->manfid == MANFID_OXSEMI) {
+	if (cf->index == 1 || cf->index == 3) {
+	    setup_serial(info, base2, link->irq.AssignedIRQ);
+	    outb(12,link->io.BasePort1+1);
+	} else {
+	    setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
+	    outb(12,base2+1);
+	}
+	return 0;
+    }
+
     setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
     /* The Nokia cards are not really multiport cards */
     if (info->manfid == MANFID_NOKIA)
 	return 0;
     for (i = 0; i < info->multi-1; i++)
 	setup_serial(info, base2+(8*i), link->irq.AssignedIRQ);
-    
+
     return 0;
 }
 
@@ -487,7 +508,7 @@
     int i, last_ret, last_fn;
 
     DEBUG(0, "serial_config(0x%p)\n", link);
-    
+
     tuple.TupleData = (cisdata_t *)buf;
     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
     tuple.Attributes = 0;
@@ -500,7 +521,7 @@
     }
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
-    
+
     /* Configure card */
     link->state |= DEV_CONFIG;
 
@@ -508,8 +529,8 @@
     tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
     tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
     info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS);
-    
-    /* Is this a multiport card? */
+
+    /* Scan list of known multiport card ID's */
     tuple.DesiredTuple = CISTPL_MANFID;
     if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
 	info->manfid = le16_to_cpu(buf[0]);
@@ -537,15 +558,15 @@
 		info->multi = 2;
 	}
     }
-    
+
     if (info->multi > 1)
 	multi_config(link);
     else
 	simple_config(link);
-    
+
     if (info->ndev == 0)
 	goto failed;
-    
+
     if (info->manfid == MANFID_IBM) {
 	conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
 	CS_CHECK(AccessConfigurationRegister, link->handle, &reg);
@@ -562,6 +583,7 @@
     cs_error(link->handle, last_fn, last_ret);
 failed:
     serial_release((u_long)link);
+    link->state &= ~DEV_CONFIG_PENDING;
 
 } /* serial_config */
 
@@ -569,7 +591,7 @@
 
     After a card is removed, serial_release() will unregister the net
     device, and release the PCMCIA configuration.
-    
+
 ======================================================================*/
 
 void serial_release(u_long arg)
@@ -577,7 +599,7 @@
     dev_link_t *link = (dev_link_t *)arg;
     serial_info_t *info = link->priv;
     int i;
-    
+
     DEBUG(0, "serial_release(0x%p)\n", link);
 
     for (i = 0; i < info->ndev; i++) {
@@ -590,7 +612,7 @@
 	CardServices(ReleaseIO, link->handle, &link->io);
 	CardServices(ReleaseIRQ, link->handle, &link->irq);
     }
-    
+
     link->state &= ~DEV_CONFIG;
 
 } /* serial_release */
@@ -601,7 +623,7 @@
     stuff to run after an event is received.  A CARD_REMOVAL event
     also sets some flags to discourage the serial drivers from
     talking to the ports.
-    
+
 ======================================================================*/
 
 static int serial_event(event_t event, int priority,
@@ -609,9 +631,9 @@
 {
     dev_link_t *link = args->client_data;
     serial_info_t *info = link->priv;
-    
+
     DEBUG(1, "serial_event(0x%06x)\n", event);
-    
+
     switch (event) {
     case CS_EVENT_CARD_REMOVAL:
 	link->state &= ~DEV_PRESENT;
@@ -650,7 +672,7 @@
     if (serv.Revision != CS_RELEASE_CODE) {
 	printk(KERN_NOTICE "serial_cs: Card Services release "
 	       "does not match!\n");
-	return -1;
+	return -EINVAL;
     }
     register_pccard_driver(&dev_info, &serial_attach, &serial_detach);
     return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/scx200_gpio.c linux-2.4.21/drivers/char/scx200_gpio.c
--- linux-2.4.20/drivers/char/scx200_gpio.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/char/scx200_gpio.c	2002-12-18 18:58:11.000000000 +0000
@@ -0,0 +1,154 @@
+/* linux/drivers/char/scx200_gpio.c 
+
+   National Semiconductor SCx200 GPIO driver.  Allows a user space
+   process to play with the GPIO pins.
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include <linux/scx200_gpio.h>
+
+#define NAME "scx200_gpio"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 GPIO Pin Driver");
+MODULE_LICENSE("GPL");
+
+static int major = 0;		/* default to dynamic major */
+MODULE_PARM(major, "i");
+MODULE_PARM_DESC(major, "Major device number");
+
+static ssize_t scx200_gpio_write(struct file *file, const char *data, 
+				 size_t len, loff_t *ppos)
+{
+	unsigned m = minor(file->f_dentry->d_inode->i_rdev);
+	size_t i;
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	for (i = 0; i < len; ++i) {
+		char c;
+		if (get_user(c, data+i))
+			return -EFAULT;
+		switch (c)
+		{
+		case '0': 
+			scx200_gpio_set(m, 0); 
+			break;
+		case '1': 
+			scx200_gpio_set(m, 1); 
+			break;
+		case 'O':
+			printk(KERN_INFO NAME ": GPIO%d output enabled\n", m);
+			scx200_gpio_configure(m, ~1, 1);
+			break;
+		case 'o':
+			printk(KERN_INFO NAME ": GPIO%d output disabled\n", m);
+			scx200_gpio_configure(m, ~1, 0);
+			break;
+		case 'T':
+			printk(KERN_INFO NAME ": GPIO%d output is push pull\n", m);
+			scx200_gpio_configure(m, ~2, 2);
+			break;
+		case 't':
+			printk(KERN_INFO NAME ": GPIO%d output is open drain\n", m);
+			scx200_gpio_configure(m, ~2, 0);
+			break;
+		case 'P':
+			printk(KERN_INFO NAME ": GPIO%d pull up enabled\n", m);
+			scx200_gpio_configure(m, ~4, 4);
+			break;
+		case 'p':
+			printk(KERN_INFO NAME ": GPIO%d pull up disabled\n", m);
+			scx200_gpio_configure(m, ~4, 0);
+			break;
+		}
+	}
+
+	return len;
+}
+
+static ssize_t scx200_gpio_read(struct file *file, char *buf,
+				size_t len, loff_t *ppos)
+{
+	unsigned m = minor(file->f_dentry->d_inode->i_rdev);
+	int value;
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	value = scx200_gpio_get(m);
+	if (put_user(value ? '1' : '0', buf))
+		return -EFAULT;
+	
+	return 1;
+}
+
+static int scx200_gpio_open(struct inode *inode, struct file *file)
+{
+	unsigned m = minor(inode->i_rdev);
+	if (m > 63)
+		return -EINVAL;
+	return 0;
+}
+
+static int scx200_gpio_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+
+static struct file_operations scx200_gpio_fops = {
+	.owner   = THIS_MODULE,
+	.write   = scx200_gpio_write,
+	.read    = scx200_gpio_read,
+	.open    = scx200_gpio_open,
+	.release = scx200_gpio_release,
+};
+
+static int __init scx200_gpio_init(void)
+{
+	int r;
+
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 GPIO Driver\n");
+
+	if (!scx200_gpio_present()) {
+		printk(KERN_ERR NAME ": no SCx200 gpio pins available\n");
+		return -ENODEV;
+	}
+
+	r = register_chrdev(major, NAME, &scx200_gpio_fops);
+	if (r < 0) {
+		printk(KERN_ERR NAME ": unable to register character device\n");
+		return r;
+	}
+	if (!major) {
+		major = r;
+		printk(KERN_DEBUG NAME ": got dynamic major %d\n", major);
+	}
+
+	return 0;
+}
+
+static void __exit scx200_gpio_cleanup(void)
+{
+	unregister_chrdev(major, NAME);
+}
+
+module_init(scx200_gpio_init);
+module_exit(scx200_gpio_cleanup);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules"
+        c-basic-offset: 8
+    End:
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/scx200_wdt.c linux-2.4.21/drivers/char/scx200_wdt.c
--- linux-2.4.20/drivers/char/scx200_wdt.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/char/scx200_wdt.c	2002-12-18 18:58:06.000000000 +0000
@@ -0,0 +1,277 @@
+/* linux/drivers/char/scx200_wdt.c 
+
+   National Semiconductor SCx200 Watchdog support
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   Som code taken from:
+   National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver
+   (c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.com>
+
+   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.
+
+   The author(s) of this software shall not be held liable for damages
+   of any nature resulting due to the use of this software. This
+   software is provided AS-IS with no warranties. */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include <linux/scx200.h>
+
+#define NAME "scx200_wdt"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 Watchdog Driver");
+MODULE_LICENSE("GPL");
+
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+#define CONFIG_WATCHDOG_NOWAYOUT 0
+#endif
+
+static int margin = 60;		/* in seconds */
+MODULE_PARM(margin, "i");
+MODULE_PARM_DESC(margin, "Watchdog margin in seconds");
+
+static int nowayout = CONFIG_WATCHDOG_NOWAYOUT;
+MODULE_PARM(nowayout, "i");
+MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
+
+static u16 wdto_restart;
+static struct semaphore open_semaphore;
+static unsigned expect_close;
+
+/* Bits of the WDCNFG register */
+#define W_ENABLE 0x00fa		/* Enable watchdog */
+#define W_DISABLE 0x0000	/* Disable watchdog */
+
+/* The scaling factor for the timer, this depends on the value of W_ENABLE */
+#define W_SCALE (32768/1024)
+
+static void scx200_wdt_ping(void)
+{
+	outw(wdto_restart, SCx200_CB_BASE + SCx200_WDT_WDTO);
+}
+
+static void scx200_wdt_update_margin(void)
+{
+	printk(KERN_INFO NAME ": timer margin %d seconds\n", margin);
+	wdto_restart = margin * W_SCALE;
+}
+
+static void scx200_wdt_enable(void)
+{
+	printk(KERN_DEBUG NAME ": enabling watchdog timer, wdto_restart = %d\n", 
+	       wdto_restart);
+
+	outw(0, SCx200_CB_BASE + SCx200_WDT_WDTO);
+	outb(SCx200_WDT_WDSTS_WDOVF, SCx200_CB_BASE + SCx200_WDT_WDSTS);
+	outw(W_ENABLE, SCx200_CB_BASE + SCx200_WDT_WDCNFG);
+
+	scx200_wdt_ping();
+}
+
+static void scx200_wdt_disable(void)
+{
+	printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
+		
+	outw(0, SCx200_CB_BASE + SCx200_WDT_WDTO);
+	outb(SCx200_WDT_WDSTS_WDOVF, SCx200_CB_BASE + SCx200_WDT_WDSTS);
+	outw(W_DISABLE, SCx200_CB_BASE + SCx200_WDT_WDCNFG);
+}
+
+static int scx200_wdt_open(struct inode *inode, struct file *file)
+{
+        /* only allow one at a time */
+        if (down_trylock(&open_semaphore))
+                return -EBUSY;
+	scx200_wdt_enable();
+	expect_close = 0;
+
+	return 0;
+}
+
+static int scx200_wdt_release(struct inode *inode, struct file *file)
+{
+	if (!expect_close) {
+		printk(KERN_WARNING NAME ": watchdog device closed unexpectedly, will not disable the watchdog timer\n");
+	} else if (!nowayout) {
+		scx200_wdt_disable();
+	}
+        up(&open_semaphore);
+
+	return 0;
+}
+
+static int scx200_wdt_notify_sys(struct notifier_block *this, 
+				      unsigned long code, void *unused)
+{
+        if (code == SYS_HALT || code == SYS_POWER_OFF)
+		if (!nowayout)
+			scx200_wdt_disable();
+
+        return NOTIFY_DONE;
+}
+
+static struct notifier_block scx200_wdt_notifier =
+{
+        notifier_call: scx200_wdt_notify_sys
+};
+
+static ssize_t scx200_wdt_write(struct file *file, const char *data, 
+				     size_t len, loff_t *ppos)
+{
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	/* check for a magic close character */
+	if (len) 
+	{
+		size_t i;
+
+		scx200_wdt_ping();
+
+		expect_close = 0;
+		for (i = 0; i < len; ++i) {
+			char c;
+			if (get_user(c, data+i))
+				return -EFAULT;
+			if (c == 'V')
+				expect_close = 1;
+		}
+
+		return len;
+	}
+
+	return 0;
+}
+
+static int scx200_wdt_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	static struct watchdog_info ident = {
+		.identity = "NatSemi SCx200 Watchdog",
+		.firmware_version = 1, 
+		.options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING),
+	};
+	int new_margin;
+	
+	switch (cmd) {
+	default:
+		return -ENOTTY;
+	case WDIOC_GETSUPPORT:
+		if(copy_to_user((struct watchdog_info *)arg, &ident, 
+				sizeof(ident)))
+			return -EFAULT;
+		return 0;
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		if (put_user(0, (int *)arg))
+			return -EFAULT;
+		return 0;
+	case WDIOC_KEEPALIVE:
+		scx200_wdt_ping();
+		return 0;
+	case WDIOC_SETTIMEOUT:
+		if (get_user(new_margin, (int *)arg))
+			return -EFAULT;
+		if (new_margin < 1)
+			return -EINVAL;
+		margin = new_margin;
+		scx200_wdt_update_margin();
+		scx200_wdt_ping();
+	case WDIOC_GETTIMEOUT:
+		if (put_user(margin, (int *)arg))
+			return -EFAULT;
+		return 0;
+	}
+}
+
+static struct file_operations scx200_wdt_fops = {
+	.owner	 = THIS_MODULE,
+	.write   = scx200_wdt_write,
+	.ioctl   = scx200_wdt_ioctl,
+	.open    = scx200_wdt_open,
+	.release = scx200_wdt_release,
+};
+
+static struct miscdevice scx200_wdt_miscdev = {
+	.minor = WATCHDOG_MINOR,
+	.name  = NAME,
+	.fops  = &scx200_wdt_fops,
+};
+
+static int __init scx200_wdt_init(void)
+{
+	int r;
+
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 Watchdog Driver\n");
+
+	/* First check that this really is a NatSemi SCx200 CPU */
+	if ((pci_find_device(PCI_VENDOR_ID_NS, 
+			     PCI_DEVICE_ID_NS_SCx200_BRIDGE,
+			     NULL)) == NULL)
+		return -ENODEV;
+
+	/* More sanity checks, verify that the configuration block is there */
+	if (!scx200_cb_probe(SCx200_CB_BASE)) {
+		printk(KERN_WARNING NAME ": no configuration block found\n");
+		return -ENODEV;
+	}
+
+	if (!request_region(SCx200_CB_BASE + SCx200_WDT_OFFSET, 
+			    SCx200_WDT_SIZE, 
+			    "NatSemi SCx200 Watchdog")) {
+		printk(KERN_WARNING NAME ": watchdog I/O region busy\n");
+		return -EBUSY;
+	}
+
+	scx200_wdt_update_margin();
+	scx200_wdt_disable();
+
+	sema_init(&open_semaphore, 1);
+
+	r = misc_register(&scx200_wdt_miscdev);
+	if (r)
+		return r;
+
+	r = register_reboot_notifier(&scx200_wdt_notifier);
+        if (r) {
+                printk(KERN_ERR NAME ": unable to register reboot notifier");
+		misc_deregister(&scx200_wdt_miscdev);
+                return r;
+        }
+
+	return 0;
+}
+
+static void __exit scx200_wdt_cleanup(void)
+{
+        unregister_reboot_notifier(&scx200_wdt_notifier);
+	misc_deregister(&scx200_wdt_miscdev);
+	release_region(SCx200_CB_BASE + SCx200_WDT_OFFSET,
+		       SCx200_WDT_SIZE);
+}
+
+module_init(scx200_wdt_init);
+module_exit(scx200_wdt_cleanup);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules"
+        c-basic-offset: 8
+    End:
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/serial.c linux-2.4.21/drivers/char/serial.c
--- linux-2.4.20/drivers/char/serial.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/char/serial.c	2002-12-18 18:58:06.000000000 +0000
@@ -842,10 +842,15 @@
 		if (status & UART_LSR_DR)
 			receive_chars(info, &status, regs);
 		check_modem_status(info);
+#ifdef CONFIG_MELAN
 		if ((status & UART_LSR_THRE) ||
 			/* for buggy ELAN processors */
 			((iir & UART_IIR_ID) == UART_IIR_THRI))
 			transmit_chars(info, 0);
+#else
+		if (status & UART_LSR_THRE)
+			transmit_chars(info, 0);
+#endif
 
 	next:
 		info = info->next_port;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/sonypi.c linux-2.4.21/drivers/char/sonypi.c
--- linux-2.4.20/drivers/char/sonypi.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/drivers/char/sonypi.c	2002-12-18 18:58:04.000000000 +0000
@@ -1,7 +1,9 @@
-/* 
+/*
  * Sony Programmable I/O Control Device driver for VAIO
  *
- * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ * Copyright (C) 2001-2002 Stelian Pop <stelian@popies.net>
+ *
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
  *
  * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
  *
@@ -34,9 +36,13 @@
 #include <linux/pci.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/miscdevice.h>
 #include <linux/poll.h>
 #include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/acpi.h>
+
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
@@ -50,7 +56,7 @@
 static int fnkeyinit; /* = 0 */
 static int camera; /* = 0 */
 static int compat; /* = 0 */
-static int nojogdial; /* = 0 */
+static unsigned long mask = 0xffffffff;
 
 /* Inits the queue */
 static inline void sonypi_initq(void) {
@@ -110,29 +116,14 @@
         return result;
 }
 
-static void sonypi_ecrset(u8 addr, u8 value) {
-
-	wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3);
-	outb_p(0x81, SONYPI_CST_IOPORT);
-	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
-	outb_p(addr, SONYPI_DATA_IOPORT);
-	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
-	outb_p(value, SONYPI_DATA_IOPORT);
-	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
-}
-
-static u8 sonypi_ecrget(u8 addr) {
-
-	wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3);
-	outb_p(0x80, SONYPI_CST_IOPORT);
-	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
-	outb_p(addr, SONYPI_DATA_IOPORT);
-	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
-	return inb_p(SONYPI_DATA_IOPORT);
-}
-
-static u16 sonypi_ecrget16(u8 addr) {
-	return sonypi_ecrget(addr) | (sonypi_ecrget(addr + 1) << 8);
+static int ec_read16(u8 addr, u16 *value) {
+	u8 val_lb, val_hb;
+	if (ec_read(addr, &val_lb))
+		return -1;
+	if (ec_read(addr + 1, &val_hb))
+		return -1;
+	*value = val_lb | (val_hb << 8);
+	return 0;
 }
 
 /* Initializes the device - this comes from the AML code in the ACPI bios */
@@ -159,9 +150,12 @@
 }
 
 static void __devinit sonypi_type2_srs(void) {
-	sonypi_ecrset(SONYPI_SHIB, (sonypi_device.ioport1 & 0xFF00) >> 8);
-	sonypi_ecrset(SONYPI_SLOB,  sonypi_device.ioport1 & 0x00FF);
-	sonypi_ecrset(SONYPI_SIRQ,  sonypi_device.bits);
+	if (ec_write(SONYPI_SHIB, (sonypi_device.ioport1 & 0xFF00) >> 8))
+		printk(KERN_WARNING "ec_write failed\n");
+	if (ec_write(SONYPI_SLOB,  sonypi_device.ioport1 & 0x00FF))
+		printk(KERN_WARNING "ec_write failed\n");
+	if (ec_write(SONYPI_SIRQ,  sonypi_device.bits))
+		printk(KERN_WARNING "ec_write failed\n");
 	udelay(10);
 }
 
@@ -179,15 +173,18 @@
 }
 
 static void __devexit sonypi_type2_dis(void) {
-	sonypi_ecrset(SONYPI_SHIB, 0);
-	sonypi_ecrset(SONYPI_SLOB, 0);
-	sonypi_ecrset(SONYPI_SIRQ, 0);
+	if (ec_write(SONYPI_SHIB, 0))
+		printk(KERN_WARNING "ec_write failed\n");
+	if (ec_write(SONYPI_SLOB, 0))
+		printk(KERN_WARNING "ec_write failed\n");
+	if (ec_write(SONYPI_SIRQ, 0))
+		printk(KERN_WARNING "ec_write failed\n");
 }
 
 static u8 sonypi_call1(u8 dev) {
 	u8 v1, v2;
 
-	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 	outb(dev, sonypi_device.ioport2);
 	v1 = inb_p(sonypi_device.ioport2);
 	v2 = inb_p(sonypi_device.ioport1);
@@ -197,9 +194,9 @@
 static u8 sonypi_call2(u8 dev, u8 fn) {
 	u8 v1;
 
-	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 	outb(dev, sonypi_device.ioport2);
-	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 	outb(fn, sonypi_device.ioport1);
 	v1 = inb_p(sonypi_device.ioport1);
 	return v1;
@@ -208,11 +205,11 @@
 static u8 sonypi_call3(u8 dev, u8 fn, u8 v) {
 	u8 v1;
 
-	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 	outb(dev, sonypi_device.ioport2);
-	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 	outb(fn, sonypi_device.ioport1);
-	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 	outb(v, sonypi_device.ioport1);
 	v1 = inb_p(sonypi_device.ioport1);
 	return v1;
@@ -234,7 +231,7 @@
 /* Set brightness, hue etc */
 static void sonypi_set(u8 fn, u8 v) {
 	
-	wait_on_command(0, sonypi_call3(0x90, fn, v));
+	wait_on_command(0, sonypi_call3(0x90, fn, v), ITERATIONS_SHORT);
 }
 
 /* Tests if the camera is ready */
@@ -308,79 +305,30 @@
 /* Interrupt handler: some event is available */
 void sonypi_irq(int irq, void *dev_id, struct pt_regs *regs) {
 	u8 v1, v2, event = 0;
-	int i;
-	u8 sonypi_jogger_ev, sonypi_fnkey_ev;
-	u8 sonypi_capture_ev, sonypi_bluetooth_ev;
-	u8 sonypi_pkey_ev;
-
-	if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
-		sonypi_jogger_ev = SONYPI_TYPE2_JOGGER_EV;
-		sonypi_fnkey_ev = SONYPI_TYPE2_FNKEY_EV;
-		sonypi_capture_ev = SONYPI_TYPE2_CAPTURE_EV;
-		sonypi_bluetooth_ev = SONYPI_TYPE2_BLUETOOTH_EV;
-		sonypi_pkey_ev = nojogdial ? SONYPI_TYPE2_PKEY_EV 
-					   : SONYPI_TYPE1_PKEY_EV;
-	}
-	else {
-		sonypi_jogger_ev = SONYPI_TYPE1_JOGGER_EV;
-		sonypi_fnkey_ev = SONYPI_TYPE1_FNKEY_EV;
-		sonypi_capture_ev = SONYPI_TYPE1_CAPTURE_EV;
-		sonypi_bluetooth_ev = SONYPI_TYPE1_BLUETOOTH_EV;
-		sonypi_pkey_ev = SONYPI_TYPE1_PKEY_EV;
-	}
+	int i, j;
 
 	v1 = inb_p(sonypi_device.ioport1);
 	v2 = inb_p(sonypi_device.ioport2);
 
-	if ((v2 & sonypi_pkey_ev) == sonypi_pkey_ev) {
-		for (i = 0; sonypi_pkeyev[i].event; i++)
-			if (sonypi_pkeyev[i].data == v1) {
-				event = sonypi_pkeyev[i].event;
-				goto found;
-			}
-	}
-	if ((v2 & sonypi_jogger_ev) == sonypi_jogger_ev) {
-		for (i = 0; sonypi_joggerev[i].event; i++)
-			if (sonypi_joggerev[i].data == v1) {
-				event = sonypi_joggerev[i].event;
-				goto found;
-			}
-	}
-	if ((v2 & sonypi_capture_ev) == sonypi_capture_ev) {
-		for (i = 0; sonypi_captureev[i].event; i++)
-			if (sonypi_captureev[i].data == v1) {
-				event = sonypi_captureev[i].event;
-				goto found;
-			}
-	}
-	if ((v2 & sonypi_fnkey_ev) == sonypi_fnkey_ev) {
-		for (i = 0; sonypi_fnkeyev[i].event; i++)
-			if (sonypi_fnkeyev[i].data == v1) {
-				event = sonypi_fnkeyev[i].event;
-				goto found;
-			}
-	}
-	if ((v2 & sonypi_bluetooth_ev) == sonypi_bluetooth_ev) {
-		for (i = 0; sonypi_blueev[i].event; i++)
-			if (sonypi_blueev[i].data == v1) {
-				event = sonypi_blueev[i].event;
-				goto found;
-			}
-	}
-	if ((v2 & SONYPI_BACK_EV) == SONYPI_BACK_EV) {
-		for (i = 0; sonypi_backev[i].event; i++)
-			if (sonypi_backev[i].data == v1) {
-				event = sonypi_backev[i].event;
-				goto found;
-			}
-	}
-	if ((v2 & SONYPI_LID_EV) == SONYPI_LID_EV) {
-		for (i = 0; sonypi_lidev[i].event; i++)
-			if (sonypi_lidev[i].data == v1) {
-				event = sonypi_lidev[i].event;
+	if (verbose > 1)
+		printk(KERN_INFO 
+		       "sonypi: event port1=0x%02x,port2=0x%02x\n", v1, v2);
+
+	for (i = 0; sonypi_eventtypes[i].model; i++) {
+		if (sonypi_device.model != sonypi_eventtypes[i].model)
+			continue;
+		if ((v2 & sonypi_eventtypes[i].data) != sonypi_eventtypes[i].data)
+			continue;
+		if (! (mask & sonypi_eventtypes[i].mask))
+			continue;
+		for (j = 0; sonypi_eventtypes[i].events[j].event; j++) {
+			if (v1 == sonypi_eventtypes[i].events[j].data) {
+				event = sonypi_eventtypes[i].events[j].event;
 				goto found;
 			}
+		}
 	}
+
 	if (verbose)
 		printk(KERN_WARNING 
 		       "sonypi: unknown event port1=0x%02x,port2=0x%02x\n",v1,v2);
@@ -542,90 +490,140 @@
 	down(&sonypi_device.lock);
 	switch (cmd) {
 	case SONYPI_IOCGBRT:
-		val8 = sonypi_ecrget(0x96);
-		if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
-			ret = -EFAULT;
-			goto out;
+		if (ec_read(SONYPI_LCD_LIGHT, &val8)) {
+			ret = -EIO;
+			break;
 		}
+		if (copy_to_user((u8 *)arg, &val8, sizeof(val8)))
+			ret = -EFAULT;
 		break;
 	case SONYPI_IOCSBRT:
 		if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) {
 			ret = -EFAULT;
-			goto out;
+			break;
 		}
-		sonypi_ecrset(0x96, val8);
+		if (ec_write(SONYPI_LCD_LIGHT, val8))
+			ret = -EIO;
 		break;
 	case SONYPI_IOCGBAT1CAP:
-		val16 = sonypi_ecrget16(0xb2);
-		if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
-			ret = -EFAULT;
-			goto out;
+		if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
+			ret = -EIO;
+			break;
 		}
+		if (copy_to_user((u16 *)arg, &val16, sizeof(val16)))
+			ret = -EFAULT;
 		break;
 	case SONYPI_IOCGBAT1REM:
-		val16 = sonypi_ecrget16(0xa2);
-		if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
-			ret = -EFAULT;
-			goto out;
+		if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
+			ret = -EIO;
+			break;
 		}
+		if (copy_to_user((u16 *)arg, &val16, sizeof(val16)))
+			ret = -EFAULT;
 		break;
 	case SONYPI_IOCGBAT2CAP:
-		val16 = sonypi_ecrget16(0xba);
-		if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
-			ret = -EFAULT;
-			goto out;
+		if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
+			ret = -EIO;
+			break;
 		}
+		if (copy_to_user((u16 *)arg, &val16, sizeof(val16)))
+			ret = -EFAULT;
 		break;
 	case SONYPI_IOCGBAT2REM:
-		val16 = sonypi_ecrget16(0xaa);
-		if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
-			ret = -EFAULT;
-			goto out;
+		if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
+			ret = -EIO;
+			break;
 		}
+		if (copy_to_user((u16 *)arg, &val16, sizeof(val16)))
+			ret = -EFAULT;
 		break;
 	case SONYPI_IOCGBATFLAGS:
-		val8 = sonypi_ecrget(0x81) & 0x07;
-		if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
-			ret = -EFAULT;
-			goto out;
+		if (ec_read(SONYPI_BAT_FLAGS, &val8)) {
+			ret = -EIO;
+			break;
 		}
+		val8 &= 0x07;
+		if (copy_to_user((u8 *)arg, &val8, sizeof(val8)))
+			ret = -EFAULT;
 		break;
 	case SONYPI_IOCGBLUE:
 		val8 = sonypi_device.bluetooth_power;
-		if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
+		if (copy_to_user((u8 *)arg, &val8, sizeof(val8)))
 			ret = -EFAULT;
-			goto out;
-		}
 		break;
 	case SONYPI_IOCSBLUE:
 		if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) {
 			ret = -EFAULT;
-			goto out;
+			break;
 		}
 		sonypi_setbluetoothpower(val8);
 		break;
 	default:
 		ret = -EINVAL;
 	}
-out:
 	up(&sonypi_device.lock);
 	return ret;
 }
 
 static struct file_operations sonypi_misc_fops = {
-	owner:		THIS_MODULE,
-	read:		sonypi_misc_read,
-	poll:		sonypi_misc_poll,
-	open:		sonypi_misc_open,
-	release:	sonypi_misc_release,
-	fasync: 	sonypi_misc_fasync,
-	ioctl:		sonypi_misc_ioctl,
+	.owner		= THIS_MODULE,
+	.read		= sonypi_misc_read,
+	.poll		= sonypi_misc_poll,
+	.open		= sonypi_misc_open,
+	.release	= sonypi_misc_release,
+	.fasync		= sonypi_misc_fasync,
+	.ioctl		= sonypi_misc_ioctl,
 };
 
 struct miscdevice sonypi_misc_device = {
 	-1, "sonypi", &sonypi_misc_fops
 };
 
+#if CONFIG_PM
+static int sonypi_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) {
+	static int old_camera_power;
+
+	switch (rqst) {
+	case PM_SUSPEND:
+		sonypi_call2(0x81, 0); /* make sure we don't get any more events */
+		if (camera) {
+			old_camera_power = sonypi_device.camera_power;
+			sonypi_camera_off();
+		}
+		if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
+			sonypi_type2_dis();
+		else
+			sonypi_type1_dis();
+#if !defined(CONFIG_ACPI)
+		/* disable ACPI mode */
+		if (fnkeyinit)
+			outb(0xf1, 0xb2);
+#endif
+		break;
+	case PM_RESUME:
+#if !defined(CONFIG_ACPI)
+		/* Enable ACPI mode to get Fn key events */
+		if (fnkeyinit)
+			outb(0xf0, 0xb2);
+#endif
+		if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
+			sonypi_type2_srs();
+		else
+			sonypi_type1_srs();
+		sonypi_call1(0x82);
+		sonypi_call2(0x81, 0xff);
+		if (compat)
+			sonypi_call1(0x92); 
+		else
+			sonypi_call1(0x82);
+		if (camera && old_camera_power)
+			sonypi_camera_on();
+		break;
+	}
+	return 0;
+}
+#endif
+
 static int __devinit sonypi_probe(struct pci_dev *pcidev) {
 	int i, ret;
 	struct sonypi_ioport_list *ioport_list;
@@ -717,14 +715,14 @@
 	       SONYPI_DRIVER_MINORVERSION);
 	printk(KERN_INFO "sonypi: detected %s model, "
 	       "verbose = %s, fnkeyinit = %s, camera = %s, "
-	       "compat = %s, nojogdial = %s\n",
+	       "compat = %s, mask = 0x%08lx\n",
 	       (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) ?
 			"type1" : "type2",
 	       verbose ? "on" : "off",
 	       fnkeyinit ? "on" : "off",
 	       camera ? "on" : "off",
 	       compat ? "on" : "off",
-	       nojogdial ? "on" : "off");
+	       mask);
 	printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n",
 	       sonypi_device.irq, 
 	       sonypi_device.ioport1, sonypi_device.ioport2);
@@ -732,6 +730,10 @@
 		printk(KERN_INFO "sonypi: device allocated minor is %d\n",
 		       sonypi_misc_device.minor);
 
+#if CONFIG_PM
+	sonypi_device.pm = pm_register(PM_PCI_DEV, 0, sonypi_pm_callback);
+#endif
+
 	return 0;
 
 out3:
@@ -743,6 +745,11 @@
 }
 
 static void __devexit sonypi_remove(void) {
+
+#if CONFIG_PM
+	pm_unregister(sonypi_device.pm);
+#endif
+
 	sonypi_call2(0x81, 0); /* make sure we don't get any more events */
 	if (camera)
 		sonypi_camera_off();
@@ -800,7 +807,7 @@
 	compat = ints[5];
 	if (ints[0] == 5)
 		goto out;
-	nojogdial = ints[6];
+	mask = ints[6];
 out:
 	return 1;
 }
@@ -812,7 +819,7 @@
 module_init(sonypi_init_module);
 module_exit(sonypi_cleanup_module);
 
-MODULE_AUTHOR("Stelian Pop <stelian.pop@fr.alcove.com>");
+MODULE_AUTHOR("Stelian Pop <stelian@popies.net>");
 MODULE_DESCRIPTION("Sony Programmable I/O Control Device driver");
 MODULE_LICENSE("GPL");
 
@@ -827,7 +834,7 @@
 MODULE_PARM_DESC(camera, "set this if you have a MotionEye camera (PictureBook series)");
 MODULE_PARM(compat,"i");
 MODULE_PARM_DESC(compat, "set this if you want to enable backward compatibility mode");
-MODULE_PARM(nojogdial, "i");
-MODULE_PARM_DESC(nojogdial, "set this if you have a Vaio without a jogdial (like the fx series)");
+MODULE_PARM(mask, "i");
+MODULE_PARM_DESC(mask, "set this to the mask of event you want to enable (see doc)");
 
 EXPORT_SYMBOL(sonypi_camera_command);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/sonypi.h linux-2.4.21/drivers/char/sonypi.h
--- linux-2.4.20/drivers/char/sonypi.h	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/char/sonypi.h	2002-12-18 18:58:02.000000000 +0000
@@ -1,7 +1,9 @@
 /* 
  * Sony Programmable I/O Control Device driver for VAIO
  *
- * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ * Copyright (C) 2001-2002 Stelian Pop <stelian@popies.net>
+ *
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
  *
  * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
  *
@@ -35,10 +37,16 @@
 #ifdef __KERNEL__
 
 #define SONYPI_DRIVER_MAJORVERSION	 1
-#define SONYPI_DRIVER_MINORVERSION	13
+#define SONYPI_DRIVER_MINORVERSION	16
+
+#define SONYPI_DEVICE_MODEL_TYPE1	1
+#define SONYPI_DEVICE_MODEL_TYPE2	2
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/pci.h>
+#include <linux/pm.h>
+#include <linux/acpi.h>
 #include "linux/sonypi.h"
 
 /* type1 models use those */
@@ -54,6 +62,20 @@
 #define SONYPI_SHIB			0x9d
 #define SONYPI_TYPE2_REGION_SIZE	0x20
 
+/* battery / brightness addresses */
+#define SONYPI_BAT_FLAGS	0x81
+#define SONYPI_LCD_LIGHT	0x96
+#define SONYPI_BAT1_PCTRM	0xa0
+#define SONYPI_BAT1_LEFT	0xa2
+#define SONYPI_BAT1_MAXRT	0xa4
+#define SONYPI_BAT2_PCTRM	0xa8
+#define SONYPI_BAT2_LEFT	0xaa
+#define SONYPI_BAT2_MAXRT	0xac
+#define SONYPI_BAT1_MAXTK	0xb0
+#define SONYPI_BAT1_FULL	0xb2
+#define SONYPI_BAT2_MAXTK	0xb8
+#define SONYPI_BAT2_FULL	0xba
+
 /* ioports used for brightness and type2 events */
 #define SONYPI_DATA_IOPORT	0x62
 #define SONYPI_CST_IOPORT	0x66
@@ -131,34 +153,41 @@
 #define SONYPI_CAMERA_REVISION 			8
 #define SONYPI_CAMERA_ROMVERSION 		9
 
-/* key press event data (ioport2) */
-#define SONYPI_TYPE1_JOGGER_EV		0x10
-#define SONYPI_TYPE2_JOGGER_EV		0x08
-#define SONYPI_TYPE1_CAPTURE_EV		0x60
-#define SONYPI_TYPE2_CAPTURE_EV		0x08
-#define SONYPI_TYPE1_FNKEY_EV		0x20
-#define SONYPI_TYPE2_FNKEY_EV		0x08
-#define SONYPI_TYPE1_BLUETOOTH_EV	0x30
-#define SONYPI_TYPE2_BLUETOOTH_EV	0x08
-#define SONYPI_TYPE1_PKEY_EV		0x40
-#define SONYPI_TYPE2_PKEY_EV		0x08
-#define SONYPI_BACK_EV			0x08
-#define SONYPI_LID_EV			0x38
+/* Event masks */
+#define SONYPI_JOGGER_MASK			0x00000001
+#define SONYPI_CAPTURE_MASK			0x00000002
+#define SONYPI_FNKEY_MASK			0x00000004
+#define SONYPI_BLUETOOTH_MASK			0x00000008
+#define SONYPI_PKEY_MASK			0x00000010
+#define SONYPI_BACK_MASK			0x00000020
+#define SONYPI_HELP_MASK			0x00000040
+#define SONYPI_LID_MASK				0x00000080
+#define SONYPI_ZOOM_MASK			0x00000100
+#define SONYPI_THUMBPHRASE_MASK			0x00000200
+#define SONYPI_MEYE_MASK			0x00000400
+#define SONYPI_MEMORYSTICK_MASK			0x00000800
 
 struct sonypi_event {
 	u8	data;
 	u8	event;
 };
-
 /* The set of possible jogger events  */
 static struct sonypi_event sonypi_joggerev[] = {
 	{ 0x1f, SONYPI_EVENT_JOGDIAL_UP },
 	{ 0x01, SONYPI_EVENT_JOGDIAL_DOWN },
 	{ 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED },
 	{ 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED },
+	{ 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP },
+	{ 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN },
+	{ 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED },
+	{ 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED },
+	{ 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP },
+	{ 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN },
+	{ 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED },
+	{ 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED },
 	{ 0x40, SONYPI_EVENT_JOGDIAL_PRESSED },
 	{ 0x00, SONYPI_EVENT_JOGDIAL_RELEASED },
-	{ 0x00, 0x00 }
+	{ 0, 0 }
 };
 
 /* The set of possible capture button events */
@@ -167,7 +196,7 @@
 	{ 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
 	{ 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
 	{ 0x00, SONYPI_EVENT_CAPTURE_RELEASED },
-	{ 0x00, 0x00 }
+	{ 0, 0 }
 };
 
 /* The set of possible fnkeys events */
@@ -192,7 +221,8 @@
 	{ 0x33, SONYPI_EVENT_FNKEY_F },
 	{ 0x34, SONYPI_EVENT_FNKEY_S },
 	{ 0x35, SONYPI_EVENT_FNKEY_B },
-	{ 0x00, 0x00 }
+	{ 0x36, SONYPI_EVENT_FNKEY_ONLY },
+	{ 0, 0 }
 };
 
 /* The set of possible program key events */
@@ -200,7 +230,7 @@
 	{ 0x01, SONYPI_EVENT_PKEY_P1 },
 	{ 0x02, SONYPI_EVENT_PKEY_P2 },
 	{ 0x04, SONYPI_EVENT_PKEY_P3 },
-	{ 0x00, 0x00 }
+	{ 0, 0 }
 };
 
 /* The set of possible bluetooth events */
@@ -208,21 +238,82 @@
 	{ 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
 	{ 0x59, SONYPI_EVENT_BLUETOOTH_ON },
 	{ 0x5a, SONYPI_EVENT_BLUETOOTH_OFF },
-	{ 0x00, 0x00 }
+	{ 0, 0 }
 };
 
 /* The set of possible back button events */
 static struct sonypi_event sonypi_backev[] = {
 	{ 0x20, SONYPI_EVENT_BACK_PRESSED },
+	{ 0, 0 }
+};
+
+/* The set of possible help button events */
+static struct sonypi_event sonypi_helpev[] = {
 	{ 0x3b, SONYPI_EVENT_HELP_PRESSED },
-	{ 0x00, 0x00 }
+	{ 0, 0 }
 };
 
+
 /* The set of possible lid events */
 static struct sonypi_event sonypi_lidev[] = {
 	{ 0x51, SONYPI_EVENT_LID_CLOSED },
 	{ 0x50, SONYPI_EVENT_LID_OPENED },
-	{ 0x00, 0x00 }
+	{ 0, 0 }
+};
+
+/* The set of possible zoom events */
+static struct sonypi_event sonypi_zoomev[] = {
+	{ 0x39, SONYPI_EVENT_ZOOM_PRESSED },
+	{ 0, 0 }
+};
+
+/* The set of possible thumbphrase events */
+static struct sonypi_event sonypi_thumbphraseev[] = {
+	{ 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED },
+	{ 0, 0 }
+};
+
+/* The set of possible motioneye camera events */
+static struct sonypi_event sonypi_meyeev[] = {
+	{ 0x00, SONYPI_EVENT_MEYE_FACE },
+	{ 0x01, SONYPI_EVENT_MEYE_OPPOSITE },
+	{ 0, 0 }
+};
+
+/* The set of possible memorystick events */
+static struct sonypi_event sonypi_memorystickev[] = {
+	{ 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT },
+	{ 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT },
+	{ 0, 0 }
+};
+
+struct sonypi_eventtypes {
+	int			model;
+	u8			data;
+	unsigned long		mask;
+	struct sonypi_event *	events;
+} sonypi_eventtypes[] = {
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
+
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_JOGGER_MASK, sonypi_joggerev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_CAPTURE_MASK, sonypi_captureev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_BACK_MASK, sonypi_backev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_HELP_MASK, sonypi_helpev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_ZOOM_MASK, sonypi_zoomev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+
+	{ 0, 0, 0, 0 }
 };
 
 #define SONYPI_BUF_SIZE	128
@@ -236,9 +327,6 @@
 	unsigned char buf[SONYPI_BUF_SIZE];
 };
 
-#define SONYPI_DEVICE_MODEL_TYPE1	1
-#define SONYPI_DEVICE_MODEL_TYPE2	2
-
 struct sonypi_device {
 	struct pci_dev *dev;
 	u16 irq;
@@ -252,14 +340,43 @@
 	struct sonypi_queue queue;
 	int open_count;
 	int model;
+#if CONFIG_PM
+	struct pm_dev *pm;
+#endif
 };
 
-#define wait_on_command(quiet, command) { \
-	unsigned int n = 10000; \
+#define ITERATIONS_LONG		10000
+#define ITERATIONS_SHORT	10
+
+#define wait_on_command(quiet, command, iterations) { \
+	unsigned int n = iterations; \
 	while (--n && (command)) \
 		udelay(1); \
 	if (!n && (verbose || !quiet)) \
-		printk(KERN_WARNING "sonypi command failed at " __FILE__ " : %s (line %d)\n", __FUNCTION__, __LINE__); \
+		printk(KERN_WARNING "sonypi command failed at %s : %s (line %d)\n", __FILE__, __FUNCTION__, __LINE__); \
+}
+
+extern int verbose;
+
+static inline int ec_write(u8 addr, u8 value) {
+	wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG);
+	outb_p(0x81, SONYPI_CST_IOPORT);
+	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
+	outb_p(addr, SONYPI_DATA_IOPORT);
+	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
+	outb_p(value, SONYPI_DATA_IOPORT);
+	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
+	return 0;
+}
+
+static inline int ec_read(u8 addr, u8 *value) {
+	wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG);
+	outb_p(0x80, SONYPI_CST_IOPORT);
+	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
+	outb_p(addr, SONYPI_DATA_IOPORT);
+	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
+	*value = inb_p(SONYPI_DATA_IOPORT);
+	return 0;
 }
 
 #endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/tipar.c linux-2.4.21/drivers/char/tipar.c
--- linux-2.4.20/drivers/char/tipar.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/char/tipar.c	2002-12-18 18:58:06.000000000 +0000
@@ -0,0 +1,538 @@
+/* Hey EMACS -*- linux-c -*-
+ *
+ * tipar - low level driver for handling a parallel link cable designed
+ * for Texas Instruments graphing calculators (http://lpg.ticalc.org).
+ *
+ * Copyright (C) 2000-2002, Romain Lievin <roms@lpg.ticalc.org>
+ * under the terms of the GNU General Public License.
+ *
+ * Various fixes & clean-up from the Linux Kernel Mailing List
+ * (Alan Cox, Richard B. Johnson, Christoph Hellwig).
+ */
+
+/* This driver should, in theory, work with any parallel port that has an
+ * appropriate low-level driver; all I/O is done through the parport
+ * abstraction layer.
+ *
+ * If this driver is built into the kernel, you can configure it using the
+ * kernel command-line.  For example:
+ *
+ *      tipar=timeout,delay       (set timeout and delay)
+ *
+ * If the driver is loaded as a module, similar functionality is available
+ * using module parameters.  The equivalent of the above commands would be:
+ *
+ *      # insmod tipar timeout=15 delay=10
+ */
+
+/* COMPATIBILITY WITH OLD KERNELS
+ *
+ * Usually, parallel cables were bound to ports at
+ * particular I/O addresses, as follows:
+ *
+ *      tipar0             0x378
+ *      tipar1             0x278
+ *      tipar2             0x3bc
+ *
+ *
+ * This driver, by default, binds tipar devices according to parport and
+ * the minor number.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <linux/devfs_fs_kernel.h>	/* DevFs support */
+#include <linux/parport.h>	/* Our code depend on parport */
+
+/*
+ * TI definitions
+ */
+#include <linux/ticable.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "1.18"
+#define DRIVER_AUTHOR  "Romain Lievin <roms@lpg.ticalc.org>"
+#define DRIVER_DESC    "Device driver for TI/PC parallel link cables"
+#define DRIVER_LICENSE "GPL"
+
+#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
+#if LINUX_VERSION_CODE < VERSION(2,5,0)
+# define minor(x) MINOR(x)
+# define need_resched() (current->need_resched)
+#endif
+
+/* ----- global variables --------------------------------------------- */
+
+struct tipar_struct {
+	struct pardevice *dev;	/* Parport device entry */
+};
+
+#define PP_NO 3
+static struct tipar_struct table[PP_NO];
+
+static int delay = IO_DELAY;	/* inter-bit delay in microseconds */
+static int timeout = TIMAXTIME;	/* timeout in tenth of seconds     */
+
+static devfs_handle_t devfs_handle;
+static unsigned int tp_count;	/* tipar count */
+static unsigned long opened;	/* opened devices */
+
+/* --- macros for parport access -------------------------------------- */
+
+#define r_dtr(x)        (parport_read_data(table[(x)].dev->port))
+#define r_str(x)        (parport_read_status(table[(x)].dev->port))
+#define w_ctr(x,y)      (parport_write_control(table[(x)].dev->port, (y)))
+#define w_dtr(x,y)      (parport_write_data(table[(x)].dev->port, (y)))
+
+/* --- setting states on the D-bus with the right timing: ------------- */
+
+static inline void
+outbyte(int value, int minor)
+{
+	w_dtr(minor, value);
+}
+
+static inline int
+inbyte(int minor)
+{
+	return (r_str(minor));
+}
+
+static inline void
+init_ti_parallel(int minor)
+{
+	outbyte(3, minor);
+}
+
+/* ----- global defines ----------------------------------------------- */
+
+#define START(x) { x=jiffies+HZ/(timeout/10); }
+#define WAIT(x)  { \
+  if (time_before((x), jiffies)) return -1; \
+  if (need_resched()) schedule(); }
+
+/* ----- D-bus bit-banging functions ---------------------------------- */
+
+/* D-bus protocol (45kbit/s max):
+                    1                 0                      0
+       _______        ______|______    __________|________    __________
+Red  :        ________      |      ____          |        ____
+       _        ____________|________      ______|__________       _____
+White:  ________            |        ______      |          _______
+*/
+
+/* Try to transmit a byte on the specified port (-1 if error). */
+static int
+put_ti_parallel(int minor, unsigned char data)
+{
+	int bit;
+	unsigned long max;
+
+	for (bit = 0; bit < 8; bit++) {
+		if (data & 1) {
+			outbyte(2, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (inbyte(minor) & 0x10);
+
+			outbyte(3, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (!(inbyte(minor) & 0x10));
+		} else {
+			outbyte(1, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (inbyte(minor) & 0x20);
+
+			outbyte(3, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (!(inbyte(minor) & 0x20));
+		}
+
+		data >>= 1;
+		udelay(delay);
+
+		if (need_resched())
+			schedule();
+	}
+
+	return 0;
+}
+
+/* Receive a byte on the specified port or -1 if error. */
+static int
+get_ti_parallel(int minor)
+{
+	int bit;
+	unsigned char v, data = 0;
+	unsigned long max;
+
+	for (bit = 0; bit < 8; bit++) {
+		START(max);
+		do {
+			WAIT(max);
+		} while ((v = inbyte(minor) & 0x30) == 0x30);
+
+		if (v == 0x10) {
+			data = (data >> 1) | 0x80;
+			outbyte(1, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (!(inbyte(minor) & 0x20));
+			outbyte(3, minor);
+		} else {
+			data = data >> 1;
+			outbyte(2, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (!(inbyte(minor) & 0x10));
+			outbyte(3, minor);
+		}
+
+		udelay(delay);
+		if (need_resched())
+			schedule();
+	}
+
+	return (int) data;
+}
+
+/* Try to detect a parallel link cable on the specified port */
+static int
+probe_ti_parallel(int minor)
+{
+	int i;
+	int seq[] = { 0x00, 0x20, 0x10, 0x30 };
+
+	for (i = 3; i >= 0; i--) {
+		outbyte(3, minor);
+		outbyte(i, minor);
+		udelay(delay);
+		/*printk(KERN_DEBUG "Probing -> %i: 0x%02x 0x%02x\n", i, data & 0x30, seq[i]); */
+		if ((inbyte(minor) & 0x30) != seq[i]) {
+			outbyte(3, minor);
+			return -1;
+		}
+	}
+
+	outbyte(3, minor);
+	return 0;
+}
+
+/* ----- kernel module functions--------------------------------------- */
+
+static int
+tipar_open(struct inode *inode, struct file *file)
+{
+	unsigned int minor = minor(inode->i_rdev) - TIPAR_MINOR;
+
+	if (minor > tp_count - 1)
+		return -ENXIO;
+
+	if (test_and_set_bit(minor, &opened))
+		return -EBUSY;
+
+	parport_claim_or_block(table[minor].dev);
+	init_ti_parallel(minor);
+	parport_release(table[minor].dev);
+
+	return 0;
+}
+
+static int
+tipar_close(struct inode *inode, struct file *file)
+{
+	unsigned int minor = minor(inode->i_rdev) - TIPAR_MINOR;
+
+	if (minor > tp_count - 1)
+		return -ENXIO;
+
+	clear_bit(minor, &opened);
+
+	return 0;
+}
+
+static ssize_t
+tipar_write(struct file *file, const char *buf, size_t count, loff_t * ppos)
+{
+	unsigned int minor =
+	    minor(file->f_dentry->d_inode->i_rdev) - TIPAR_MINOR;
+	ssize_t n;
+
+	parport_claim_or_block(table[minor].dev);
+
+	for (n = 0; n < count; n++) {
+		unsigned char b;
+
+		if (get_user(b, buf + n)) {
+			n = -EFAULT;
+			goto out;
+		}
+
+		if (put_ti_parallel(minor, b) == -1) {
+			init_ti_parallel(minor);
+			n = -ETIMEDOUT;
+			goto out;
+		}
+	}
+      out:
+	parport_release(table[minor].dev);
+	return n;
+}
+
+static ssize_t
+tipar_read(struct file *file, char *buf, size_t count, loff_t * ppos)
+{
+	int b = 0;
+	unsigned int minor =
+	    minor(file->f_dentry->d_inode->i_rdev) - TIPAR_MINOR;
+	ssize_t retval = 0;
+	ssize_t n = 0;
+
+	if (count == 0)
+		return 0;
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	parport_claim_or_block(table[minor].dev);
+
+	while (n < count) {
+		b = get_ti_parallel(minor);
+		if (b == -1) {
+			init_ti_parallel(minor);
+			retval = -ETIMEDOUT;
+			goto out;
+		} else {
+			if (put_user(b, ((unsigned char *) buf) + n)) {
+				retval = -EFAULT;
+				break;
+			} else
+				retval = ++n;
+		}
+
+		/* Non-blocking mode : try again ! */
+		if (file->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
+			goto out;
+		}
+
+		/* Signal pending, try again ! */
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			goto out;
+		}
+
+		if (need_resched())
+			schedule();
+	}
+
+      out:
+	parport_release(table[minor].dev);
+	return retval;
+}
+
+static int
+tipar_ioctl(struct inode *inode, struct file *file,
+	    unsigned int cmd, unsigned long arg)
+{
+	int retval = 0;
+
+	switch (cmd) {
+	case IOCTL_TIPAR_DELAY:
+	  delay = (int)arg;    //get_user(delay, &arg);
+	  break;
+	case IOCTL_TIPAR_TIMEOUT:
+	  timeout = (int)arg;  //get_user(timeout, &arg);
+	  break;
+	default:
+		retval = -ENOTTY;
+		break;
+	}
+
+	return retval;
+}
+
+/* ----- kernel module registering ------------------------------------ */
+
+static struct file_operations tipar_fops = {
+	owner:THIS_MODULE,
+	llseek:no_llseek,
+	read:tipar_read,
+	write:tipar_write,
+	ioctl:tipar_ioctl,
+	open:tipar_open,
+	release:tipar_close,
+};
+
+/* --- initialisation code ------------------------------------- */
+
+#ifndef MODULE
+/*      You must set these - there is no sane way to probe for this cable.
+ *      You can use 'tipar=timeout,delay' to set these now. */
+static int __init
+tipar_setup(char *str)
+{
+	int ints[2];
+
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+
+	if (ints[0] > 0) {
+		timeout = ints[1];
+		if (ints[0] > 1) {
+			delay = ints[2];
+		}
+	}
+
+	return 1;
+}
+#endif
+
+/*
+ * Register our module into parport.
+ * Pass also 2 callbacks functions to parport: a pre-emptive function and an
+ * interrupt handler function (unused).
+ * Display a message such "tipar0: using parport0 (polling)".
+ */
+static int
+tipar_register(int nr, struct parport *port)
+{
+	char name[8];
+
+	/* Register our module into parport */
+	table[nr].dev = parport_register_device(port, "tipar",
+						NULL, NULL, NULL, 0,
+						(void *) &table[nr]);
+
+	if (table[nr].dev == NULL)
+		return 1;
+
+	/* Use devfs, tree: /dev/ticables/par/[0..2] */
+	sprintf(name, "%d", nr);
+	printk
+	    ("tipar: registering to devfs : major = %d, minor = %d, node = %s\n",
+	     TISER_MAJOR, (TIPAR_MINOR + nr), name);
+	devfs_register(devfs_handle, name, DEVFS_FL_DEFAULT, TIPAR_MAJOR,
+		       TIPAR_MINOR + nr, S_IFCHR | S_IRUGO | S_IWUGO,
+		       &tipar_fops, NULL);
+
+	/* Display informations */
+	printk(KERN_INFO "tipar%d: using %s (%s).\n", nr, port->name,
+	       (port->irq ==
+		PARPORT_IRQ_NONE) ? "polling" : "interrupt-driven");
+
+	if (probe_ti_parallel(nr) != -1)
+		printk("tipar%d: link cable found !\n", nr);
+	else
+		printk("tipar%d: link cable not found.\n", nr);
+
+	return 0;
+}
+
+static void
+tipar_attach(struct parport *port)
+{
+	if (tp_count == PP_NO) {
+		printk("tipar: ignoring parallel port (max. %d)\n", PP_NO);
+		return;
+	}
+
+	if (!tipar_register(tp_count, port))
+		tp_count++;
+}
+
+static void
+tipar_detach(struct parport *port)
+{
+	/* Nothing to do */
+}
+
+static struct parport_driver tipar_driver = {
+	"tipar",
+	tipar_attach,
+	tipar_detach,
+	NULL
+};
+
+int __init
+tipar_init_module(void)
+{
+	printk("tipar: parallel link cable driver, version %s\n",
+	       DRIVER_VERSION);
+
+	if (devfs_register_chrdev(TIPAR_MAJOR, "tipar", &tipar_fops)) {
+		printk("tipar: unable to get major %d\n", TIPAR_MAJOR);
+		return -EIO;
+	}
+
+	/* Use devfs with tree: /dev/ticables/par/[0..2] */
+	devfs_handle = devfs_mk_dir(NULL, "ticables/par", NULL);
+
+	if (parport_register_driver(&tipar_driver)) {
+		printk("tipar: unable to register with parport\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+void __exit
+tipar_cleanup_module(void)
+{
+	unsigned int i;
+
+	/* Unregistering module */
+	parport_unregister_driver(&tipar_driver);
+
+	devfs_unregister(devfs_handle);
+	devfs_unregister_chrdev(TIPAR_MAJOR, "tipar");
+
+	for (i = 0; i < PP_NO; i++) {
+		if (table[i].dev == NULL)
+			continue;
+		parport_unregister_device(table[i].dev);
+	}
+
+	printk("tipar: module unloaded !\n");
+}
+
+/* --------------------------------------------------------------------- */
+
+__setup("tipar=", tipar_setup);
+module_init(tipar_init_module);
+module_exit(tipar_cleanup_module);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_PARM(timeout, "i");
+MODULE_PARM_DESC(timeout, "Timeout (default=1.5 seconds)");
+MODULE_PARM(delay, "i");
+MODULE_PARM_DESC(delay, "Inter-bit delay (default=10 microseconds)");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/wdt285.c linux-2.4.21/drivers/char/wdt285.c
--- linux-2.4.20/drivers/char/wdt285.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21/drivers/char/wdt285.c	2002-12-18 18:58:04.000000000 +0000
@@ -179,10 +179,15 @@
 
 static int __init footbridge_watchdog_init(void)
 {
+	int retval;
+
 	if (machine_is_netwinder())
 		return -ENODEV;
 
-	misc_register(&watchdog_miscdev);
+	retval = misc_register(&watchdog_miscdev);
+	if(retval < 0)
+		return retval;
+
 	printk("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n", 
 	       soft_margin);
 	if (machine_is_cats())
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/gsc/dino.c linux-2.4.21/drivers/gsc/dino.c
--- linux-2.4.20/drivers/gsc/dino.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/gsc/dino.c	2002-12-18 18:58:12.000000000 +0000
@@ -436,7 +436,7 @@
 	if (mask) {
 		if (--ilr_loop > 0)
 			goto ilr_again;
-		printk("Dino %lx: stuck interrupt %d\n", dino_dev->hba.base_addr, mask);
+		printk("Dino %lx: IRQ base %d, stuck IRQ lines? 0x%x\n", dino_dev->hba.base_addr, dino_dev->dino_region->data.irqbase, mask);
 	}
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/gsc/lasi.c linux-2.4.21/drivers/gsc/lasi.c
--- linux-2.4.20/drivers/gsc/lasi.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/gsc/lasi.c	2002-12-18 18:58:06.000000000 +0000
@@ -26,7 +26,7 @@
 #include <asm/gsc.h>
 #include <asm/hardware.h>
 #include <asm/led.h>
-
+#include <asm/pdc.h>
 #include "busdevice.h"
 
 
@@ -77,7 +77,10 @@
 
 	/* Resets */
 	/* gsc_writel(0xFFFFFFFF, lasi_base+0x2000);*/	/* Parallel */
-	gsc_writel(0xFFFFFFFF, lasi_base+0x4004);	/* Audio */
+
+	if(pdc_add_valid(lasi_base+0x4004) == PDC_OK)
+		gsc_writel(0xFFFFFFFF, lasi_base+0x4004);	/* Audio */
+
 	/* gsc_writel(0xFFFFFFFF, lasi_base+0x5000);*/	/* Serial */ 
 	/* gsc_writel(0xFFFFFFFF, lasi_base+0x6000);*/	/* SCSI */
 	gsc_writel(0xFFFFFFFF, lasi_base+0x7000);	/* LAN */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hil/hil_kbd.c linux-2.4.21/drivers/hil/hil_kbd.c
--- linux-2.4.20/drivers/hil/hil_kbd.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/hil/hil_kbd.c	2002-12-18 18:58:01.000000000 +0000
@@ -431,9 +431,9 @@
 
 
 struct serio_dev hil_kbd_serio_dev = {
-	connect:	hil_kbd_connect,
-	disconnect:	hil_kbd_disconnect,
-	interrupt:	hil_kbd_interrupt
+	.connect =	hil_kbd_connect,
+	.disconnect =	hil_kbd_disconnect,
+	.interrupt =	hil_kbd_interrupt
 };
 
 static int __init hil_kbd_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hil/hil_ptr.c linux-2.4.21/drivers/hil/hil_ptr.c
--- linux-2.4.20/drivers/hil/hil_ptr.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/hil/hil_ptr.c	2002-12-18 18:58:11.000000000 +0000
@@ -386,9 +386,9 @@
 
 
 struct serio_dev hil_ptr_serio_dev = {
-	connect: hil_ptr_connect,
-	disconnect: hil_ptr_disconnect,
-	interrupt: hil_ptr_interrupt
+	.connect =	hil_ptr_connect,
+	.disconnect =	hil_ptr_disconnect,
+	.interrupt =	hil_ptr_interrupt
 };
 
 static int __init hil_ptr_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hil/hilkbd.c linux-2.4.21/drivers/hil/hilkbd.c
--- linux-2.4.20/drivers/hil/hilkbd.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/hil/hilkbd.c	2002-12-18 18:58:10.000000000 +0000
@@ -348,9 +348,9 @@
 MODULE_DEVICE_TABLE(parisc, hil_tbl);
 
 static struct parisc_driver hil_driver = {
-	name:		"HIL",
-	id_table:	hil_tbl,
-	probe:		hil_init_chip,
+	.name =		"HIL",
+	.id_table =	hil_tbl,
+	.probe =	hil_init_chip,
 };
 #endif /* CONFIG_PARISC */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hil/hp_sdc.c linux-2.4.21/drivers/hil/hp_sdc.c
--- linux-2.4.20/drivers/hil/hp_sdc.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/hil/hp_sdc.c	2002-12-18 18:58:05.000000000 +0000
@@ -745,10 +745,10 @@
 
 static struct parisc_device_id hp_sdc_tbl[] = {
 	{
-		hw_type:	HPHW_FIO, 
-		hversion_rev:	HVERSION_REV_ANY_ID,
-		hversion:	HVERSION_ANY_ID,
-		sversion:	0x73, 
+		.hw_type =	HPHW_FIO, 
+		.hversion_rev =	HVERSION_REV_ANY_ID,
+		.hversion =	HVERSION_ANY_ID,
+		.sversion =	0x73, 
 	 },
 	{ 0, }
 };
@@ -758,9 +758,9 @@
 static int __init hp_sdc_init(struct parisc_device *d);
 
 static struct parisc_driver hp_sdc_driver = {
-	name:		"HP SDC",
-	id_table:	hp_sdc_tbl,
-	probe:		hp_sdc_init,
+	.name =		"HP SDC",
+	.id_table =	hp_sdc_tbl,
+	.probe =	hp_sdc_init,
 };
 
 static int __init hp_sdc_init(struct parisc_device *d)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hil/hp_sdc_rtc.c linux-2.4.21/drivers/hil/hp_sdc_rtc.c
--- linux-2.4.20/drivers/hil/hp_sdc_rtc.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/hil/hp_sdc_rtc.c	2002-12-18 18:58:09.000000000 +0000
@@ -674,20 +674,20 @@
 }
 
 static struct file_operations hp_sdc_rtc_fops = {
-        owner:          THIS_MODULE,
-        llseek:         hp_sdc_rtc_llseek,
-        read:           hp_sdc_rtc_read,
-        poll:           hp_sdc_rtc_poll,
-        ioctl:          hp_sdc_rtc_ioctl,
-        open:           hp_sdc_rtc_open,
-        release:        hp_sdc_rtc_release,
-        fasync:         hp_sdc_rtc_fasync,
+        .owner =	THIS_MODULE,
+        .llseek =	hp_sdc_rtc_llseek,
+        .read =		hp_sdc_rtc_read,
+        .poll =		hp_sdc_rtc_poll,
+        .ioctl =	hp_sdc_rtc_ioctl,
+        .open =		hp_sdc_rtc_open,
+        .release =	hp_sdc_rtc_release,
+        .fasync =	hp_sdc_rtc_fasync,
 };
 
 static struct miscdevice hp_sdc_rtc_dev = {
-        minor:		RTC_MINOR,
-        name:		"rtc",
-        fops:		&hp_sdc_rtc_fops
+        .minor =	RTC_MINOR,
+        .name =		"rtc",
+        .fops =		&hp_sdc_rtc_fops
 };
 
 static int __init hp_sdc_rtc_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/Makefile linux-2.4.21/drivers/hotplug/Makefile
--- linux-2.4.20/drivers/hotplug/Makefile	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/hotplug/Makefile	2002-12-18 18:58:04.000000000 +0000
@@ -29,9 +29,6 @@
 
 ifdef CONFIG_HOTPLUG_PCI_ACPI
   EXTRA_CFLAGS	+= -D_LINUX -I$(CURDIR)/../acpi
-  ifdef CONFIG_ACPI_DEBUG
-    EXTRA_CFLAGS += -DACPI_DEBUG -Wno-unused
-  endif
 endif
 
 acpiphp_objs		:=	acpiphp_core.o	\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/acpiphp.h linux-2.4.21/drivers/hotplug/acpiphp.h
--- linux-2.4.20/drivers/hotplug/acpiphp.h	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/hotplug/acpiphp.h	2002-12-18 18:58:01.000000000 +0000
@@ -97,17 +97,17 @@
 
 #define dbg(format, arg...)					\
 	do {							\
-		if (debug)					\
-			printk (KERN_DEBUG "%s: " format "\n",	\
+		if (acpiphp_debug)				\
+			printk(KERN_DEBUG "%s: " format,	\
 				MY_NAME , ## arg); 		\
 	} while (0)
-#define err(format, arg...) printk (KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
-#define info(format, arg...) printk (KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
-#define warn(format, arg...) printk (KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
+#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
 
 #define SLOT_MAGIC	0x67267322
 /* name size which is used for entries in pcihpfs */
-#define SLOT_NAME_SIZE	16		/* ACPIxxxx */
+#define SLOT_NAME_SIZE	32		/* ACPI{_SUN}-{BUS}:{DEV} */
 
 struct acpiphp_bridge;
 struct acpiphp_slot;
@@ -122,8 +122,6 @@
 	struct hotplug_slot	*hotplug_slot;
 	struct list_head	slot_list;
 
-	/* if there are multiple corresponding ACPI slot objects,
-	   this points to one of them */
 	struct acpiphp_slot	*acpi_slot;
 };
 
@@ -175,8 +173,6 @@
 	/* PCI-to-PCI bridge device */
 	struct pci_dev *pci_dev;
 
-	struct pci_ops *pci_ops;
-
 	/* ACPI 2.0 _HPP parameters */
 	struct hpp_param hpp;
 
@@ -200,7 +196,6 @@
 	struct acpiphp_bridge *bridge;	/* parent */
 	struct list_head funcs;		/* one slot may have different
 					   objects (i.e. for each function) */
-	struct acpiphp_func *func;	/* functions */
 	struct semaphore crit_sect;
 
 	u32		id;		/* slot id (serial #) for hotplug core */
@@ -213,7 +208,7 @@
 
 
 /**
- * struct acpiphp_func - PCI slot information
+ * struct acpiphp_func - PCI function information
  *
  * PCI function information for each object in ACPI namespace
  * typically 8 objects per slot (i.e. for each PCI function)
@@ -319,4 +314,7 @@
 extern void acpiphp_dump_resource (struct acpiphp_bridge *bridge); /* debug */
 extern void acpiphp_dump_func_resource (struct acpiphp_func *func); /* debug */
 
+/* variables */
+extern int acpiphp_debug;
+
 #endif /* _ACPIPHP_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/acpiphp_core.c linux-2.4.21/drivers/hotplug/acpiphp_core.c
--- linux-2.4.20/drivers/hotplug/acpiphp_core.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/hotplug/acpiphp_core.c	2002-12-18 18:58:06.000000000 +0000
@@ -50,12 +50,14 @@
 	#define MY_NAME	THIS_MODULE->name
 #endif
 
+static int debug;
+int acpiphp_debug;
+
 /* local variables */
-static int debug = 1;			/* XXX set to 0 after debug */
 static int num_slots;
 
-#define DRIVER_VERSION	"0.3"
-#define DRIVER_AUTHOR	"Greg Kroah-Hartman <gregkh@us.ibm.com>"
+#define DRIVER_VERSION	"0.4"
+#define DRIVER_AUTHOR	"Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kouchi@cq.jp.nec.com>"
 #define DRIVER_DESC	"ACPI Hot Plug PCI Controller Driver"
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
@@ -72,17 +74,21 @@
 static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
 static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
 static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
+static int get_max_bus_speed	(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value);
+static int get_cur_bus_speed	(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value);
 
 static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
-	owner:			THIS_MODULE,
-	enable_slot:		enable_slot,
-	disable_slot:		disable_slot,
-	set_attention_status:	set_attention_status,
-	hardware_test:		hardware_test,
-	get_power_status:	get_power_status,
-	get_attention_status:	get_attention_status,
-	get_latch_status:	get_latch_status,
-	get_adapter_status:	get_adapter_status,
+	.owner			= THIS_MODULE,
+	.enable_slot		= enable_slot,
+	.disable_slot		= disable_slot,
+	.set_attention_status	= set_attention_status,
+	.hardware_test		= hardware_test,
+	.get_power_status	= get_power_status,
+	.get_attention_status	= get_attention_status,
+	.get_latch_status	= get_latch_status,
+	.get_adapter_status	= get_adapter_status,
+	.get_max_bus_speed	= get_max_bus_speed,
+	.get_cur_bus_speed	= get_cur_bus_speed,
 };
 
 
@@ -90,15 +96,15 @@
 static inline int slot_paranoia_check (struct slot *slot, const char *function)
 {
 	if (!slot) {
-		dbg("%s - slot == NULL", function);
+		dbg("%s - slot == NULL\n", function);
 		return -1;
 	}
 	if (slot->magic != SLOT_MAGIC) {
-		dbg("%s - bad magic number for slot", function);
+		dbg("%s - bad magic number for slot\n", function);
 		return -1;
 	}
 	if (!slot->hotplug_slot) {
-		dbg("%s - slot->hotplug_slot == NULL!", function);
+		dbg("%s - slot->hotplug_slot == NULL!\n", function);
 		return -1;
 	}
 	return 0;
@@ -106,16 +112,16 @@
 
 
 static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
-{ 
+{
 	struct slot *slot;
 
 	if (!hotplug_slot) {
-		dbg("%s - hotplug_slot == NULL", function);
+		dbg("%s - hotplug_slot == NULL\n", function);
 		return NULL;
 	}
 
 	slot = (struct slot *)hotplug_slot->private;
-	if (slot_paranoia_check (slot, function))
+	if (slot_paranoia_check(slot, function))
                 return NULL;
 	return slot;
 }
@@ -130,16 +136,16 @@
  */
 static int enable_slot (struct hotplug_slot *hotplug_slot)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval = 0;
-	
+
 	if (slot == NULL)
 		return -ENODEV;
 
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	/* enable the specified slot */
-	retval = acpiphp_enable_slot (slot->acpi_slot);
+	retval = acpiphp_enable_slot(slot->acpi_slot);
 
 	return retval;
 }
@@ -154,16 +160,16 @@
  */
 static int disable_slot (struct hotplug_slot *hotplug_slot)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval = 0;
 
 	if (slot == NULL)
 		return -ENODEV;
-	
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	/* disable the specified slot */
-	retval = acpiphp_disable_slot (slot->acpi_slot);
+	retval = acpiphp_disable_slot(slot->acpi_slot);
 
 	return retval;
 }
@@ -180,8 +186,8 @@
 static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
 {
 	int retval = 0;
-	
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	switch (status) {
 		case 0:
@@ -208,15 +214,15 @@
  */
 static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval = 0;
-	
+
 	if (slot == NULL)
 		return -ENODEV;
-	
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
 
-	err ("No hardware tests are defined for this driver");
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	err("No hardware tests are defined for this driver\n");
 	retval = -ENODEV;
 
 	return retval;
@@ -234,15 +240,15 @@
  */
 static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval = 0;
-	
+
 	if (slot == NULL)
 		return -ENODEV;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
 
-	*value = acpiphp_get_power_status (slot->acpi_slot);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_power_status(slot->acpi_slot);
 
 	return retval;
 }
@@ -258,8 +264,8 @@
 static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
 {
 	int retval = 0;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	*value = hotplug_slot->info->attention_status;
 
@@ -278,15 +284,15 @@
  */
 static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval = 0;
-	
+
 	if (slot == NULL)
 		return -ENODEV;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
 
-	*value = acpiphp_get_latch_status (slot->acpi_slot);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_latch_status(slot->acpi_slot);
 
 	return retval;
 }
@@ -303,20 +309,48 @@
  */
 static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval = 0;
-	
+
 	if (slot == NULL)
 		return -ENODEV;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
 
-	*value = acpiphp_get_adapter_status (slot->acpi_slot);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_adapter_status(slot->acpi_slot);
 
 	return retval;
 }
 
 
+/* return dummy value because ACPI doesn't provide any method... */
+static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	*value = PCI_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+
+/* return dummy value because ACPI doesn't provide any method... */
+static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	*value = PCI_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+
 static int init_acpi (void)
 {
 	int retval;
@@ -335,13 +369,6 @@
 }
 
 
-static void exit_acpi (void)
-{
-	/* deallocate internal data structures etc. */
-	acpiphp_glue_exit();
-}
-
-
 /**
  * make_slot_name - make a slot name that appears in pcihpfs
  * @slot: slot to name
@@ -349,7 +376,10 @@
  */
 static void make_slot_name (struct slot *slot)
 {
-	snprintf (slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%x", slot->acpi_slot->sun);
+	snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%d-%02x:%02x",
+		 slot->acpi_slot->sun,
+		 slot->acpi_slot->bridge->bus,
+		 slot->acpi_slot->device);
 }
 
 /**
@@ -363,31 +393,31 @@
 	int i;
 
 	for (i = 0; i < num_slots; ++i) {
-		slot = kmalloc (sizeof (struct slot), GFP_KERNEL);
+		slot = kmalloc(sizeof(struct slot), GFP_KERNEL);
 		if (!slot)
 			return -ENOMEM;
 		memset(slot, 0, sizeof(struct slot));
 
-		slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
+		slot->hotplug_slot = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
 		if (!slot->hotplug_slot) {
-			kfree (slot);
+			kfree(slot);
 			return -ENOMEM;
 		}
-		memset(slot->hotplug_slot, 0, sizeof (struct hotplug_slot));
+		memset(slot->hotplug_slot, 0, sizeof(struct hotplug_slot));
 
-		slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+		slot->hotplug_slot->info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
 		if (!slot->hotplug_slot->info) {
-			kfree (slot->hotplug_slot);
-			kfree (slot);
+			kfree(slot->hotplug_slot);
+			kfree(slot);
 			return -ENOMEM;
 		}
-		memset(slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info));
+		memset(slot->hotplug_slot->info, 0, sizeof(struct hotplug_slot_info));
 
-		slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL);
+		slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
 		if (!slot->hotplug_slot->name) {
-			kfree (slot->hotplug_slot->info);
-			kfree (slot->hotplug_slot);
-			kfree (slot);
+			kfree(slot->hotplug_slot->info);
+			kfree(slot->hotplug_slot);
+			kfree(slot);
 			return -ENOMEM;
 		}
 
@@ -397,26 +427,27 @@
 		slot->hotplug_slot->private = slot;
 		slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;
 
-		slot->acpi_slot = get_slot_from_id (i);
+		slot->acpi_slot = get_slot_from_id(i);
 		slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot);
 		slot->hotplug_slot->info->attention_status = acpiphp_get_attention_status(slot->acpi_slot);
 		slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot);
 		slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
 
-		make_slot_name (slot);
+		make_slot_name(slot);
 
-		retval = pci_hp_register (slot->hotplug_slot);
+		retval = pci_hp_register(slot->hotplug_slot);
 		if (retval) {
-			err ("pci_hp_register failed with error %d", retval);
-			kfree (slot->hotplug_slot->info);
-			kfree (slot->hotplug_slot->name);
-			kfree (slot->hotplug_slot);
-			kfree (slot);
+			err("pci_hp_register failed with error %d\n", retval);
+			kfree(slot->hotplug_slot->info);
+			kfree(slot->hotplug_slot->name);
+			kfree(slot->hotplug_slot);
+			kfree(slot);
 			return retval;
 		}
 
 		/* add slot to our internal list */
-		list_add (&slot->slot_list, &slot_list);
+		list_add(&slot->slot_list, &slot_list);
+		info("Slot [%s] registered\n", slot->hotplug_slot->name);
 	}
 
 	return retval;
@@ -425,17 +456,17 @@
 
 static void cleanup_slots (void)
 {
-	struct list_head *tmp;
+	struct list_head *tmp, *n;
 	struct slot *slot;
 
-	list_for_each (tmp, &slot_list) {
-		slot = list_entry (tmp, struct slot, slot_list);
-		list_del (&slot->slot_list);
-		pci_hp_deregister (slot->hotplug_slot);
-		kfree (slot->hotplug_slot->info);
-		kfree (slot->hotplug_slot->name);
-		kfree (slot->hotplug_slot);
-		kfree (slot);
+	list_for_each_safe (tmp, n, &slot_list) {
+		slot = list_entry(tmp, struct slot, slot_list);
+		list_del(&slot->slot_list);
+		pci_hp_deregister(slot->hotplug_slot);
+		kfree(slot->hotplug_slot->info);
+		kfree(slot->hotplug_slot->name);
+		kfree(slot->hotplug_slot);
+		kfree(slot);
 	}
 
 	return;
@@ -446,6 +477,10 @@
 {
 	int retval;
 
+	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+
+	acpiphp_debug = debug;
+
 	/* read all the ACPI info from the system */
 	retval = init_acpi();
 	if (retval)
@@ -455,7 +490,6 @@
 	if (retval)
 		return retval;
 
-	info (DRIVER_DESC " version: " DRIVER_VERSION);
 	return 0;
 }
 
@@ -463,7 +497,8 @@
 static void __exit acpiphp_exit(void)
 {
 	cleanup_slots();
-	exit_acpi();
+	/* deallocate internal data structures etc. */
+	acpiphp_glue_exit();
 }
 
 module_init(acpiphp_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/acpiphp_glue.c linux-2.4.21/drivers/hotplug/acpiphp_glue.c
--- linux-2.4.20/drivers/hotplug/acpiphp_glue.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/hotplug/acpiphp_glue.c	2002-12-18 18:58:06.000000000 +0000
@@ -39,12 +39,10 @@
 
 static LIST_HEAD(bridge_list);
 
-static int debug = 1;			/* XXX set 0 after debug */
 #define MY_NAME "acpiphp_glue"
 
 static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
 static void handle_hotplug_event_func (acpi_handle, u32, void *);
-static struct pci_ops *default_ops;
 
 /*
  * initialization & terminatation routines
@@ -90,8 +88,6 @@
 static acpi_status
 is_ejectable_slot (acpi_handle handle, u32 lvl,	void *context, void **rv)
 {
-	acpi_status status;
-	acpi_handle tmp;
 	int *count = (int *)context;
 
 	if (is_ejectable(handle)) {
@@ -157,7 +153,7 @@
 	for (slot = bridge->slots; slot; slot = slot->next)
 		if (slot->device == device) {
 			if (slot->sun != sun)
-				warn("sibling found, but _SUN doesn't match!");
+				warn("sibling found, but _SUN doesn't match!\n");
 			break;
 		}
 
@@ -181,7 +177,7 @@
 
 		bridge->nr_slots++;
 
-		dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d",
+		dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d\n",
 		    slot->bridge->bus, slot->device, slot->sun);
 	}
 
@@ -206,7 +202,7 @@
 					     newfunc);
 
 	if (ACPI_FAILURE(status)) {
-		err("failed to register interrupt notify handler");
+		err("failed to register interrupt notify handler\n");
 		return status;
 	}
 
@@ -306,21 +302,21 @@
 			switch (resource_type) {
 			case ACPI_MEMORY_RANGE:
 				if (cache_attribute == ACPI_PREFETCHABLE_MEMORY) {
-					dbg("resource type: prefetchable memory 0x%x - 0x%x", (u32)min_address_range, (u32)max_address_range);
+					dbg("resource type: prefetchable memory 0x%x - 0x%x\n", (u32)min_address_range, (u32)max_address_range);
 					res = acpiphp_make_resource(min_address_range,
 							    address_length);
 					if (!res) {
-						err("out of memory");
+						err("out of memory\n");
 						return;
 					}
 					res->next = bridge->p_mem_head;
 					bridge->p_mem_head = res;
 				} else {
-					dbg("resource type: memory 0x%x - 0x%x", (u32)min_address_range, (u32)max_address_range);
+					dbg("resource type: memory 0x%x - 0x%x\n", (u32)min_address_range, (u32)max_address_range);
 					res = acpiphp_make_resource(min_address_range,
 							    address_length);
 					if (!res) {
-						err("out of memory");
+						err("out of memory\n");
 						return;
 					}
 					res->next = bridge->mem_head;
@@ -328,22 +324,22 @@
 				}
 				break;
 			case ACPI_IO_RANGE:
-				dbg("resource type: io 0x%x - 0x%x", (u32)min_address_range, (u32)max_address_range);
+				dbg("resource type: io 0x%x - 0x%x\n", (u32)min_address_range, (u32)max_address_range);
 				res = acpiphp_make_resource(min_address_range,
 						    address_length);
 				if (!res) {
-					err("out of memory");
+					err("out of memory\n");
 					return;
 				}
 				res->next = bridge->io_head;
 				bridge->io_head = res;
 				break;
 			case ACPI_BUS_NUMBER_RANGE:
-				dbg("resource type: bus number %d - %d", (u32)min_address_range, (u32)max_address_range);
+				dbg("resource type: bus number %d - %d\n", (u32)min_address_range, (u32)max_address_range);
 				res = acpiphp_make_resource(min_address_range,
 						    address_length);
 				if (!res) {
-					err("out of memory");
+					err("out of memory\n");
 					return;
 				}
 				res->next = bridge->bus_head;
@@ -360,10 +356,9 @@
 	acpiphp_resource_sort_and_combine(&bridge->mem_head);
 	acpiphp_resource_sort_and_combine(&bridge->p_mem_head);
 	acpiphp_resource_sort_and_combine(&bridge->bus_head);
-#if 1
-	info("ACPI _CRS resource:");
+
+	dbg("ACPI _CRS resource:\n");
 	acpiphp_dump_resource(bridge);
-#endif
 }
 
 
@@ -372,7 +367,7 @@
 {
 	const struct list_head *l;
 
-	list_for_each(l, list) {
+	list_for_each (l, list) {
 		struct pci_bus *b = pci_bus_b(l);
 		if (b->number == bus)
 			return b;
@@ -386,7 +381,7 @@
 		}
 	}
 
-	return 0;
+	return NULL;
 }
 
 
@@ -397,7 +392,8 @@
 #if ACPI_CA_VERSION < 0x20020201
 	acpi_buffer buffer;
 #else
-	acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER,
+			       .pointer = NULL};
 #endif
 	acpi_object *package;
 	int i;
@@ -425,7 +421,7 @@
 #endif
 
 	if (ACPI_FAILURE(status)) {
-		dbg("_HPP evaluation failed");
+		dbg("_HPP evaluation failed\n");
 		return;
 	}
 
@@ -433,13 +429,13 @@
 
 	if (!package || package->type != ACPI_TYPE_PACKAGE ||
 	    package->package.count != 4 || !package->package.elements) {
-		err("invalid _HPP object; ignoring");
+		err("invalid _HPP object; ignoring\n");
 		goto err_exit;
 	}
 
 	for (i = 0; i < 4; i++) {
 		if (package->package.elements[i].type != ACPI_TYPE_INTEGER) {
-			err("invalid _HPP parameter type; ignoring");
+			err("invalid _HPP parameter type; ignoring\n");
 			goto err_exit;
 		}
 	}
@@ -449,7 +445,7 @@
 	bridge->hpp.enable_SERR = package->package.elements[2].integer.value;
 	bridge->hpp.enable_PERR = package->package.elements[3].integer.value;
 
-	dbg("_HPP parameter = (%02x, %02x, %02x, %02x)",
+	dbg("_HPP parameter = (%02x, %02x, %02x, %02x)\n",
 	    bridge->hpp.cache_line_size,
 	    bridge->hpp.latency_timer,
 	    bridge->hpp.enable_SERR,
@@ -484,15 +480,13 @@
 					     bridge);
 
 	if (ACPI_FAILURE(status)) {
-		err("failed to register interrupt notify handler");
+		err("failed to register interrupt notify handler\n");
 	}
 
 	list_add(&bridge->list, &bridge_list);
 
-#if 1
-	dbg("Bridge resource:");
+	dbg("Bridge resource:\n");
 	acpiphp_dump_resource(bridge);
-#endif
 }
 
 
@@ -503,7 +497,8 @@
 #if ACPI_CA_VERSION < 0x20020201
 	acpi_buffer buffer;
 #else
-	acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER,
+			       .pointer = NULL};
 #endif
 	struct acpiphp_bridge *bridge;
 
@@ -519,7 +514,6 @@
 	bridge->bus = bus;
 
 	bridge->pci_bus = find_pci_bus(&pci_root_buses, bus);
-	bridge->pci_ops = bridge->pci_bus->ops;
 
 	bridge->res_lock = SPIN_LOCK_UNLOCKED;
 
@@ -545,7 +539,7 @@
 #endif
 
 	if (ACPI_FAILURE(status)) {
-		err("failed to decode bridge resources");
+		err("failed to decode bridge resources\n");
 		kfree(bridge);
 		return;
 	}
@@ -565,17 +559,15 @@
 /* allocate and initialize PCI-to-PCI bridge data structure */
 static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int fn)
 {
-	acpi_status status;
 	struct acpiphp_bridge *bridge;
 	u8 tmp8;
 	u16 tmp16;
-	u32 tmp;
 	u64 base64, limit64;
 	u32 base, limit, base32u, limit32u;
 
 	bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
 	if (bridge == NULL) {
-		err("out of memory");
+		err("out of memory\n");
 		return;
 	}
 
@@ -587,18 +579,17 @@
 
 	bridge->pci_dev = pci_find_slot(bus, PCI_DEVFN(dev, fn));
 	if (!bridge->pci_dev) {
-		err("Can't get pci_dev");
+		err("Can't get pci_dev\n");
 		kfree(bridge);
 		return;
 	}
 
 	bridge->pci_bus = bridge->pci_dev->subordinate;
 	if (!bridge->pci_bus) {
-		err("This is not a PCI-to-PCI bridge!");
+		err("This is not a PCI-to-PCI bridge!\n");
 		kfree(bridge);
 		return;
 	}
-	bridge->pci_ops = bridge->pci_bus->ops;
 
 	bridge->res_lock = SPIN_LOCK_UNLOCKED;
 
@@ -621,10 +612,10 @@
 		limit = ((limit << 8) & 0xf000) + 0xfff;
 		bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
 		if (!bridge->io_head) {
-			err("out of memory");
+			err("out of memory\n");
 			return;
 		}
-		dbg("16bit I/O range: %04x-%04x",
+		dbg("16bit I/O range: %04x-%04x\n",
 		    (u32)bridge->io_head->base,
 		    (u32)(bridge->io_head->base + bridge->io_head->length - 1));
 		break;
@@ -635,18 +626,18 @@
 		limit = (((u32)tmp16 << 16) | ((limit << 8) & 0xf000)) + 0xfff;
 		bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
 		if (!bridge->io_head) {
-			err("out of memory");
+			err("out of memory\n");
 			return;
 		}
-		dbg("32bit I/O range: %08x-%08x",
+		dbg("32bit I/O range: %08x-%08x\n",
 		    (u32)bridge->io_head->base,
 		    (u32)(bridge->io_head->base + bridge->io_head->length - 1));
 		break;
 	case 0x0f:
-		dbg("I/O space unsupported");
+		dbg("I/O space unsupported\n");
 		break;
 	default:
-		warn("Unknown I/O range type");
+		warn("Unknown I/O range type\n");
 	}
 
 	/* Memory resources (mandatory for P2P bridge) */
@@ -656,10 +647,10 @@
 	limit = ((tmp16 & 0xfff0) << 16) | 0xfffff;
 	bridge->mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
 	if (!bridge->mem_head) {
-		err("out of memory");
+		err("out of memory\n");
 		return;
 	}
-	dbg("32bit Memory range: %08x-%08x",
+	dbg("32bit Memory range: %08x-%08x\n",
 	    (u32)bridge->mem_head->base,
 	    (u32)(bridge->mem_head->base + bridge->mem_head->length-1));
 
@@ -675,10 +666,10 @@
 		limit = ((limit & 0xfff0) << 16) | 0xfffff;
 		bridge->p_mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
 		if (!bridge->p_mem_head) {
-			err("out of memory");
+			err("out of memory\n");
 			return;
 		}
-		dbg("32bit Prefetchable memory range: %08x-%08x",
+		dbg("32bit Prefetchable memory range: %08x-%08x\n",
 		    (u32)bridge->p_mem_head->base,
 		    (u32)(bridge->p_mem_head->base + bridge->p_mem_head->length - 1));
 		break;
@@ -690,10 +681,10 @@
 
 		bridge->p_mem_head = acpiphp_make_resource(base64, limit64 - base64 + 1);
 		if (!bridge->p_mem_head) {
-			err("out of memory");
+			err("out of memory\n");
 			return;
 		}
-		dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x",
+		dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x\n",
 		    (u32)(bridge->p_mem_head->base >> 32),
 		    (u32)(bridge->p_mem_head->base & 0xffffffff),
 		    (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) >> 32),
@@ -702,7 +693,7 @@
 	case 0x0f:
 		break;
 	default:
-		warn("Unknown prefetchale memory type");
+		warn("Unknown prefetchale memory type\n");
 	}
 
 	init_bridge_misc(bridge);
@@ -719,7 +710,6 @@
 	unsigned long tmp;
 	int seg, bus, device, function;
 	struct pci_dev *dev;
-	u32 val;
 
 	/* get PCI address */
 	seg = (*segbus >> 8) & 0xff;
@@ -731,7 +721,7 @@
 
 	status = acpi_evaluate_integer(handle, "_ADR", NULL, &tmp);
 	if (ACPI_FAILURE(status)) {
-		dbg("%s: _ADR evaluation failure", __FUNCTION__);
+		dbg("%s: _ADR evaluation failure\n", __FUNCTION__);
 		return AE_OK;
 	}
 
@@ -748,7 +738,7 @@
 
 	/* check if this bridge has ejectable slots */
 	if (detect_ejectable_slots(handle) > 0) {
-		dbg("found PCI-to-PCI bridge at PCI %02x:%02x.%d", bus, device, function);
+		dbg("found PCI-to-PCI bridge at PCI %s\n", dev->slot_name);
 		add_p2p_bridge(handle, seg, bus, device, function);
 	}
 
@@ -763,14 +753,13 @@
 	unsigned long tmp;
 	int seg, bus;
 	acpi_handle dummy_handle;
-	int sta = -1;
 
 	/* if the bridge doesn't have _STA, we assume it is always there */
 	status = acpi_get_handle(handle, "_STA", &dummy_handle);
 	if (ACPI_SUCCESS(status)) {
 		status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);
 		if (ACPI_FAILURE(status)) {
-			dbg("%s: _STA evaluation failure", __FUNCTION__);
+			dbg("%s: _STA evaluation failure\n", __FUNCTION__);
 			return 0;
 		}
 		if ((tmp & ACPI_STA_FUNCTIONING) == 0)
@@ -789,13 +778,13 @@
 	if (ACPI_SUCCESS(status)) {
 		bus = tmp;
 	} else {
-		warn("can't get bus number, assuming 0");
+		warn("can't get bus number, assuming 0\n");
 		bus = 0;
 	}
 
 	/* check if this bridge has ejectable slots */
 	if (detect_ejectable_slots(handle) > 0) {
-		dbg("found PCI host-bus bridge with hot-pluggable slots");
+		dbg("found PCI host-bus bridge with hot-pluggable slots\n");
 		add_host_bridge(handle, seg, bus);
 		return 0;
 	}
@@ -807,7 +796,7 @@
 				     find_p2p_bridge, &tmp, NULL);
 
 	if (ACPI_FAILURE(status))
-		warn("find_p2p_bridge faied (error code = 0x%x)",status);
+		warn("find_p2p_bridge faied (error code = 0x%x)\n",status);
 
 	return 0;
 }
@@ -820,21 +809,23 @@
 	acpi_status status;
 	acpi_device_info info;
 	char objname[5];
-	acpi_buffer buffer = { sizeof(objname), objname };
+	acpi_buffer buffer = { .length = sizeof(objname),
+			       .pointer = objname };
 
 	status = acpi_get_object_info(handle, &info);
 	if (ACPI_FAILURE(status)) {
-		dbg("%s: failed to get bridge information", __FUNCTION__);
+		dbg("%s: failed to get bridge information\n", __FUNCTION__);
 		return AE_OK;		/* continue */
 	}
 
 	info.hardware_id[sizeof(info.hardware_id)-1] = '\0';
 
-	/* TBD check _CID also */
-	if (strcmp(info.hardware_id, ACPI_PCI_HOST_HID) == 0) {
-
+	/* TBD use acpi_get_devices() API */
+	if (info.current_status &&
+	    (info.valid & ACPI_VALID_HID) &&
+	    strcmp(info.hardware_id, ACPI_PCI_HOST_HID) == 0) {
 		acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
-		dbg("checking PCI-hotplug capable bridges under [%s]", objname);
+		dbg("checking PCI-hotplug capable bridges under [%s]\n", objname);
 		add_bridges(handle);
 	}
 	return AE_OK;
@@ -852,15 +843,15 @@
 	if (slot->flags & SLOT_POWEREDON)
 		goto err_exit;
 
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		if (func->flags & FUNC_HAS_PS0) {
-			dbg("%s: executing _PS0 on %02x:%02x.%d", __FUNCTION__,
-			    slot->bridge->bus, slot->device, func->function);
+			dbg("%s: executing _PS0 on %s\n", __FUNCTION__,
+			    func->pci_dev->slot_name);
 			status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL);
 			if (ACPI_FAILURE(status)) {
-				warn("%s: _PS0 failed", __FUNCTION__);
+				warn("%s: _PS0 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
 			}
@@ -890,27 +881,27 @@
 	if ((slot->flags & SLOT_POWEREDON) == 0)
 		goto err_exit;
 
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		if (func->flags & FUNC_HAS_PS3) {
-			dbg("%s: executing _PS3 on %02x:%02x.%d", __FUNCTION__,
-			    slot->bridge->bus, slot->device, func->function);
+			dbg("%s: executing _PS3 on %s\n", __FUNCTION__,
+			    func->pci_dev->slot_name);
 			status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
 			if (ACPI_FAILURE(status)) {
-				warn("%s: _PS3 failed", __FUNCTION__);
+				warn("%s: _PS3 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
 			}
 		}
 	}
 
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		if (func->flags & FUNC_HAS_EJ0) {
-			dbg("%s: executing _EJ0 on %02x:%02x.%d", __FUNCTION__,
-			    slot->bridge->bus, slot->device, func->function);
+			dbg("%s: executing _EJ0 on %s\n", __FUNCTION__,
+			    func->pci_dev->slot_name);
 
 			/* _EJ0 method take one argument */
 			arg_list.count = 1;
@@ -920,7 +911,7 @@
 
 			status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);
 			if (ACPI_FAILURE(status)) {
-				warn("%s: _EJ0 failed", __FUNCTION__);
+				warn("%s: _EJ0 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
 			}
@@ -946,7 +937,6 @@
  */
 static int enable_device (struct acpiphp_slot *slot)
 {
-	acpi_status status;
 	u8 bus;
 	struct pci_dev dev0, *dev;
 	struct pci_bus *child;
@@ -961,7 +951,7 @@
 	dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0));
 	if (dev) {
 		/* This case shouldn't happen */
-		err("pci_dev structure already exists.");
+		err("pci_dev structure already exists.\n");
 		retval = -1;
 		goto err_exit;
 	}
@@ -981,7 +971,7 @@
 	dev = pci_scan_slot (&dev0);
 
 	if (!dev) {
-		err("No new device found");
+		err("No new device found\n");
 		retval = -1;
 		goto err_exit;
 	}
@@ -993,7 +983,7 @@
 	}
 
 	/* associate pci_dev to our representation */
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		func->pci_dev = pci_find_slot(slot->bridge->bus,
@@ -1010,10 +1000,8 @@
 
 	slot->flags |= SLOT_ENABLED;
 
-#if 1
-	dbg("Available resources:");
+	dbg("Available resources:\n");
 	acpiphp_dump_resource(slot->bridge);
-#endif
 
  err_exit:
 	return retval;
@@ -1028,20 +1016,19 @@
 	int retval = 0;
 	struct acpiphp_func *func;
 	struct list_head *l;
-	acpi_status status;
 
 	/* is this slot already disabled? */
 	if (!(slot->flags & SLOT_ENABLED))
 		goto err_exit;
 
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		if (func->pci_dev) {
 			if (acpiphp_unconfigure_function(func) == 0) {
 				func->pci_dev = NULL;
 			} else {
-				err("failed to unconfigure device");
+				err("failed to unconfigure device\n");
 				retval = -1;
 				goto err_exit;
 			}
@@ -1070,12 +1057,11 @@
 {
 	acpi_status status;
 	unsigned long sta = 0;
-	int fn;
 	u32 dvid;
 	struct list_head *l;
 	struct acpiphp_func *func;
 
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		if (func->flags & FUNC_HAS_STA) {
@@ -1083,11 +1069,9 @@
 			if (ACPI_SUCCESS(status) && sta)
 				break;
 		} else {
-			pci_read_config_dword_nodev(default_ops,
-						    slot->bridge->bus,
-						    slot->device,
-						    func->function,
-						    PCI_VENDOR_ID, &dvid);
+			pci_bus_read_config_dword(slot->bridge->pci_bus,
+					PCI_DEVFN(slot->device, func->function),
+					PCI_VENDOR_ID, &dvid);
 			if (dvid != 0xffffffff) {
 				sta = ACPI_STA_ALL;
 				break;
@@ -1106,7 +1090,7 @@
 /**
  * handle_hotplug_event_bridge - handle ACPI event on bridges
  *
- * @handle: Notify()'ed acpi_handle 
+ * @handle: Notify()'ed acpi_handle
  * @type: Notify code
  * @context: pointer to acpiphp_bridge structure
  *
@@ -1117,7 +1101,8 @@
 {
 	struct acpiphp_bridge *bridge;
 	char objname[64];
-	acpi_buffer buffer = { sizeof(objname), objname };
+	acpi_buffer buffer = { .length = sizeof(objname),
+			       .pointer = objname };
 
 	bridge = (struct acpiphp_bridge *)context;
 
@@ -1126,28 +1111,28 @@
 	switch (type) {
 	case ACPI_NOTIFY_BUS_CHECK:
 		/* bus re-enumerate */
-		dbg("%s: Bus check notify on %s", __FUNCTION__, objname);
+		dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname);
 		acpiphp_check_bridge(bridge);
 		break;
 
 	case ACPI_NOTIFY_DEVICE_CHECK:
 		/* device check */
-		dbg("%s: Device check notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device check notify on %s\n", __FUNCTION__, objname);
 		acpiphp_check_bridge(bridge);
 		break;
 
 	case ACPI_NOTIFY_DEVICE_WAKE:
 		/* wake event */
-		dbg("%s: Device wake notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname);
 		break;
 
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
-		dbg("%s: Device eject notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
 		break;
 
 	default:
-		warn("notify_handler: unknown event type 0x%x for %s", type, objname);
+		warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
 		break;
 	}
 }
@@ -1156,7 +1141,7 @@
 /**
  * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
  *
- * @handle: Notify()'ed acpi_handle 
+ * @handle: Notify()'ed acpi_handle
  * @type: Notify code
  * @context: pointer to acpiphp_func structure
  *
@@ -1167,7 +1152,8 @@
 {
 	struct acpiphp_func *func;
 	char objname[64];
-	acpi_buffer buffer = { sizeof(objname), objname };
+	acpi_buffer buffer = { .length = sizeof(objname),
+			       .pointer = objname };
 
 	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
@@ -1176,29 +1162,29 @@
 	switch (type) {
 	case ACPI_NOTIFY_BUS_CHECK:
 		/* bus re-enumerate */
-		dbg("%s: Bus check notify on %s", __FUNCTION__, objname);
+		dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname);
 		acpiphp_enable_slot(func->slot);
 		break;
 
 	case ACPI_NOTIFY_DEVICE_CHECK:
 		/* device check : re-enumerate from parent bus */
-		dbg("%s: Device check notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device check notify on %s\n", __FUNCTION__, objname);
 		acpiphp_check_bridge(func->slot->bridge);
 		break;
 
 	case ACPI_NOTIFY_DEVICE_WAKE:
 		/* wake event */
-		dbg("%s: Device wake notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname);
 		break;
 
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
-		dbg("%s: Device eject notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
 		acpiphp_disable_slot(func->slot);
 		break;
 
 	default:
-		warn("notify_handler: unknown event type 0x%x for %s", type, objname);
+		warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
 		break;
 	}
 }
@@ -1215,17 +1201,12 @@
 	if (list_empty(&pci_root_buses))
 		return -1;
 
-	/* set default pci_ops for configuration space operation */
-	default_ops = pci_bus_b(pci_root_buses.next)->ops;
-	if (!default_ops)
-		return -1;
-
 	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
 				     ACPI_UINT32_MAX, find_host_bridge,
 				     NULL, NULL);
 
 	if (ACPI_FAILURE(status)) {
-		err("%s: acpi_walk_namespace() failed", __FUNCTION__);
+		err("%s: acpi_walk_namespace() failed\n", __FUNCTION__);
 		return -1;
 	}
 
@@ -1240,19 +1221,19 @@
  */
 void acpiphp_glue_exit (void)
 {
-	struct list_head *node, *shead, *l, *n;
+	struct list_head *l1, *l2, *n1, *n2;
 	struct acpiphp_bridge *bridge;
 	struct acpiphp_slot *slot, *next;
 	struct acpiphp_func *func;
 	acpi_status status;
 
-	list_for_each(node, &bridge_list) {
-		bridge = (struct acpiphp_bridge *)node;
+	list_for_each_safe (l1, n1, &bridge_list) {
+		bridge = (struct acpiphp_bridge *)l1;
 		slot = bridge->slots;
 		while (slot) {
 			next = slot->next;
-			list_for_each_safe(l, n, &slot->funcs) {
-				func = list_entry(l, struct acpiphp_func, sibling);
+			list_for_each_safe (l2, n2, &slot->funcs) {
+				func = list_entry(l2, struct acpiphp_func, sibling);
 				acpiphp_free_resource(&func->io_head);
 				acpiphp_free_resource(&func->mem_head);
 				acpiphp_free_resource(&func->p_mem_head);
@@ -1261,7 +1242,7 @@
 								    ACPI_SYSTEM_NOTIFY,
 								    handle_hotplug_event_func);
 				if (ACPI_FAILURE(status))
-					err("failed to remove notify handler");
+					err("failed to remove notify handler\n");
 				kfree(func);
 			}
 			kfree(slot);
@@ -1270,7 +1251,7 @@
 		status = acpi_remove_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY,
 						    handle_hotplug_event_bridge);
 		if (ACPI_FAILURE(status))
-			err("failed to remove notify handler");
+			err("failed to remove notify handler\n");
 
 		acpiphp_free_resource(&bridge->io_head);
 		acpiphp_free_resource(&bridge->mem_head);
@@ -1293,13 +1274,13 @@
 
 	num_slots = 0;
 
-	list_for_each(node, &bridge_list) {
+	list_for_each (node, &bridge_list) {
 		bridge = (struct acpiphp_bridge *)node;
-		dbg("Bus%d %dslot(s)", bridge->bus, bridge->nr_slots);
+		dbg("Bus%d %dslot(s)\n", bridge->bus, bridge->nr_slots);
 		num_slots += bridge->nr_slots;
 	}
 
-	dbg("Total %dslots", num_slots);
+	dbg("Total %dslots\n", num_slots);
 	return num_slots;
 }
 
@@ -1317,7 +1298,7 @@
 	struct acpiphp_slot *slot;
 	int retval = 0;
 
-	list_for_each(node, &bridge_list) {
+	list_for_each (node, &bridge_list) {
 		bridge = (struct acpiphp_bridge *)node;
 		for (slot = bridge->slots; slot; slot = slot->next) {
 			retval = fn(slot, data);
@@ -1338,7 +1319,7 @@
 	struct acpiphp_bridge *bridge;
 	struct acpiphp_slot *slot;
 
-	list_for_each(node, &bridge_list) {
+	list_for_each (node, &bridge_list) {
 		bridge = (struct acpiphp_bridge *)node;
 		for (slot = bridge->slots; slot; slot = slot->next)
 			if (slot->id == id)
@@ -1346,7 +1327,7 @@
 	}
 
 	/* should never happen! */
-	err("%s: no object for id %d",__FUNCTION__, id);
+	err("%s: no object for id %d\n",__FUNCTION__, id);
 	return 0;
 }
 
@@ -1357,7 +1338,6 @@
 int acpiphp_enable_slot (struct acpiphp_slot *slot)
 {
 	int retval;
-	int online = 0;
 
 	down(&slot->crit_sect);
 
@@ -1381,8 +1361,6 @@
  */
 int acpiphp_disable_slot (struct acpiphp_slot *slot)
 {
-	struct list_head *l;
-	struct acpiphp_func *func;
 	int retval = 0;
 
 	down(&slot->crit_sect);
@@ -1397,14 +1375,12 @@
 	if (retval)
 		goto err_exit;
 
-#if 1
 	acpiphp_resource_sort_and_combine(&slot->bridge->io_head);
 	acpiphp_resource_sort_and_combine(&slot->bridge->mem_head);
 	acpiphp_resource_sort_and_combine(&slot->bridge->p_mem_head);
 	acpiphp_resource_sort_and_combine(&slot->bridge->bus_head);
-	dbg("Available resources:");
+	dbg("Available resources:\n");
 	acpiphp_dump_resource(slot->bridge);
-#endif
 
  err_exit:
 	up(&slot->crit_sect);
@@ -1431,7 +1407,7 @@
 			if (sta != ACPI_STA_ALL) {
 				retval = acpiphp_disable_slot(slot);
 				if (retval) {
-					err("Error occured in enabling");
+					err("Error occured in enabling\n");
 					up(&slot->crit_sect);
 					goto err_exit;
 				}
@@ -1442,7 +1418,7 @@
 			if (sta == ACPI_STA_ALL) {
 				retval = acpiphp_enable_slot(slot);
 				if (retval) {
-					err("Error occured in enabling");
+					err("Error occured in enabling\n");
 					up(&slot->crit_sect);
 					goto err_exit;
 				}
@@ -1451,7 +1427,7 @@
 		}
 	}
 
-	dbg("%s: %d enabled, %d disabled", __FUNCTION__, enabled, disabled);
+	dbg("%s: %d enabled, %d disabled\n", __FUNCTION__, enabled, disabled);
 
  err_exit:
 	return retval;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/acpiphp_pci.c linux-2.4.21/drivers/hotplug/acpiphp_pci.c
--- linux-2.4.20/drivers/hotplug/acpiphp_pci.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/hotplug/acpiphp_pci.c	2002-12-18 18:58:07.000000000 +0000
@@ -37,16 +37,14 @@
 #include "pci_hotplug.h"
 #include "acpiphp.h"
 
-static int debug = 1;			/* XXX set 0 after debug */
 #define MY_NAME "acpiphp_pci"
 
 static void acpiphp_configure_irq (struct pci_dev *dev);
 
 
 /* allocate mem/pmem/io resource to a new function */
-static int alloc_resource (struct acpiphp_func *func)
+static int init_config_space (struct acpiphp_func *func)
 {
-	u64 base;
 	u32 bar, len;
 	u32 address[] = {
 		PCI_BASE_ADDRESS_0,
@@ -60,23 +58,22 @@
 	int count;
 	struct acpiphp_bridge *bridge;
 	struct pci_resource *res;
-	struct pci_ops *ops;
-	int bus, device, function;
+	struct pci_bus *bus;
+	int devfn;
 
 	bridge = func->slot->bridge;
-	bus = bridge->bus;
-	device = func->slot->device;
-	function = func->function;
-	ops = bridge->pci_ops;
+	bus = bridge->pci_bus;
+	devfn = PCI_DEVFN(func->slot->device, func->function);
 
 	for (count = 0; address[count]; count++) {	/* for 6 BARs */
-		pci_write_config_dword_nodev (ops, bus, device, function, address[count], 0xFFFFFFFF);
-		pci_read_config_dword_nodev(ops, bus, device, function, address[count], &bar);
+		pci_bus_write_config_dword(bus, devfn, address[count], 0xFFFFFFFF);
+		pci_bus_read_config_dword(bus, devfn, address[count], &bar);
 
 		if (!bar)	/* This BAR is not implemented */
 			continue;
 
-		dbg("Device %02x.%02x BAR %d wants %x", device, function, count, bar);
+		dbg("Device %02x.%d BAR %d wants %x\n", PCI_SLOT(devfn),
+				PCI_FUNC(devfn), count, bar);
 
 		if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
 			/* This is IO */
@@ -84,7 +81,7 @@
 			len = bar & 0xFFFFFFFC;
 			len = ~len + 1;
 
-			dbg ("len in IO %x, BAR %d", len, count);
+			dbg("len in IO %x, BAR %d\n", len, count);
 
 			spin_lock(&bridge->res_lock);
 			res = acpiphp_get_io_resource(&bridge->io_head, len);
@@ -92,10 +89,10 @@
 
 			if (!res) {
 				err("cannot allocate requested io for %02x:%02x.%d len %x\n",
-				    bus, device, function, len);
+				    bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), len);
 				return -1;
 			}
-			pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)res->base);
+			pci_bus_write_config_dword(bus, devfn, address[count], (u32)res->base);
 			res->next = func->io_head;
 			func->io_head = res;
 
@@ -107,7 +104,7 @@
 				len = bar & 0xFFFFFFF0;
 				len = ~len + 1;
 
-				dbg("len in PFMEM %x, BAR %d", len, count);
+				dbg("len in PFMEM %x, BAR %d\n", len, count);
 
 				spin_lock(&bridge->res_lock);
 				res = acpiphp_get_resource(&bridge->p_mem_head, len);
@@ -115,16 +112,16 @@
 
 				if (!res) {
 					err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
-					    bus, device, function, len);
+					    bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), len);
 					return -1;
 				}
 
-				pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)res->base);
+				pci_bus_write_config_dword(bus, devfn, address[count], (u32)res->base);
 
 				if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
-					dbg ("inside the pfmem 64 case, count %d", count);
+					dbg("inside the pfmem 64 case, count %d\n", count);
 					count += 1;
-					pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)(res->base >> 32));
+					pci_bus_write_config_dword(bus, devfn, address[count], (u32)(res->base >> 32));
 				}
 
 				res->next = func->p_mem_head;
@@ -136,7 +133,7 @@
 				len = bar & 0xFFFFFFF0;
 				len = ~len + 1;
 
-				dbg("len in MEM %x, BAR %d", len, count);
+				dbg("len in MEM %x, BAR %d\n", len, count);
 
 				spin_lock(&bridge->res_lock);
 				res = acpiphp_get_resource(&bridge->mem_head, len);
@@ -144,17 +141,17 @@
 
 				if (!res) {
 					err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
-					    bus, device, function, len);
+					    bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), len);
 					return -1;
 				}
 
-				pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)res->base);
+				pci_bus_write_config_dword(bus, devfn, address[count], (u32)res->base);
 
 				if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {
 					/* takes up another dword */
-					dbg ("inside mem 64 case, reg. mem, count %d", count);
+					dbg("inside mem 64 case, reg. mem, count %d\n", count);
 					count += 1;
-					pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)(res->base >> 32));
+					pci_bus_write_config_dword(bus, devfn, address[count], (u32)(res->base >> 32));
 				}
 
 				res->next = func->mem_head;
@@ -165,7 +162,7 @@
 	}
 
 	/* disable expansion rom */
-	pci_write_config_dword_nodev(ops, bus, device, function, PCI_ROM_ADDRESS, 0x00000000);
+	pci_bus_write_config_dword(bus, devfn, PCI_ROM_ADDRESS, 0x00000000);
 
 	return 0;
 }
@@ -203,15 +200,16 @@
 	pci_proc_attach_device(dev);
 #endif
 	pci_announce_device_to_drivers(dev);
+	info("Device %s configured\n", dev->slot_name);
 
 	return 0;
 }
 
 
-static int is_pci_dev_in_use (struct pci_dev* dev) 
+static int is_pci_dev_in_use (struct pci_dev* dev)
 {
-	/* 
-	 * dev->driver will be set if the device is in use by a new-style 
+	/*
+	 * dev->driver will be set if the device is in use by a new-style
 	 * driver -- otherwise, check the device's regions to see if any
 	 * driver has claimed them
 	 */
@@ -253,13 +251,13 @@
 {
 	struct pci_dev *dev = wrapped_dev->dev;
 
-	dbg("attempting removal of driver for device %s", dev->slot_name);
+	dbg("attempting removal of driver for device %s\n", dev->slot_name);
 
 	/* Now, remove the Linux Driver Representation */
 	if (dev->driver) {
 		if (dev->driver->remove) {
 			dev->driver->remove(dev);
-			dbg("driver was properly removed");
+			dbg("driver was properly removed\n");
 		}
 		dev->driver = NULL;
 	}
@@ -276,6 +274,7 @@
 	/* Now, remove the Linux Representation */
 	if (dev) {
 		if (pci_hp_remove_device(dev) == 0) {
+			info("Device %s removed\n", dev->slot_name);
 			kfree(dev); /* Now, remove */
 		} else {
 			return -1; /* problems while freeing, abort visitation */
@@ -313,7 +312,7 @@
 /* detect_used_resource - subtract resource under dev from bridge */
 static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *dev)
 {
-	u32 bar, len, pin;
+	u32 bar, len;
 	u64 base;
 	u32 address[] = {
 		PCI_BASE_ADDRESS_0,
@@ -327,7 +326,7 @@
 	int count;
 	struct pci_resource *res;
 
-	dbg("Device %s", dev->slot_name);
+	dbg("Device %s\n", dev->slot_name);
 
 	for (count = 0; address[count]; count++) {	/* for 6 BARs */
 		pci_read_config_dword(dev, address[count], &bar);
@@ -344,7 +343,7 @@
 			len &= 0xFFFFFFFC;
 			len = ~len + 1;
 
-			dbg("BAR[%d] %08x - %08x (IO)", count, (u32)base, (u32)base + len - 1);
+			dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
 
 			spin_lock(&bridge->res_lock);
 			res = acpiphp_get_resource_with_base(&bridge->io_head, base, len);
@@ -361,10 +360,10 @@
 				len = ~len + 1;
 
 				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
-					dbg ("prefetch mem 64");
+					dbg("prefetch mem 64\n");
 					count += 1;
 				}
-				dbg("BAR[%d] %08x - %08x (PMEM)", count, (u32)base, (u32)base + len - 1);
+				dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1);
 				spin_lock(&bridge->res_lock);
 				res = acpiphp_get_resource_with_base(&bridge->p_mem_head, base, len);
 				spin_unlock(&bridge->res_lock);
@@ -378,10 +377,10 @@
 
 				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {
 					/* takes up another dword */
-					dbg ("mem 64");
+					dbg("mem 64\n");
 					count += 1;
 				}
-				dbg("BAR[%d] %08x - %08x (MEM)", count, (u32)base, (u32)base + len - 1);
+				dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1);
 				spin_lock(&bridge->res_lock);
 				res = acpiphp_get_resource_with_base(&bridge->mem_head, base, len);
 				spin_unlock(&bridge->res_lock);
@@ -403,7 +402,7 @@
 	struct list_head *l;
 	struct pci_dev *dev;
 
-	list_for_each(l, &bus->devices) {
+	list_for_each (l, &bus->devices) {
 		dev = pci_dev_b(l);
 		detect_used_resource(bridge, dev);
 		/* XXX recursive call */
@@ -421,9 +420,6 @@
  */
 int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge)
 {
-	struct list_head *l;
-	struct pci_dev *dev;
-
 	detect_used_resource_bus(bridge, bridge->pci_bus);
 
 	return 0;
@@ -452,20 +448,19 @@
 	};
 	int count;
 	struct pci_resource *res;
-	struct pci_ops *ops;
 	struct pci_dev *dev;
 
 	dev = func->pci_dev;
-	dbg("Hot-pluggable device %s", dev->slot_name);
+	dbg("Hot-pluggable device %s\n", dev->slot_name);
 
 	for (count = 0; address[count]; count++) {	/* for 6 BARs */
-		pci_read_config_dword (dev, address[count], &bar);
+		pci_read_config_dword(dev, address[count], &bar);
 
 		if (!bar)	/* This BAR is not implemented */
 			continue;
 
-		pci_write_config_dword (dev, address[count], 0xFFFFFFFF);
-		pci_read_config_dword (dev, address[count], &len);
+		pci_write_config_dword(dev, address[count], 0xFFFFFFFF);
+		pci_read_config_dword(dev, address[count], &len);
 
 		if (len & PCI_BASE_ADDRESS_SPACE_IO) {
 			/* This is IO */
@@ -473,7 +468,7 @@
 			len &= 0xFFFFFFFC;
 			len = ~len + 1;
 
-			dbg("BAR[%d] %08x - %08x (IO)", count, (u32)base, (u32)base + len - 1);
+			dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
 
 			res = acpiphp_make_resource(base, len);
 			if (!res)
@@ -492,10 +487,10 @@
 				len = ~len + 1;
 
 				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
-					dbg ("prefetch mem 64");
+					dbg("prefetch mem 64\n");
 					count += 1;
 				}
-				dbg("BAR[%d] %08x - %08x (PMEM)", count, (u32)base, (u32)base + len - 1);
+				dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1);
 				res = acpiphp_make_resource(base, len);
 				if (!res)
 					goto no_memory;
@@ -511,10 +506,10 @@
 
 				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {
 					/* takes up another dword */
-					dbg ("mem 64");
+					dbg("mem 64\n");
 					count += 1;
 				}
-				dbg("BAR[%d] %08x - %08x (MEM)", count, (u32)base, (u32)base + len - 1);
+				dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1);
 				res = acpiphp_make_resource(base, len);
 				if (!res)
 					goto no_memory;
@@ -525,7 +520,7 @@
 			}
 		}
 
-		pci_write_config_dword (dev, address[count], bar);
+		pci_write_config_dword(dev, address[count], bar);
 	}
 #if 1
 	acpiphp_dump_func_resource(func);
@@ -534,7 +529,7 @@
 	return 0;
 
  no_memory:
-	err("out of memory");
+	err("out of memory\n");
 	acpiphp_free_resource(&func->io_head);
 	acpiphp_free_resource(&func->mem_head);
 	acpiphp_free_resource(&func->p_mem_head);
@@ -560,23 +555,22 @@
 	int retval = 0;
 	int is_multi = 0;
 
-	pci_read_config_byte_nodev(slot->bridge->pci_ops,
-				   slot->bridge->bus, slot->device, 0,
-				   PCI_HEADER_TYPE, &hdr);
+	pci_bus_read_config_byte(slot->bridge->pci_bus,
+					PCI_DEVFN(slot->device, 0),
+					PCI_HEADER_TYPE, &hdr);
 
 	if (hdr & 0x80)
 		is_multi = 1;
 
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 		if (is_multi || func->function == 0) {
-			pci_read_config_dword_nodev(slot->bridge->pci_ops,
-						    slot->bridge->bus,
-						    slot->device,
-						    func->function,
+			pci_bus_read_config_dword(slot->bridge->pci_bus,
+						    PCI_DEVFN(slot->device,
+								func->function),
 						    PCI_VENDOR_ID, &dvid);
 			if (dvid != 0xffffffff) {
-				retval = alloc_resource(func);
+				retval = init_config_space(func);
 				if (retval)
 					break;
 			}
@@ -589,16 +583,16 @@
 
 /* for pci_visit_dev() */
 static struct pci_visit configure_functions = {
-	post_visit_pci_dev:	configure_pci_dev
+	.post_visit_pci_dev =	configure_pci_dev
 };
 
 static struct pci_visit unconfigure_functions_phase1 = {
-	post_visit_pci_dev:	unconfigure_pci_dev_driver
+	.post_visit_pci_dev =	unconfigure_pci_dev_driver
 };
 
 static struct pci_visit unconfigure_functions_phase2 = {
-	post_visit_pci_bus:	unconfigure_pci_bus,
-	post_visit_pci_dev:	unconfigure_pci_dev
+	.post_visit_pci_bus =	unconfigure_pci_bus,
+	.post_visit_pci_dev =	unconfigure_pci_dev
 };
 
 
@@ -647,7 +641,6 @@
 int acpiphp_unconfigure_function (struct acpiphp_func *func)
 {
 	struct acpiphp_bridge *bridge;
-	struct pci_resource *tmp;
 	struct pci_dev_wrapped wrapped_dev;
 	struct pci_bus_wrapped wrapped_bus;
 	int retval = 0;
@@ -686,45 +679,6 @@
 }
 
 
-/* XXX IA64 specific */
-#ifdef CONFIG_IA64
-static int ia64_get_irq(struct pci_dev *dev, int pin)
-{
-	extern int pci_pin_to_vector(int bus, int slot, int pci_pin);
-	int irq;
-
-	irq = pci_pin_to_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
-
-	if (irq < 0 && dev->bus->parent) {
-		/* go back to the bridge */
-		struct pci_dev *bridge = dev->bus->self;
-
-		if (bridge) {
-			/* allow for multiple bridges on an adapter */
-			do {
-				/* do the bridge swizzle... */
-				pin = (pin + PCI_SLOT(dev->devfn)) % 4;
-				irq = pci_pin_to_vector(bridge->bus->number,
-							PCI_SLOT(bridge->devfn),
-							   pin);
-			} while (irq < 0 && (bridge = bridge->bus->self));
-		}
-		if (irq >= 0)
-			printk(KERN_WARNING
-			       "PCI: using PPB(B%d,I%d,P%d) to get vector %02x\n",
-			       dev->bus->number, PCI_SLOT(dev->devfn),
-			       pin, irq);
-		else
-			printk(KERN_WARNING
-			       "PCI: Couldn't map irq for (B%d,I%d,P%d)\n",
-			       dev->bus->number, PCI_SLOT(dev->devfn), pin);
-	}
-
-	return irq;
-}
-#endif
-
-
 /*
  * acpiphp_configure_irq - configure PCI_INTERRUPT_PIN
  *
@@ -740,24 +694,10 @@
  */
 static void acpiphp_configure_irq (struct pci_dev *dev)
 {
-#if CONFIG_IA64		    /* XXX IA64 specific, need i386 version */
-	int bus, device, function, irq;
-	u8 tmp;
-
-	bus = dev->bus->number;
-	device = PCI_SLOT(dev->devfn);
-	function = PCI_FUNC(dev->devfn);
-
-	pci_read_config_byte (dev, PCI_INTERRUPT_PIN, &tmp);
-
-	if ((tmp > 0x00) && (tmp < 0x05)) {
-		irq = ia64_get_irq(dev, tmp - 1);
-		if (irq > 0) {
-			dev->irq = irq;
-			pci_write_config_byte (dev, PCI_INTERRUPT_LINE, irq);
-		} else {
-			err("Couldn't get IRQ for INT%c", 'A' + tmp - 1);
-		}
-	}
+#if CONFIG_IA64		    /* XXX IA64 specific */
+	extern void iosapic_fixup_pci_interrupt (struct pci_dev *dev);
+
+	iosapic_fixup_pci_interrupt(dev);
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
 #endif
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/acpiphp_res.c linux-2.4.21/drivers/hotplug/acpiphp_res.c
--- linux-2.4.20/drivers/hotplug/acpiphp_res.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/hotplug/acpiphp_res.c	2002-12-18 18:58:08.000000000 +0000
@@ -59,8 +59,6 @@
 
 #define MY_NAME "acpiphp_res"
 
-/* local variables */
-static int debug = 0;
 
 /*
  * sort_by_size - sort nodes by their length, smallest first
@@ -275,7 +273,7 @@
 
 	for (max = *head;max; max = max->next) {
 
-		/* If not big enough we could probably just bail, 
+		/* If not big enough we could probably just bail,
 		   instead we'll continue to the next. */
 		if (max->length < size)
 			continue;
@@ -372,13 +370,13 @@
 		return NULL;
 
 	for (node = *head; node; node = node->next) {
-		dbg("%s: req_size =%x node=%p, base=%x, length=%x",
+		dbg("%s: req_size =%x node=%p, base=%x, length=%x\n",
 		    __FUNCTION__, size, node, (u32)node->base, node->length);
 		if (node->length < size)
 			continue;
 
 		if (node->base & (size - 1)) {
-			dbg("%s: not aligned", __FUNCTION__);
+			dbg("%s: not aligned\n", __FUNCTION__);
 			/* this one isn't base aligned properly
 			   so we'll make a new entry and split it up */
 			temp_qword = (node->base | (size-1)) + 1;
@@ -402,7 +400,7 @@
 
 		/* Don't need to check if too small since we already did */
 		if (node->length > size) {
-			dbg("%s: too big", __FUNCTION__);
+			dbg("%s: too big\n", __FUNCTION__);
 			/* this one is longer than we need
 			   so we'll make a new entry and split it up */
 			split_node = acpiphp_make_resource(node->base + size, node->length - size);
@@ -417,7 +415,7 @@
 			node->next = split_node;
 		}  /* End of too big on top end */
 
-		dbg("%s: got one!!!", __FUNCTION__);
+		dbg("%s: got one!!!\n", __FUNCTION__);
 		/* If we got here, then it is the right size
 		   Now take it out of the list */
 		if (*head == node) {
@@ -439,7 +437,7 @@
 /**
  * get_resource_with_base - get resource with specific base address
  *
- * this function 
+ * this function
  * returns the first node of "size" length located at specified base address.
  * If it finds a node larger than "size" it will split it up.
  *
@@ -460,7 +458,7 @@
 		return NULL;
 
 	for (node = *head; node; node = node->next) {
-		dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x",
+		dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
 		    (u32)base, size, node, (u32)node->base, node->length);
 		if (node->base > base)
 			continue;
@@ -469,7 +467,7 @@
 			continue;
 
 		if (node->base < base) {
-			dbg(": split 1");
+			dbg(": split 1\n");
 			/* this one isn't base aligned properly
 			   so we'll make a new entry and split it up */
 			temp_qword = base;
@@ -491,12 +489,12 @@
 			node->next = split_node;
 		}
 
-		dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x",
+		dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
 		    (u32)base, size, node, (u32)node->base, node->length);
 
 		/* Don't need to check if too small since we already did */
 		if (node->length > size) {
-			dbg(": split 2");
+			dbg(": split 2\n");
 			/* this one is longer than we need
 			   so we'll make a new entry and split it up */
 			split_node = acpiphp_make_resource(node->base + size, node->length - size);
@@ -511,7 +509,7 @@
 			node->next = split_node;
 		}  /* End of too big on top end */
 
-		dbg(": got one!!!");
+		dbg(": got one!!!\n");
 		/* If we got here, then it is the right size
 		   Now take it out of the list */
 		if (*head == node) {
@@ -549,13 +547,13 @@
 	if (!(*head))
 		return 1;
 
-	dbg("*head->next = %p",(*head)->next);
+	dbg("*head->next = %p\n",(*head)->next);
 
 	if (!(*head)->next)
 		return 0;	/* only one item on the list, already sorted! */
 
-	dbg("*head->base = 0x%x",(u32)(*head)->base);
-	dbg("*head->next->base = 0x%x", (u32)(*head)->next->base);
+	dbg("*head->base = 0x%x\n",(u32)(*head)->base);
+	dbg("*head->next->base = 0x%x\n", (u32)(*head)->next->base);
 	while (out_of_order) {
 		out_of_order = 0;
 
@@ -589,7 +587,7 @@
 	while (node1 && node1->next) {
 		if ((node1->base + node1->length) == node1->next->base) {
 			/* Combine */
-			dbg("8..");
+			dbg("8..\n");
 			node1->length += node1->next->length;
 			node2 = node1->next;
 			node1->next = node1->next->next;
@@ -670,39 +668,32 @@
 	cnt = 0;
 
 	while (p) {
-		info("[%02d] %08x - %08x",
-		     cnt++, (u32)p->base, (u32)p->base + p->length - 1);
+		dbg("[%02d] %08x - %08x\n",
+		    cnt++, (u32)p->base, (u32)p->base + p->length - 1);
 		p = p->next;
 	}
 }
 
 void acpiphp_dump_resource(struct acpiphp_bridge *bridge)
 {
-	info("I/O resource:");
+	dbg("I/O resource:\n");
 	dump_resource(bridge->io_head);
-	info("MEM resource:");
+	dbg("MEM resource:\n");
 	dump_resource(bridge->mem_head);
-	info("PMEM resource:");
+	dbg("PMEM resource:\n");
 	dump_resource(bridge->p_mem_head);
-	info("BUS resource:");
+	dbg("BUS resource:\n");
 	dump_resource(bridge->bus_head);
 }
 
 void acpiphp_dump_func_resource(struct acpiphp_func *func)
 {
-	info("I/O resource:");
+	dbg("I/O resource:\n");
 	dump_resource(func->io_head);
-	info("MEM resource:");
+	dbg("MEM resource:\n");
 	dump_resource(func->mem_head);
-	info("PMEM resource:");
+	dbg("PMEM resource:\n");
 	dump_resource(func->p_mem_head);
-	info("BUS resource:");
+	dbg("BUS resource:\n");
 	dump_resource(func->bus_head);
 }
-
-/*
-EXPORT_SYMBOL(acpiphp_get_io_resource);
-EXPORT_SYMBOL(acpiphp_get_max_resource);
-EXPORT_SYMBOL(acpiphp_get_resource);
-EXPORT_SYMBOL(acpiphp_resource_sort_and_combine);
-*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/pci_hotplug.h linux-2.4.21/drivers/hotplug/pci_hotplug.h
--- linux-2.4.20/drivers/hotplug/pci_hotplug.h	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/hotplug/pci_hotplug.h	2002-12-18 18:58:07.000000000 +0000
@@ -167,6 +167,18 @@
 				 struct pci_dev_wrapped *wrapped_dev,
 				 struct pci_bus_wrapped *wrapped_parent);
 
+int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val);
+int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val);
+int pci_bus_read_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 *val);
+int pci_bus_write_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 val);
+int pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 val);
+int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 val);
+
+/*
+ * Compatibility functions.  Don't use these, use the
+ * pci_bus_*() functions above.
+ */
+
 extern int pci_read_config_byte_nodev	(struct pci_ops *ops, u8 bus, u8 device,
 					 u8 function, int where, u8 *val);
 extern int pci_read_config_word_nodev	(struct pci_ops *ops, u8 bus, u8 device,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/pci_hotplug_util.c linux-2.4.21/drivers/hotplug/pci_hotplug_util.c
--- linux-2.4.20/drivers/hotplug/pci_hotplug_util.c	2001-11-09 22:01:22.000000000 +0000
+++ linux-2.4.21/drivers/hotplug/pci_hotplug_util.c	2002-12-18 18:58:10.000000000 +0000
@@ -50,78 +50,58 @@
 /* local variables */
 static int debug;
 
-
-static int build_dev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, struct pci_dev **pci_dev)
+static int build_dev (struct pci_bus *bus, unsigned int devfn, struct pci_dev **pci_dev)
 {
 	struct pci_dev *my_dev;
-	struct pci_bus *my_bus;
-
-	/* Some validity checks. */
-	if ((function > 7) ||
-	    (slot > 31) ||
-	    (pci_dev == NULL) ||
-	    (ops == NULL))
-		return -ENODEV;
 
 	my_dev = kmalloc (sizeof (struct pci_dev), GFP_KERNEL);
 	if (!my_dev)
 		return -ENOMEM;
-	my_bus = kmalloc (sizeof (struct pci_bus), GFP_KERNEL);
-	if (!my_bus) {
-		kfree (my_dev);
-		return -ENOMEM;
-	}
+
 	memset(my_dev, 0, sizeof(struct pci_dev));
-	memset(my_bus, 0, sizeof(struct pci_bus));
 
-	my_bus->number = bus;
-	my_bus->ops = ops;
-	my_dev->devfn = PCI_DEVFN(slot, function);
-	my_dev->bus = my_bus;
+	my_dev->devfn = devfn;
+	my_dev->bus = bus;
+	my_dev->sysdata = bus->sysdata;
 	*pci_dev = my_dev;
 	return 0;
 }
 
 /**
- * pci_read_config_byte_nodev - read a byte from a pci device
- * @ops: pointer to a &struct pci_ops that will be used to read from the pci device
- * @bus: the bus of the pci device to read from
- * @slot: the pci slot number of the pci device to read from
- * @function: the function of the pci device to read from
- * @where: the location on the pci address space to read from
+ * pci_bus_read_config_byte - read a byte from a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
+ * @where: the location in the pci address space to read from
  * @value: pointer to where to place the data read
  *
  * Like pci_read_config_byte() but works for pci devices that do not have a
  * pci_dev structure set up yet.
  * Returns 0 on success.
  */
-int pci_read_config_byte_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u8 *value)
+int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %p\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_read_config_byte (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_read_config_byte(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
 
 /**
- * pci_read_config_word_nodev - read a word from a pci device
- * @ops: pointer to a &struct pci_ops that will be used to read from the pci device
- * @bus: the bus of the pci device to read from
- * @slot: the pci slot number of the pci device to read from
- * @function: the function of the pci device to read from
+ * pci_bus_read_config_word - read a word from a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
  * @where: the location on the pci address space to read from
  * @value: pointer to where to place the data read
  *
@@ -129,34 +109,30 @@
  * pci_dev structure set up yet. 
  * Returns 0 on success.
  */
-int pci_read_config_word_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u16 *value)
+int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %p\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_read_config_word (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_read_config_word(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
 
 /**
- * pci_read_config_dword_nodev - read a dword from a pci device
- * @ops: pointer to a &struct pci_ops that will be used to read from the pci
- * device
- * @bus: the bus of the pci device to read from
- * @slot: the pci slot number of the pci device to read from
- * @function: the function of the pci device to read from
+ * pci_bus_read_config_dword - read a dword from a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
  * @where: the location on the pci address space to read from
  * @value: pointer to where to place the data read
  *
@@ -164,34 +140,30 @@
  * pci_dev structure set up yet. 
  * Returns 0 on success.
  */
-int pci_read_config_dword_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u32 *value)
+int pci_bus_read_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 *value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %p\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_read_config_dword (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_read_config_dword(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
 
 /**
- * pci_write_config_byte_nodev - write a byte to a pci device
- * @ops: pointer to a &struct pci_ops that will be used to write to the pci
- * device
- * @bus: the bus of the pci device to write to
- * @slot: the pci slot number of the pci device to write to
- * @function: the function of the pci device to write to
+ * pci_bus_write_config_byte - write a byte to a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
  * @where: the location on the pci address space to write to
  * @value: the value to write to the pci device
  *
@@ -199,34 +171,30 @@
  * pci_dev structure set up yet. 
  * Returns 0 on success.
  */
-int pci_write_config_byte_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u8 value)
+int pci_bus_write_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %d\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_write_config_byte (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_write_config_byte(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
 
 /**
- * pci_write_config_word_nodev - write a word to a pci device
- * @ops: pointer to a &struct pci_ops that will be used to write to the pci
- * device
- * @bus: the bus of the pci device to write to
- * @slot: the pci slot number of the pci device to write to
- * @function: the function of the pci device to write to
+ * pci_bus_write_config_word - write a word to a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
  * @where: the location on the pci address space to write to
  * @value: the value to write to the pci device
  *
@@ -234,34 +202,30 @@
  * pci_dev structure set up yet. 
  * Returns 0 on success.
  */
-int pci_write_config_word_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u16 value)
+int pci_bus_write_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %d\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_write_config_word (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_write_config_word(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
 
 /**
- * pci_write_config_dword_nodev - write a dword to a pci device
- * @ops: pointer to a &struct pci_ops that will be used to write to the pci
- * device
- * @bus: the bus of the pci device to write to
- * @slot: the pci slot number of the pci device to write to
- * @function: the function of the pci device to write to
+ * pci_bus_write_config_dword - write a dword to a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
  * @where: the location on the pci address space to write to
  * @value: the value to write to the pci device
  *
@@ -269,23 +233,22 @@
  * pci_dev structure set up yet. 
  * Returns 0 on success.
  */
-int pci_write_config_dword_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u32 value)
+int pci_bus_write_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %d\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_write_config_dword (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_write_config_dword(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
@@ -392,8 +355,98 @@
 	return result;
 }
 
+/* Compatibility wrapper functions */
+
+static struct pci_bus *alloc_bus(struct pci_ops *ops, u8 bus_nr)
+{
+	struct pci_bus *bus = kmalloc(sizeof(struct pci_bus), GFP_KERNEL);
+	if (!bus)
+		return NULL;
+	memset(bus, 0, sizeof(struct pci_bus));
+	bus->number = bus_nr;
+	bus->ops = ops;
+	return bus;
+}
+
+int pci_read_config_byte_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u8 *value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_read_config_byte(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
+
+int pci_read_config_word_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u16 *value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_read_config_word(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
+
+int pci_read_config_dword_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u32 *value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_read_config_dword(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
+
+int pci_write_config_byte_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u8 value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_write_config_byte(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
+
+int pci_write_config_word_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u16 value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_write_config_word(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
+
+int pci_write_config_dword_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u32 value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_write_config_dword(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
 
 EXPORT_SYMBOL(pci_visit_dev);
+EXPORT_SYMBOL(pci_bus_read_config_byte);
+EXPORT_SYMBOL(pci_bus_read_config_word);
+EXPORT_SYMBOL(pci_bus_read_config_dword);
+EXPORT_SYMBOL(pci_bus_write_config_byte);
+EXPORT_SYMBOL(pci_bus_write_config_word);
+EXPORT_SYMBOL(pci_bus_write_config_dword);
 EXPORT_SYMBOL(pci_read_config_byte_nodev);
 EXPORT_SYMBOL(pci_read_config_word_nodev);
 EXPORT_SYMBOL(pci_read_config_dword_nodev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/i2c/Config.in linux-2.4.21/drivers/i2c/Config.in
--- linux-2.4.20/drivers/i2c/Config.in	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.21/drivers/i2c/Config.in	2002-12-18 18:58:11.000000000 +0000
@@ -13,6 +13,12 @@
       dep_tristate '  Philips style parallel port adapter' CONFIG_I2C_PHILIPSPAR $CONFIG_I2C_ALGOBIT $CONFIG_PARPORT
       dep_tristate '  ELV adapter' CONFIG_I2C_ELV $CONFIG_I2C_ALGOBIT
       dep_tristate '  Velleman K9000 adapter' CONFIG_I2C_VELLEMAN $CONFIG_I2C_ALGOBIT
+      dep_tristate '  NatSemi SCx200 I2C using GPIO pins' CONFIG_SCx200_I2C $CONFIG_SCx200 $CONFIG_I2C_ALGOBIT
+      if [ "$CONFIG_SCx200_I2C" != "n" ]; then
+         int  '    GPIO pin used for SCL' CONFIG_SCx200_I2C_SCL 12
+         int  '    GPIO pin used for SDA' CONFIG_SCx200_I2C_SDA 13
+      fi
+      dep_tristate '  NatSemi SCx200 ACCESS.bus' CONFIG_SCx200_ACB $CONFIG_I2C
    fi
 
    dep_tristate 'I2C PCF 8584 interfaces' CONFIG_I2C_ALGOPCF $CONFIG_I2C
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/i2c/Makefile linux-2.4.21/drivers/i2c/Makefile
--- linux-2.4.20/drivers/i2c/Makefile	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.21/drivers/i2c/Makefile	2002-12-18 18:58:01.000000000 +0000
@@ -18,6 +18,8 @@
 obj-$(CONFIG_ITE_I2C_ALGO)	+= i2c-algo-ite.o
 obj-$(CONFIG_ITE_I2C_ADAP)	+= i2c-adap-ite.o
 obj-$(CONFIG_I2C_PROC)		+= i2c-proc.o
+obj-$(CONFIG_SCx200_I2C)	+= scx200_i2c.o
+obj-$(CONFIG_SCx200_ACB)	+= scx200_acb.o
 obj-$(CONFIG_I2C_KEYWEST)	+= i2c-keywest.o
 
 # This is needed for automatic patch generation: sensors code starts here
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/i2c/scx200_acb.c linux-2.4.21/drivers/i2c/scx200_acb.c
--- linux-2.4.20/drivers/i2c/scx200_acb.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/i2c/scx200_acb.c	2002-12-18 18:58:11.000000000 +0000
@@ -0,0 +1,579 @@
+/*  linux/drivers/i2c/scx200_acb.c 
+
+    Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+    National Semiconductor SCx200 ACCESS.bus support
+    
+    Based on i2c-keywest.c which is:
+        Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+        Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.
+   
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    General Public License for more details.
+   
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/smp_lock.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include <linux/scx200.h>
+
+#define NAME "scx200_acb"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver");
+MODULE_LICENSE("GPL");
+
+#define MAX_DEVICES 4
+static int base[MAX_DEVICES] = { 0x840 };
+MODULE_PARM(base, "1-4i");
+MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers");
+
+#define DEBUG 0
+
+#if DEBUG
+#define DBG(x...) printk(KERN_DEBUG NAME ": " x)
+#else
+#define DBG(x...)
+#endif
+
+/* The hardware supports interrupt driven mode too, but I haven't
+   implemented that. */
+#define POLLED_MODE 1
+#define POLL_TIMEOUT (HZ)
+
+enum scx200_acb_state {
+	state_idle,
+	state_address,
+	state_command,
+	state_repeat_start,
+	state_quick,
+	state_read,
+	state_write,
+};
+
+static const char *scx200_acb_state_name[] = {
+	"idle",
+	"address",
+	"command",
+	"repeat_start",
+	"quick",
+	"read",
+	"write",
+};
+
+/* Physical interface */
+struct scx200_acb_iface
+{
+	struct scx200_acb_iface *next;
+	struct i2c_adapter adapter;
+	unsigned base;
+	struct semaphore sem;
+
+	/* State machine data */
+	enum scx200_acb_state state;
+	int result;
+	u8 address_byte;
+	u8 command;
+	u8 *ptr;
+	char needs_reset;
+	unsigned len;
+};
+
+/* Register Definitions */
+#define ACBSDA		(iface->base + 0)
+#define ACBST		(iface->base + 1)
+#define    ACBST_SDAST		0x40 /* SDA Status */
+#define    ACBST_BER		0x20 
+#define    ACBST_NEGACK		0x10 /* Negative Acknowledge */
+#define    ACBST_STASTR		0x08 /* Stall After Start */
+#define    ACBST_MASTER		0x02
+#define ACBCST		(iface->base + 2)
+#define    ACBCST_BB		0x02
+#define ACBCTL1		(iface->base + 3)
+#define    ACBCTL1_STASTRE	0x80
+#define    ACBCTL1_NMINTE	0x40
+#define	   ACBCTL1_ACK		0x10
+#define	   ACBCTL1_STOP		0x02
+#define	   ACBCTL1_START	0x01
+#define ACBADDR		(iface->base + 4)
+#define ACBCTL2		(iface->base + 5)
+#define    ACBCTL2_ENABLE	0x01
+
+/************************************************************************/
+
+static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
+{
+	const char *errmsg;
+
+	DBG("state %s, status = 0x%02x\n", 
+	    scx200_acb_state_name[iface->state], status);
+
+	if (status & ACBST_BER) {
+		errmsg = "bus error";
+		goto error;
+	}
+	if (!(status & ACBST_MASTER)) {
+		errmsg = "not master";
+		goto error;
+	}
+	if (status & ACBST_NEGACK)
+		goto negack;
+
+	switch (iface->state) {
+	case state_idle:
+		printk(KERN_WARNING NAME ": %s, interrupt in idle state\n", 
+		       iface->adapter.name);
+		break;
+
+	case state_address:
+		/* Do a pointer write first */
+		outb(iface->address_byte & ~1, ACBSDA);
+
+		iface->state = state_command;
+		break;
+
+	case state_command:
+		outb(iface->command, ACBSDA);
+
+		if (iface->address_byte & 1)
+			iface->state = state_repeat_start;
+		else
+			iface->state = state_write;
+		break;
+
+	case state_repeat_start:
+		outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+		/* fallthrough */
+		
+	case state_quick:
+		if (iface->address_byte & 1) {
+			if (iface->len == 1) 
+				outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
+			else
+				outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
+			outb(iface->address_byte, ACBSDA);
+
+			iface->state = state_read;
+		} else {
+			outb(iface->address_byte, ACBSDA);
+
+			iface->state = state_write;
+		}
+		break;
+
+	case state_read:
+		/* Set ACK if receiving the last byte */
+		if (iface->len == 1)
+			outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
+		else
+			outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
+
+		*iface->ptr++ = inb(ACBSDA);
+		--iface->len;
+
+		if (iface->len == 0) {
+			iface->result = 0;
+			iface->state = state_idle;
+			outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+		}
+
+		break;
+
+	case state_write:
+		if (iface->len == 0) {
+			iface->result = 0;
+			iface->state = state_idle;
+			outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+			break;
+		}
+		
+		outb(*iface->ptr++, ACBSDA);
+		--iface->len;
+		
+		break;
+	}
+
+	return;
+
+ negack:
+	DBG("negative acknowledge in state %s\n", 
+	    scx200_acb_state_name[iface->state]);
+
+	iface->state = state_idle;
+	iface->result = -ENXIO;
+
+	outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+	outb(ACBST_STASTR | ACBST_NEGACK, ACBST);
+	return;
+
+ error:
+	printk(KERN_ERR NAME ": %s, %s in state %s\n", iface->adapter.name, 
+	       errmsg, scx200_acb_state_name[iface->state]);
+
+	iface->state = state_idle;
+	iface->result = -EIO;
+	iface->needs_reset = 1;
+}
+
+static void scx200_acb_timeout(struct scx200_acb_iface *iface) 
+{
+	printk(KERN_ERR NAME ": %s, timeout in state %s\n", 
+	       iface->adapter.name, scx200_acb_state_name[iface->state]);
+
+	iface->state = state_idle;
+	iface->result = -EIO;
+	iface->needs_reset = 1;
+}
+
+#ifdef POLLED_MODE
+static void scx200_acb_poll(struct scx200_acb_iface *iface)
+{
+	u8 status = 0;
+	unsigned long timeout;
+
+	timeout = jiffies + POLL_TIMEOUT;
+	while (time_before(jiffies, timeout)) {
+		status = inb(ACBST);
+		if ((status & (ACBST_SDAST|ACBST_BER|ACBST_NEGACK)) != 0) {
+			scx200_acb_machine(iface, status);
+			return;
+		}
+		yield();
+	}
+
+	scx200_acb_timeout(iface);
+}
+#endif /* POLLED_MODE */
+
+static void scx200_acb_reset(struct scx200_acb_iface *iface)
+{
+	/* Disable the ACCESS.bus device and Configure the SCL
+           frequency: 16 clock cycles */
+	outb(0x70, ACBCTL2);
+	/* Polling mode */
+	outb(0, ACBCTL1);
+	/* Disable slave address */
+	outb(0, ACBADDR);
+	/* Enable the ACCESS.bus device */
+	outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
+	/* Free STALL after START */
+	outb(inb(ACBCTL1) & ~(ACBCTL1_STASTRE | ACBCTL1_NMINTE), ACBCTL1);
+	/* Send a STOP */
+	outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+	/* Clear BER, NEGACK and STASTR bits */
+	outb(ACBST_BER | ACBST_NEGACK | ACBST_STASTR, ACBST);
+	/* Clear BB bit */
+	outb(inb(ACBCST) | ACBCST_BB, ACBCST);
+}
+
+static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter,
+				u16 address, unsigned short flags,	
+				char rw, u8 command, int size, 
+				union i2c_smbus_data *data)
+{
+	struct scx200_acb_iface *iface = adapter->data;
+	int len;
+	u8 *buffer;
+	u16 cur_word;
+	int rc;
+
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+	    	len = 0;
+	    	buffer = NULL;
+	    	break;
+	case I2C_SMBUS_BYTE:
+		if (rw == I2C_SMBUS_READ) {
+			len = 1;
+			buffer = &data->byte;
+		} else {
+			len = 1;
+			buffer = &command;
+		}
+	    	break;
+	case I2C_SMBUS_BYTE_DATA:
+	    	len = 1;
+	    	buffer = &data->byte;
+	    	break;
+	case I2C_SMBUS_WORD_DATA:
+		len = 2;
+	    	cur_word = cpu_to_le16(data->word);
+	    	buffer = (u8 *)&cur_word;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+	    	len = data->block[0];
+	    	buffer = &data->block[1];
+		break;
+	default:
+	    	return -EINVAL;
+	}
+
+	DBG("size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n",
+	    size, address, command, len, rw == I2C_SMBUS_READ);
+
+	if (!len && rw == I2C_SMBUS_READ) {
+		printk(KERN_WARNING NAME ": %s, zero length read\n", 
+		       adapter->name);
+		return -EINVAL;
+	}
+
+	if (len && !buffer) {
+		printk(KERN_WARNING NAME ": %s, nonzero length but no buffer\n", adapter->name);
+		return -EFAULT;
+	}
+
+	down(&iface->sem);
+
+	iface->address_byte = address<<1;
+	if (rw == I2C_SMBUS_READ)
+		iface->address_byte |= 1;
+	iface->command = command;
+	iface->ptr = buffer;
+	iface->len = len;
+	iface->result = -EINVAL;
+	iface->needs_reset = 0;
+
+	outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+
+	if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE)
+		iface->state = state_quick;
+	else
+		iface->state = state_address;
+
+#ifdef POLLED_MODE
+	while (iface->state != state_idle)
+		scx200_acb_poll(iface);
+#else /* POLLED_MODE */
+#error Interrupt driven mode not implemented
+#endif /* POLLED_MODE */	
+
+	if (iface->needs_reset)
+		scx200_acb_reset(iface);
+
+	rc = iface->result;
+
+	up(&iface->sem);
+
+	if (rc == 0 && size == I2C_SMBUS_WORD_DATA && rw == I2C_SMBUS_READ)
+	    	data->word = le16_to_cpu(cur_word);
+
+#if DEBUG
+	printk(KERN_DEBUG NAME ": transfer done, result: %d", rc);
+	if (buffer) {
+		int i;
+		printk(" data:");
+		for (i = 0; i < len; ++i)
+			printk(" %02x", buffer[i]);
+	}
+	printk("\n");
+#endif
+
+	return rc;
+}
+
+static u32 scx200_acb_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	       I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static int scx200_acb_reg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static int scx200_acb_unreg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static void scx200_acb_inc_use(struct i2c_adapter *adapter)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void scx200_acb_dec_use(struct i2c_adapter *adapter)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+/* For now, we only handle combined mode (smbus) */
+static struct i2c_algorithm scx200_acb_algorithm = {
+	name:		"NatSemi SCx200 ACCESS.bus",
+	id:		I2C_ALGO_SMBUS,
+	smbus_xfer:	scx200_acb_smbus_xfer,
+	functionality:	scx200_acb_func,
+};
+
+struct scx200_acb_iface *scx200_acb_list;
+
+int scx200_acb_probe(struct scx200_acb_iface *iface)
+{
+	u8 val;
+
+	/* Disable the ACCESS.bus device and Configure the SCL
+           frequency: 16 clock cycles */
+	outb(0x70, ACBCTL2);
+
+	if (inb(ACBCTL2) != 0x70) {
+		DBG("ACBCTL2 readback failed\n");
+		return -ENXIO;
+	}
+
+	outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
+
+	val = inb(ACBCTL1);
+	if (val) {
+		DBG("disabled, but ACBCTL1=0x%02x\n", val);
+		return -ENXIO;
+	}
+
+	outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
+
+	outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
+
+	val = inb(ACBCTL1);
+	if ((val & ACBCTL1_NMINTE) != ACBCTL1_NMINTE) {
+		DBG("enabled, but NMINTE won't be set, ACBCTL1=0x%02x\n", val);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static int  __init scx200_acb_create(int base, int index)
+{
+	struct scx200_acb_iface *iface;
+	struct i2c_adapter *adapter;
+	int rc = 0;
+	char description[64];
+
+	iface = kmalloc(sizeof(*iface), GFP_KERNEL);
+	if (!iface) {
+		printk(KERN_ERR NAME ": can't allocate memory\n");
+		rc = -ENOMEM;
+		goto errout;
+	}
+
+	memset(iface, 0, sizeof(*iface));
+	adapter = &iface->adapter;
+	adapter->data = iface;
+	sprintf(adapter->name, "SCx200 ACB%d", index);
+	adapter->id = I2C_ALGO_SMBUS;
+	adapter->algo = &scx200_acb_algorithm;
+	adapter->inc_use = scx200_acb_inc_use;
+	adapter->dec_use = scx200_acb_dec_use;
+	adapter->client_register = scx200_acb_reg;
+	adapter->client_unregister = scx200_acb_unreg;
+
+	init_MUTEX(&iface->sem);
+
+	sprintf(description, "NatSemi SCx200 ACCESS.bus [%s]", adapter->name);
+	if (request_region(base, 8, description) == 0) {
+		printk(KERN_ERR NAME ": %s, can't allocate io 0x%x-0x%x\n", 
+		       adapter->name, base, base + 8-1);
+		rc = -EBUSY;
+		goto errout;
+	}
+	iface->base = base;
+
+	rc = scx200_acb_probe(iface);
+	if (rc) {
+		printk(KERN_WARNING NAME ": %s, probe failed\n", adapter->name);
+		goto errout;
+	}
+
+	scx200_acb_reset(iface);
+
+	if (i2c_add_adapter(adapter) < 0) {
+		printk(KERN_ERR NAME ": %s, failed to register\n", adapter->name);
+		rc = -ENODEV;
+		goto errout;
+	}
+
+	lock_kernel();
+	iface->next = scx200_acb_list;
+	scx200_acb_list = iface;
+	unlock_kernel();
+
+	return 0;
+
+ errout:
+	if (iface) {
+		if (iface->base)
+			release_region(iface->base, 8);
+		kfree(iface);
+	}
+	return rc;
+}
+
+static int __init scx200_acb_init(void)
+{
+	int i;
+	int rc;
+
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
+
+	/* Verify that this really is a SCx200 processor */
+	if (pci_find_device(PCI_VENDOR_ID_NS,
+			    PCI_DEVICE_ID_NS_SCx200_BRIDGE,
+			    NULL) == NULL)
+		return -ENODEV;
+
+	rc = -ENXIO;
+	for (i = 0; i < MAX_DEVICES; ++i) {
+		if (base[i] > 0)
+			rc = scx200_acb_create(base[i], i);
+	}
+	if (scx200_acb_list)
+		return 0;
+	return rc;
+}
+
+static void __exit scx200_acb_cleanup(void)
+{
+	struct scx200_acb_iface *iface;
+	lock_kernel();
+	while ((iface = scx200_acb_list) != NULL) {
+		scx200_acb_list = iface->next;
+		unlock_kernel();
+
+		i2c_del_adapter(&iface->adapter);
+		release_region(iface->base, 8);
+		kfree(iface);
+		lock_kernel();
+	}
+	unlock_kernel();
+}
+
+module_init(scx200_acb_init);
+module_exit(scx200_acb_cleanup);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
+        c-basic-offset: 8
+    End:
+*/
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/i2c/scx200_i2c.c linux-2.4.21/drivers/i2c/scx200_i2c.c
--- linux-2.4.20/drivers/i2c/scx200_i2c.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/i2c/scx200_i2c.c	2002-12-18 18:58:08.000000000 +0000
@@ -0,0 +1,156 @@
+/* linux/drivers/i2c/scx200_i2c.c 
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   National Semiconductor SCx200 I2C bus on GPIO pins
+
+   Based on i2c-velleman.c Copyright (C) 1995-96, 2000 Simon G. Vogl
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		     
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <asm/io.h>
+
+#include <linux/scx200_gpio.h>
+
+#define NAME "scx200_i2c"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 I2C Driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(scl, "i");
+MODULE_PARM_DESC(scl, "GPIO line for SCL");
+MODULE_PARM(sda, "i");
+MODULE_PARM_DESC(sda, "GPIO line for SDA");
+
+static int scl = CONFIG_SCx200_I2C_SCL;
+static int sda = CONFIG_SCx200_I2C_SDA;
+
+static void scx200_i2c_setscl(void *data, int state)
+{
+	scx200_gpio_set(scl, state);
+}
+
+static void scx200_i2c_setsda(void *data, int state)
+{
+	scx200_gpio_set(sda, state);
+} 
+
+static int scx200_i2c_getscl(void *data)
+{
+	return scx200_gpio_get(scl);
+}
+
+static int scx200_i2c_getsda(void *data)
+{
+	return scx200_gpio_get(sda);
+}
+
+static int scx200_i2c_reg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static int scx200_i2c_unreg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static void scx200_i2c_inc_use(struct i2c_adapter *adap)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void scx200_i2c_dec_use(struct i2c_adapter *adap)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+/* ------------------------------------------------------------------------
+ * Encapsulate the above functions in the correct operations structure.
+ * This is only done when more than one hardware adapter is supported.
+ */
+
+static struct i2c_algo_bit_data scx200_i2c_data = {
+	NULL,
+	scx200_i2c_setsda,
+	scx200_i2c_setscl,
+	scx200_i2c_getsda,
+	scx200_i2c_getscl,
+	10, 10, 100,		/* waits, timeout */
+};
+
+static struct i2c_adapter scx200_i2c_ops = {
+	.name              = "NatSemi SCx200 I2C",
+	.id		   = I2C_HW_B_VELLE,
+	.algo_data	   = &scx200_i2c_data,
+	.inc_use	   = scx200_i2c_inc_use,
+	.dec_use	   = scx200_i2c_dec_use,
+	.client_register   = scx200_i2c_reg,
+	.client_unregister = scx200_i2c_unreg,
+};
+
+int scx200_i2c_init(void)
+{
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 I2C Driver\n");
+
+	if (!scx200_gpio_present()) {
+		printk(KERN_ERR NAME ": no SCx200 gpio pins available\n");
+		return -ENODEV;
+	}
+
+	printk(KERN_DEBUG NAME ": SCL=GPIO%02u, SDA=GPIO%02u\n", 
+	       scl, sda);
+
+	if (scl == -1 || sda == -1 || scl == sda) {
+		printk(KERN_ERR NAME ": scl and sda must be specified\n");
+		return -EINVAL;
+	}
+
+	/* Configure GPIOs as open collector outputs */
+	scx200_gpio_configure(scl, ~2, 5);
+	scx200_gpio_configure(sda, ~2, 5);
+
+	if (i2c_bit_add_bus(&scx200_i2c_ops) < 0) {
+		printk(KERN_ERR NAME ": adapter %s registration failed\n", 
+		       scx200_i2c_ops.name);
+		return -ENODEV;
+	}
+	
+	return 0;
+}
+
+void scx200_i2c_cleanup(void)
+{
+	i2c_bit_del_bus(&scx200_i2c_ops);
+}
+
+module_init(scx200_i2c_init);
+module_exit(scx200_i2c_cleanup);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
+        c-basic-offset: 8
+    End:
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/Config.in linux-2.4.21/drivers/ide/Config.in
--- linux-2.4.20/drivers/ide/Config.in	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ide/Config.in	2002-12-18 18:58:11.000000000 +0000
@@ -16,17 +16,6 @@
    dep_mbool '    Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE $CONFIG_BLK_DEV_IDEDISK
    dep_mbool '    Auto-Geometry Resizing support' CONFIG_IDEDISK_STROKE $CONFIG_BLK_DEV_IDEDISK
 
-   define_bool CONFIG_BLK_DEV_IDEDISK_VENDOR n
-   dep_mbool '    Fujitsu Vendor Specific' CONFIG_BLK_DEV_IDEDISK_FUJITSU $CONFIG_BLK_DEV_IDEDISK_VENDOR
-   dep_mbool '    IBM Vendor Specific' CONFIG_BLK_DEV_IDEDISK_IBM $CONFIG_BLK_DEV_IDEDISK_VENDOR
-   dep_mbool '    Maxtor Vendor Specific' CONFIG_BLK_DEV_IDEDISK_MAXTOR $CONFIG_BLK_DEV_IDEDISK_VENDOR
-   dep_mbool '    Quantum Vendor Specific' CONFIG_BLK_DEV_IDEDISK_QUANTUM $CONFIG_BLK_DEV_IDEDISK_VENDOR
-   dep_mbool '    Seagate Vendor Specific' CONFIG_BLK_DEV_IDEDISK_SEAGATE $CONFIG_BLK_DEV_IDEDISK_VENDOR
-   dep_mbool '    Western Digital Vendor Specific' CONFIG_BLK_DEV_IDEDISK_WD $CONFIG_BLK_DEV_IDEDISK_VENDOR
-
-   define_bool CONFIG_BLK_DEV_COMMERIAL n
-   dep_mbool '    TiVo Commerial Application Specific' CONFIG_BLK_DEV_TIVO $CONFIG_BLK_DEV_COMMERIAL
-
    dep_tristate '  PCMCIA IDE support' CONFIG_BLK_DEV_IDECS $CONFIG_BLK_DEV_IDE $CONFIG_PCMCIA
    dep_tristate '  Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE
    dep_tristate '  Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
@@ -34,7 +23,7 @@
    dep_tristate '  SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE $CONFIG_SCSI
 
    bool '  IDE Taskfile Access' CONFIG_IDE_TASK_IOCTL
-#   bool '  IDE Taskfile IO' CONFIG_IDE_TASKFILE_IO
+   bool '  IDE Taskfile IO' CONFIG_IDE_TASKFILE_IO
 
    comment 'IDE chipset support/bugfixes'
    if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
@@ -42,9 +31,9 @@
       dep_bool '    CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED $CONFIG_BLK_DEV_CMD640
       dep_bool '  ISA-PNP EIDE support' CONFIG_BLK_DEV_ISAPNP $CONFIG_ISAPNP
       if [ "$CONFIG_PCI" = "y" ]; then
-	 dep_bool '  RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_X86
-	 bool '  Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI
+	 bool '  PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI
 	 if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
+	    dep_bool '    Generic PCI IDE Chipset Support' CONFIG_BLK_DEV_GENERIC $CONFIG_BLK_DEV_IDEPCI
 	    bool '    Sharing PCI IDE interrupts support' CONFIG_IDEPCI_SHARE_IRQ
 	    bool '    Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI
 	    bool '    Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
@@ -53,46 +42,42 @@
             dep_bool '    Enable DMA only for disks ' CONFIG_IDEDMA_ONLYDISK $CONFIG_IDEDMA_PCI_AUTO
 	    define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '      ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
-	    dep_bool '      Attempt to HACK around Chipsets that TIMEOUT (WIP)' CONFIG_BLK_DEV_IDEDMA_TIMEOUT $CONFIG_IDEDMA_PCI_WIP
-	    dep_bool '      Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP
-#	    dep_bool '      Asynchronous DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL
-	    define_bool CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI
-#	    dep_bool '      Tag Command Queue DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDMA_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL
-
-	    dep_bool '    AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_mbool '      AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX
-	    dep_bool '    ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_mbool '      ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3
-	    dep_bool '    AMD Viper support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_mbool '      AMD Viper ATA-66 Override (WIP)' CONFIG_AMD74XX_OVERRIDE $CONFIG_BLK_DEV_AMD74XX $CONFIG_IDEDMA_PCI_WIP
-	    dep_bool '    CMD64X and CMD680 chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_bool '    CMD680 chipset tuning support' CONFIG_BLK_DEV_CMD680 $CONFIG_BLK_DEV_CMD64X
-	    dep_bool '    CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_bool '    Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI
-  	    dep_bool '    HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_mbool '      HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_IDEDMA_PCI_WIP
-	    dep_bool '    HPT366/368/370 chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
-	    if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" -o "$CONFIG_MIPS" = "y" ]; then
-	       dep_mbool '    Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI
-	       dep_mbool '      PIIXn Tuning support' CONFIG_PIIX_TUNING $CONFIG_BLK_DEV_PIIX $CONFIG_IDEDMA_PCI_AUTO
-	    fi
+#	    dep_bool '      Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP
+            define_bool CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI
+
+	    dep_tristate '    AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_mbool    '      ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3
+	    dep_tristate '    AMD Viper support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_mbool    '      AMD Viper ATA-66 Override' CONFIG_AMD74XX_OVERRIDE $CONFIG_BLK_DEV_AMD74XX
+	    dep_tristate '    CMD64{3|6|8|9} chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI
+  	    dep_tristate '    HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_mbool    '      HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_IDEDMA_PCI_WIP
+	    dep_tristate '    HPT366/368/370 chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI
 	    if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then
 	       dep_mbool '    IT8172 IDE support' CONFIG_BLK_DEV_IT8172 $CONFIG_BLK_DEV_IDEDMA_PCI
-	       dep_mbool '      IT8172 IDE Tuning support' CONFIG_IT8172_TUNING $CONFIG_BLK_DEV_IT8172 $CONFIG_IDEDMA_PCI_AUTO
 	    fi
-	    dep_bool '    NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
-	    dep_bool '    OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL
-#	    dep_mbool '   Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_BLK_DEV_ADMA $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL
-	    dep_bool '    PROMISE PDC202{46|62|65|67|68|69|70} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_bool '      Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX
-	    dep_bool '      Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX
-	    dep_bool '    ServerWorks OSB4/CSB5 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
-	    dep_bool '    SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
-	    dep_bool '    SLC90E66 chipset support' CONFIG_BLK_DEV_SLC90E66 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
-	    dep_bool '    Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
-	    dep_bool '    VIA82CXXX chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    nVidia NFORCE support' CONFIG_BLK_DEV_NFORCE $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    NS87415 chipset support' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL
+	    dep_tristate '    PROMISE PDC202{46|62|65|67} support' CONFIG_BLK_DEV_PDC202XX_OLD $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool     '      Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX_OLD $CONFI_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    PROMISE PDC202{68|69|70|71|75|76|77} support' CONFIG_BLK_DEV_PDC202XX_NEW $CONFIG_BLK_DEV_IDEDMA_PCI
+		# FIXME - probably wants to be one for old and for new
+	    dep_bool     '      Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX_NEW
+	    dep_tristate '    RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_X86
+	    dep_tristate '    SCx200 chipset support' CONFIG_BLK_DEV_SC1200 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    ServerWorks OSB4/CSB5/CSB6 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    Silicon Image chipset support' CONFIG_BLK_DEV_SIIMAGE $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
+	    dep_tristate '    SLC90E66 chipset support' CONFIG_BLK_DEV_SLC90E66 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    Tekram TRM290 chipset support' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    VIA82CXXX chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI
 	    if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
-	       bool '    Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
+	       dep_tristate '    Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 $CONFIG_BLK_DEV_IDEPCI
 	    fi
          fi
       fi
@@ -149,14 +134,12 @@
       if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
 	 comment 'Note: most of these also require special kernel boot parameters'
 	 bool '    Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES
-	 bool '    ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
-	 bool '    DTC-2278 support' CONFIG_BLK_DEV_DTC2278
-	 bool '    Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
-	 if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-	    bool '    PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
-	 fi
-	 bool '    QDI QD65xx support' CONFIG_BLK_DEV_QD65XX
-	 bool '    UMC-8672 support' CONFIG_BLK_DEV_UMC8672
+	 dep_tristate '    ALI M14xx support' CONFIG_BLK_DEV_ALI14XX $CONFIG_BLK_DEV_IDE
+	 dep_tristate '    DTC-2278 support' CONFIG_BLK_DEV_DTC2278 $CONFIG_BLK_DEV_IDE
+	 dep_tristate '    Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B $CONFIG_BLK_DEV_IDE
+	 dep_tristate '    PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030 $CONFIG_BLK_DEV_IDEDISK $CONFIG_EXPERIMENTAL
+	 dep_tristate '    QDI QD65xx support' CONFIG_BLK_DEV_QD65XX $CONFIG_BLK_DEV_IDE
+	 dep_tristate '    UMC-8672 support' CONFIG_BLK_DEV_UMC8672 $CONFIG_BLK_DEV_IDE
       fi
    fi
 else
@@ -184,7 +167,26 @@
   define_bool CONFIG_DMA_NONPCI n
 fi
 
-if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
+if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
+   if [ "$CONFIG_BLK_DEV_PDC202XX_OLD" != "n" -o \
+        "$CONFIG_BLK_DEV_PDC202XX_NEW" != "n" ]; then
+      define_bool CONFIG_BLK_DEV_PDC202XX y
+   fi
+fi
+
+##if [ "$CONFIG_IDE_TASKFILE_IO" = "y" ]; then
+##  dep_mbool CONFIG_BLK_DEV_TF_DISK $CONFIG_BLK_DEV_IDEDISK
+##else
+##  dep_mbool CONFIG_BLK_DEV_NTF_DISK $CONFIG_BLK_DEV_IDEDISK
+##fi
+
+if [ "$CONFIG_BLK_DEV_4DRIVES" = "y" -o \
+     "$CONFIG_BLK_DEV_ALI14XX" != "n" -o \
+     "$CONFIG_BLK_DEV_DTC2278" != "n" -o \
+     "$CONFIG_BLK_DEV_HT6560B" != "n" -o \
+     "$CONFIG_BLK_DEV_PDC4030" != "n" -o \
+     "$CONFIG_BLK_DEV_QD65XX" != "n" -o \
+     "$CONFIG_BLK_DEV_UMC8672" != "n" -o \
      "$CONFIG_BLK_DEV_AEC62XX" = "y" -o \
      "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \
      "$CONFIG_BLK_DEV_AMD74XX" = "y" -o \
@@ -195,16 +197,19 @@
      "$CONFIG_BLK_DEV_HPT34X" = "y" -o \
      "$CONFIG_BLK_DEV_HPT366" = "y" -o \
      "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \
+     "$CONFIG_BLK_DEV_IT8172" = "y" -o \
+     "$CONFIG_BLK_DEV_MPC8xx_IDE" = "y" -o \
+     "$CONFIG_BLK_DEV_NFORCE" = "y" -o \
      "$CONFIG_BLK_DEV_OPTI621" = "y" -o \
      "$CONFIG_BLK_DEV_SVWKS" = "y" -o \
      "$CONFIG_BLK_DEV_PDC202XX" = "y" -o \
      "$CONFIG_BLK_DEV_PIIX" = "y" -o \
-     "$CONFIG_BLK_DEV_IT8172" = "y" -o \
+     "$CONFIG_BLK_DEV_SVWKS" = "y" -o \
+     "$CONFIG_BLK_DEV_SIIMAGE" = "y" -o \
      "$CONFIG_BLK_DEV_SIS5513" = "y" -o \
-     "$CONFIG_BLK_DEV_SLC90E66" = "y" -o \
      "$CONFIG_BLK_DEV_SL82C105" = "y" -o \
-     "$CONFIG_BLK_DEV_VIA82CXXX" = "y" -o \
-     "$CONFIG_BLK_DEV_MPC8xx_IDE" = "y" ]; then
+     "$CONFIG_BLK_DEV_SLC90E66" = "y" -o \
+     "$CONFIG_BLK_DEV_VIA82CXXX" = "y" ]; then
    define_bool CONFIG_BLK_DEV_IDE_MODES y
 else
    define_bool CONFIG_BLK_DEV_IDE_MODES n
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/Makefile linux-2.4.21/drivers/ide/Makefile
--- linux-2.4.20/drivers/ide/Makefile	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ide/Makefile	2002-12-18 18:58:10.000000000 +0000
@@ -10,80 +10,50 @@
 
 O_TARGET := idedriver.o
 
-export-objs		:= ide.o ide-features.o ide-probe.o ide-taskfile.o ataraid.o
-list-multi		:= ide-mod.o ide-probe-mod.o
+export-objs := ide-iops.o ide-taskfile.o ide-proc.o ide.o ide-probe.o ide-dma.o ide-lib.o setup-pci.o ide-io.o
+
+all-subdirs	:= arm legacy pci ppc raid
+mod-subdirs	:= arm legacy pci ppc raid
 
 obj-y		:=
 obj-m		:=
 ide-obj-y	:=
 
-obj-$(CONFIG_BLK_DEV_HD)	+= hd.o
-obj-$(CONFIG_BLK_DEV_IDE)       += ide-mod.o ide-probe-mod.o
-obj-$(CONFIG_BLK_DEV_IDECS)     += ide-cs.o
-obj-$(CONFIG_BLK_DEV_IDEDISK)   += ide-disk.o
-obj-$(CONFIG_BLK_DEV_IDECD)     += ide-cd.o
-obj-$(CONFIG_BLK_DEV_IDETAPE)   += ide-tape.o
-obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o
-
-obj-$(CONFIG_BLK_DEV_IT8172)    += it8172.o
-
-ide-obj-$(CONFIG_BLK_DEV_AEC62XX)	+= aec62xx.o
-ide-obj-$(CONFIG_BLK_DEV_ALI14XX)	+= ali14xx.o
-ide-obj-$(CONFIG_BLK_DEV_ALI15X3)	+= alim15x3.o
-ide-obj-$(CONFIG_BLK_DEV_AMD74XX)	+= amd74xx.o
-ide-obj-$(CONFIG_BLK_DEV_BUDDHA)	+= buddha.o
-ide-obj-$(CONFIG_BLK_DEV_CMD640)	+= cmd640.o
-ide-obj-$(CONFIG_BLK_DEV_CMD64X)	+= cmd64x.o
-ide-obj-$(CONFIG_BLK_DEV_CS5530)	+= cs5530.o
-ide-obj-$(CONFIG_BLK_DEV_CY82C693)	+= cy82c693.o
-ide-obj-$(CONFIG_BLK_DEV_DTC2278)	+= dtc2278.o
-ide-obj-$(CONFIG_BLK_DEV_FALCON_IDE)	+= falconide.o
-ide-obj-$(CONFIG_BLK_DEV_GAYLE)		+= gayle.o
-ide-obj-$(CONFIG_BLK_DEV_Q40IDE)	+= q40ide.o
-ide-obj-$(CONFIG_BLK_DEV_HPT34X)	+= hpt34x.o
-ide-obj-$(CONFIG_BLK_DEV_HPT366)	+= hpt366.o
-ide-obj-$(CONFIG_BLK_DEV_HT6560B)	+= ht6560b.o
-ide-obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
-ide-obj-$(CONFIG_BLK_DEV_ADMA)		+= ide-adma.o
-ide-obj-$(CONFIG_BLK_DEV_IDEDMA_PCI)	+= ide-dma.o
-ide-obj-$(CONFIG_BLK_DEV_IDEPCI)	+= ide-pci.o
-ide-obj-$(CONFIG_BLK_DEV_ISAPNP)	+= ide-pnp.o
-ide-obj-$(CONFIG_BLK_DEV_IDE_PMAC)	+= ide-pmac.o
-ide-obj-$(CONFIG_BLK_DEV_IDE_SIBYTE)	+= ide-sibyte.o
-ide-obj-$(CONFIG_BLK_DEV_MAC_IDE)	+= macide.o
-ide-obj-$(CONFIG_BLK_DEV_NS87415)	+= ns87415.o
-ide-obj-$(CONFIG_BLK_DEV_OPTI621)	+= opti621.o
-ide-obj-$(CONFIG_BLK_DEV_SVWKS)		+= serverworks.o
-ide-obj-$(CONFIG_BLK_DEV_PDC202XX)	+= pdc202xx.o
-ide-obj-$(CONFIG_BLK_DEV_PDC4030)	+= pdc4030.o
-ide-obj-$(CONFIG_BLK_DEV_PDC_ADMA)	+= pdcadma.o
-ide-obj-$(CONFIG_BLK_DEV_PIIX)		+= piix.o
-ide-obj-$(CONFIG_BLK_DEV_QD65XX)	+= qd65xx.o
-ide-obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)	+= rapide.o
-ide-obj-$(CONFIG_BLK_DEV_RZ1000)	+= rz1000.o
-ide-obj-$(CONFIG_BLK_DEV_SIS5513)	+= sis5513.o
-ide-obj-$(CONFIG_BLK_DEV_SLC90E66)	+= slc90e66.o
-ide-obj-$(CONFIG_BLK_DEV_SL82C105)	+= sl82c105.o
-ide-obj-$(CONFIG_BLK_DEV_TRM290)	+= trm290.o
-ide-obj-$(CONFIG_BLK_DEV_UMC8672)	+= umc8672.o
-ide-obj-$(CONFIG_BLK_DEV_VIA82CXXX)	+= via82cxxx.o
-ide-obj-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= ide-m8xx.o
-
-# The virtualised raid layers MUST come after the ide itself or bad stuff
-# will happen.
-obj-$(CONFIG_BLK_DEV_ATARAID)		+= ataraid.o
-obj-$(CONFIG_BLK_DEV_ATARAID_PDC)	+= pdcraid.o
-obj-$(CONFIG_BLK_DEV_ATARAID_HPT)	+= hptraid.o
+subdir-$(CONFIG_BLK_DEV_IDE) += legacy ppc arm raid pci
 
-ide-obj-$(CONFIG_PROC_FS)		+= ide-proc.o
+# First come modules that register themselves with the core
 
-ide-mod-objs		:= ide.o ide-features.o ide-taskfile.o $(ide-obj-y)
-ide-probe-mod-objs	:= ide-probe.o ide-geometry.o
+ifeq ($(CONFIG_BLK_DEV_IDE),y)
+  obj-y		+= pci/idedriver-pci.o
+endif
+
+# Core IDE code - must come before legacy
+
+obj-$(CONFIG_BLK_DEV_IDE)		+= ide-probe.o ide-geometry.o ide-iops.o ide-taskfile.o ide.o ide-lib.o ide-io.o
+obj-$(CONFIG_BLK_DEV_IDEDISK)		+= ide-disk.o
+obj-$(CONFIG_BLK_DEV_IDECD)		+= ide-cd.o
+obj-$(CONFIG_BLK_DEV_IDETAPE)		+= ide-tape.o
+obj-$(CONFIG_BLK_DEV_IDEFLOPPY)		+= ide-floppy.o
+
+obj-$(CONFIG_BLK_DEV_IDEPCI)		+= setup-pci.o
+obj-$(CONFIG_BLK_DEV_IDEDMA_PCI)	+= ide-dma.o
+obj-$(CONFIG_BLK_DEV_ISAPNP)		+= ide-pnp.o
 
-include $(TOPDIR)/Rules.make
 
-ide-mod.o: $(ide-mod-objs)
-	$(LD) -r -o $@ $(ide-mod-objs)
+ifeq ($(CONFIG_BLK_DEV_IDE),y)
+obj-$(CONFIG_PROC_FS)			+= ide-proc.o
+endif
 
-ide-probe-mod.o: $(ide-probe-mod-objs)
-	$(LD) -r -o $@ $(ide-probe-mod-objs)
+ifeq ($(CONFIG_BLK_DEV_IDE),y)
+  obj-y		+= legacy/idedriver-legacy.o
+  obj-y		+= ppc/idedriver-ppc.o
+  obj-y		+= arm/idedriver-arm.o
+endif
+
+
+ifeq ($(CONFIG_BLK_DEV_IDE),y)
+# RAID must be last of all
+  obj-y		+= raid/idedriver-raid.o
+endif
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/aec62xx.c linux-2.4.21/drivers/ide/aec62xx.c
--- linux-2.4.20/drivers/ide/aec62xx.c	2000-06-20 14:52:36.000000000 +0000
+++ linux-2.4.21/drivers/ide/aec62xx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,582 +0,0 @@
-/*
- * linux/drivers/ide/aec62xx.c		Version 0.09	June. 9, 2000
- *
- * Copyright (C) 1999-2000	Andre Hedrick (andre@linux-ide.org)
- * May be copied or modified under the terms of the GNU General Public License
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_AEC62XX_TIMINGS
-
-#ifndef HIGH_4
-#define HIGH_4(H)		((H)=(H>>4))
-#endif
-#ifndef LOW_4
-#define LOW_4(L)		((L)=(L-((L>>4)<<4)))
-#endif
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-#ifndef MAKE_WORD
-#define MAKE_WORD(W,HB,LB)	((W)=((HB<<8)+LB))
-#endif
-
-
-#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int aec62xx_get_info(char *, char **, off_t, int);
-extern int (*aec62xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-
-static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-	u8 c0 = 0, c1 = 0;
-	u8 art = 0, uart = 0;
-
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			p += sprintf(p, "\n                                AEC6210 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-			p += sprintf(p, "\n                                AEC6260 No Bios Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			p += sprintf(p, "\n                                AEC6260 Chipset.\n");
-			break;
-		default:
-			p += sprintf(p, "\n                                AEC62?? Chipset.\n");
-			break;
-	}
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	(void) pci_read_config_byte(bmide_dev, 0x4a, &art);
-	p += sprintf(p, "                %sabled                         %sabled\n",
-		(art&0x02)?" en":"dis",(art&0x04)?" en":"dis");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	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 ");
-
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			(void) pci_read_config_byte(bmide_dev, 0x54, &art);
-			p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)         %s(%s)           %s(%s)\n",
-				(c0&0x20)?((art&0x03)?"UDMA":" DMA"):" PIO",
-				(art&0x02)?"2":(art&0x01)?"1":"0",
-				(c0&0x40)?((art&0x0c)?"UDMA":" DMA"):" PIO",
-				(art&0x08)?"2":(art&0x04)?"1":"0",
-				(c1&0x20)?((art&0x30)?"UDMA":" DMA"):" PIO",
-				(art&0x20)?"2":(art&0x10)?"1":"0",
-				(c1&0x40)?((art&0xc0)?"UDMA":" DMA"):" PIO",
-				(art&0x80)?"2":(art&0x40)?"1":"0");
-			(void) pci_read_config_byte(bmide_dev, 0x40, &art);
-			p += sprintf(p, "Active:         0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x42, &art);
-			p += sprintf(p, "             0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x44, &art);
-			p += sprintf(p, "            0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x46, &art);
-			p += sprintf(p, "              0x%02x\n", art);
-			(void) pci_read_config_byte(bmide_dev, 0x41, &art);
-			p += sprintf(p, "Recovery:       0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x43, &art);
-			p += sprintf(p, "             0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x45, &art);
-			p += sprintf(p, "            0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x47, &art);
-			p += sprintf(p, "              0x%02x\n", art);
-			break;
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			(void) pci_read_config_byte(bmide_dev, 0x44, &art);
-			p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)",
-				(c0&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
-				((art&0x06)==0x06)?"4":((art&0x05)==0x05)?"4":((art&0x04)==0x04)?"3":((art&0x03)==0x03)?"2":((art&0x02)==0x02)?"1":((art&0x01)==0x01)?"0":"?",
-				(c0&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
-				((art&0x60)==0x60)?"4":((art&0x50)==0x50)?"4":((art&0x40)==0x40)?"3":((art&0x30)==0x30)?"2":((art&0x20)==0x20)?"1":((art&0x10)==0x10)?"0":"?");
-			(void) pci_read_config_byte(bmide_dev, 0x45, &art);
-			p += sprintf(p, "         %s(%s)           %s(%s)\n",
-				(c1&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
-				((art&0x06)==0x06)?"4":((art&0x05)==0x05)?"4":((art&0x04)==0x04)?"3":((art&0x03)==0x03)?"2":((art&0x02)==0x02)?"1":((art&0x01)==0x01)?"0":"?",
-				(c1&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
-				((art&0x60)==0x60)?"4":((art&0x50)==0x50)?"4":((art&0x40)==0x40)?"3":((art&0x30)==0x30)?"2":((art&0x20)==0x20)?"1":((art&0x10)==0x10)?"0":"?");
-			(void) pci_read_config_byte(bmide_dev, 0x40, &art);
-			p += sprintf(p, "Active:         0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x41, &art);
-			p += sprintf(p, "             0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x42, &art);
-			p += sprintf(p, "            0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x43, &art);
-			p += sprintf(p, "              0x%02x\n", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x40, &art);
-			p += sprintf(p, "Recovery:       0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x41, &art);
-			p += sprintf(p, "             0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x42, &art);
-			p += sprintf(p, "            0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x43, &art);
-			p += sprintf(p, "              0x%02x\n", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x49, &uart);
-			p += sprintf(p, "reg49h = 0x%02x ", uart);
-			(void) pci_read_config_byte(bmide_dev, 0x4a, &uart);
-			p += sprintf(p, "reg4ah = 0x%02x\n", uart);
-			break;
-		default:
-			break;
-	}
-
-	return p-buffer;/* => must be less than 4k! */
-}
-#endif	/* defined(DISPLAY_AEC62xx_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte aec62xx_proc = 0;
-
-#ifdef CONFIG_AEC62XX_TUNING
-
-struct chipset_bus_clock_list_entry {
-	byte		xfer_speed;
-
-	byte		chipset_settings_34;
-	byte		ultra_settings_34;
-
-	byte		chipset_settings_33;
-	byte		ultra_settings_33;
-};
-
-struct chipset_bus_clock_list_entry aec62xx_base [] = {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	{	XFER_UDMA_4,	0x41,	0x04,	0x31,	0x05	},
-	{	XFER_UDMA_3,	0x41,	0x03,	0x31,	0x04	},
-	{	XFER_UDMA_2,	0x41,	0x02,	0x31,	0x03	},
-	{	XFER_UDMA_1,	0x41,	0x01,	0x31,	0x02	},
-	{	XFER_UDMA_0,	0x41,	0x01,	0x31,	0x01	},
-
-	{	XFER_MW_DMA_2,	0x41,	0x00,	0x31,	0x00	},
-	{	XFER_MW_DMA_1,	0x42,	0x00,	0x31,	0x00	},
-	{	XFER_MW_DMA_0,	0x7a,	0x00,	0x0a,	0x00	},
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	{	XFER_PIO_4,	0x41,	0x00,	0x31,	0x00	},
-	{	XFER_PIO_3,	0x43,	0x00,	0x33,	0x00	},
-	{	XFER_PIO_2,	0x78,	0x00,	0x08,	0x00	},
-	{	XFER_PIO_1,	0x7a,	0x00,	0x0a,	0x00	},
-	{	XFER_PIO_0,	0x70,	0x00,	0x00,	0x00	},
-	{	0,		0x00,	0x00,	0x00,	0x00	}
-};
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/*
- * TO DO: active tuning and correction of cards without a bios.
- */
-
-static byte pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
-{
-	int bus_speed = system_bus_clock();
-
-	for ( ; chipset_table->xfer_speed ; chipset_table++)
-		if (chipset_table->xfer_speed == speed) {
-			return ((byte) ((bus_speed <= 33) ? chipset_table->chipset_settings_33 : chipset_table->chipset_settings_34));
-		}
-	return 0x00;
-}
-
-static byte pci_bus_clock_list_ultra (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
-{
-	int bus_speed = system_bus_clock();
-
-	for ( ; chipset_table->xfer_speed ; chipset_table++)
-		if (chipset_table->xfer_speed == speed) {
-			return ((byte) ((bus_speed <= 33) ? chipset_table->ultra_settings_33 : chipset_table->ultra_settings_34));
-		}
-	return 0x00;
-}
-
-static int aec6210_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	int err			= 0;
-	unsigned short d_conf	= 0x0000;
-	byte ultra		= 0x00;
-	byte ultra_conf		= 0x00;
-	byte tmp0		= 0x00;
-	byte tmp1		= 0x00;
-	byte tmp2		= 0x00;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf);
-	tmp0 = pci_bus_clock_list(speed, aec62xx_base);
-	SPLIT_BYTE(tmp0,tmp1,tmp2);
-	MAKE_WORD(d_conf,tmp1,tmp2);
-	pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf);
-
-	tmp1 = 0x00;
-	tmp2 = 0x00;
-	pci_read_config_byte(dev, 0x54, &ultra);
-	tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn))));
-	ultra_conf = pci_bus_clock_list_ultra(speed, aec62xx_base);
-	tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
-	pci_write_config_byte(dev, 0x54, tmp2);
-
-	__restore_flags(flags);	/* local CPU only */
-
-	err = ide_config_drive_speed(drive, speed);
-	return(err);
-}
-
-static int aec6260_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte unit		= (drive->select.b.unit & 0x01);
-	byte ultra_pci		= hwif->channel ? 0x45 : 0x44;
-	int err			= 0;
-	byte drive_conf		= 0x00;
-	byte ultra_conf		= 0x00;
-	byte ultra		= 0x00;
-	byte tmp1		= 0x00;
-	byte tmp2		= 0x00;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf);
-	drive_conf = pci_bus_clock_list(speed, aec62xx_base);
-	pci_write_config_byte(dev, 0x40|drive->dn, drive_conf);
-
-	pci_read_config_byte(dev, ultra_pci, &ultra);
-	tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit))));
-	ultra_conf = pci_bus_clock_list_ultra(speed, aec62xx_base);
-	tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
-	pci_write_config_byte(dev, ultra_pci, tmp2);
-	__restore_flags(flags);	/* local CPU only */
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return(err);
-}
-
-
-static int aec62xx_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
-		return ((int) aec6210_tune_chipset(drive, speed));
-	} else {
-		return ((int) aec6260_tune_chipset(drive, speed));
-	}
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_aec6210_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	byte unit		= (drive->select.b.unit & 0x01);
-	unsigned long dma_base	= hwif->dma_base;
-	byte speed		= -1;
-
-	if (drive->media != ide_disk)
-		return ((int) ide_dma_off_quietly);
-
-	if (((id->dma_ultra & 0x0010) ||
-	     (id->dma_ultra & 0x0008) ||
-	     (id->dma_ultra & 0x0004)) && (ultra)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_mword & 0x0001) {
-		speed = XFER_MW_DMA_0;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-	} else if (id->dma_1word & 0x0002) {
-		speed = XFER_SW_DMA_1;
-	} else if (id->dma_1word & 0x0001) {
-		speed = XFER_SW_DMA_0;
-	} else {
- 		return ((int) ide_dma_off_quietly);
- 	}
-
-	outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	(void) aec6210_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 3) ? ide_dma_off :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int config_aec6260_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	byte unit		= (drive->select.b.unit & 0x01);
-	unsigned long dma_base	= hwif->dma_base;
-	byte speed		= -1;
-	byte ultra66		= eighty_ninty_three(drive);
-
-	if (drive->media != ide_disk)
-		return ((int) ide_dma_off_quietly);
-
-	if ((id->dma_ultra & 0x0010) && (ultra) && (ultra66)) {
-		speed = XFER_UDMA_4;
-	} else if ((id->dma_ultra & 0x0008) && (ultra) && (ultra66)) {
-		speed = XFER_UDMA_3;
-	} else if ((id->dma_ultra & 0x0004) && (ultra)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_mword & 0x0001) {
-		speed = XFER_MW_DMA_0;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-	} else if (id->dma_1word & 0x0002) {
-		speed = XFER_SW_DMA_1;
-	} else if (id->dma_1word & 0x0001) {
-		speed = XFER_SW_DMA_0;
-	} else {
-		return ((int) ide_dma_off_quietly);
-	}
-
-	outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	(void) aec6260_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 3) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	switch(HWIF(drive)->pci_dev->device) {	
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			return config_aec6210_chipset_for_dma(drive, ultra);
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			return config_aec6260_chipset_for_dma(drive, ultra);
-		default:
-			return ((int) ide_dma_off_quietly);
-	}
-}
-
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-static void aec62xx_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-	byte new_pio = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-	switch(pio) {
-		case 5:		speed = new_pio; break;
-		case 4:		speed = XFER_PIO_4; break;
-		case 3:		speed = XFER_PIO_3; break;
-		case 2:		speed = XFER_PIO_2; break;
-		case 1:		speed = XFER_PIO_1; break;
-		default:	speed = XFER_PIO_0; break;
-	}
-
-	switch(HWIF(drive)->pci_dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			(void) aec6210_tune_chipset(drive, speed);
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			(void) aec6260_tune_chipset(drive, speed);
-		default:
-			break;
-        }
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x001F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive, 1);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive, 0);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive, 0);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		aec62xx_tune_drive(drive, 5);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * aec62xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- */
-int aec62xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_lostirq:
-		case ide_dma_timeout:
-			switch(HWIF(drive)->pci_dev->device) {
-				case PCI_DEVICE_ID_ARTOP_ATP860:
-				case PCI_DEVICE_ID_ARTOP_ATP860R:
-//					{
-//						int i = 0;
-//						byte reg49h = 0;
-//						pci_read_config_byte(HWIF(drive)->pci_dev, 0x49, &reg49h);
-//						for (i=0;i<256;i++)
-//							pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h|0x10);
-//						pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h & ~0x10);
-//					}
-//					return 0;
-				default:
-					break;
-			}
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-#endif /* CONFIG_AEC62XX_TUNING */
-
-unsigned int __init pci_init_aec62xx (struct pci_dev *dev, const char *name)
-{
-	if (dev->resource[PCI_ROM_RESOURCE].start) {
-		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
-	}
-
-#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!aec62xx_proc) {
-		aec62xx_proc = 1;
-		bmide_dev = dev;
-		aec62xx_display_info = &aec62xx_get_info;
-	}
-#endif /* DISPLAY_AEC62XX_TIMINGS && CONFIG_PROC_FS */
-
-	return dev->irq;
-}
-
-unsigned int __init ata66_aec62xx (ide_hwif_t *hwif)
-{
-	byte mask	= hwif->channel ? 0x02 : 0x01;
-	byte ata66	= 0;
-
-	pci_read_config_byte(hwif->pci_dev, 0x49, &ata66);
-	return ((ata66 & mask) ? 0 : 1);
-}
-
-void __init ide_init_aec62xx (ide_hwif_t *hwif)
-{
-#ifdef CONFIG_AEC62XX_TUNING
-	hwif->tuneproc = &aec62xx_tune_drive;
-	hwif->speedproc = &aec62xx_tune_chipset;
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base)
-		hwif->dmaproc = &aec62xx_dmaproc;
-#else /* !CONFIG_BLK_DEV_IDEDMA */
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-#endif /* CONFIG_AEC62XX_TUNING */
-}
-
-void __init ide_dmacapable_aec62xx (ide_hwif_t *hwif, unsigned long dmabase)
-{
-#ifdef CONFIG_AEC62XX_TUNING
-	unsigned long flags;
-	byte reg54h = 0;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
-	pci_write_config_byte(hwif->pci_dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F));
-
-	__restore_flags(flags);	/* local CPU only */
-#endif /* CONFIG_AEC62XX_TUNING */
-	ide_setup_dma(hwif, dmabase, 8);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ali14xx.c linux-2.4.21/drivers/ide/ali14xx.c
--- linux-2.4.20/drivers/ide/ali14xx.c	2001-07-15 23:22:23.000000000 +0000
+++ linux-2.4.21/drivers/ide/ali14xx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,226 +0,0 @@
-/*
- *  linux/drivers/ide/ali14xx.c		Version 0.03	Feb 09, 1996
- *
- *  Copyright (C) 1996  Linus Torvalds & author (see below)
- */
-
-/*
- * ALI M14xx chipset EIDE controller
- *
- * Works for ALI M1439/1443/1445/1487/1489 chipsets.
- *
- * Adapted from code developed by derekn@vw.ece.cmu.edu.  -ml
- * Derek's notes follow:
- *
- * I think the code should be pretty understandable,
- * but I'll be happy to (try to) answer questions.
- *
- * The critical part is in the setupDrive function.  The initRegisters
- * function doesn't seem to be necessary, but the DOS driver does it, so
- * I threw it in.
- *
- * I've only tested this on my system, which only has one disk.  I posted
- * it to comp.sys.linux.hardware, so maybe some other people will try it
- * out.
- *
- * Derek Noonburg  (derekn@ece.cmu.edu)
- * 95-sep-26
- *
- * Update 96-jul-13:
- *
- * I've since upgraded to two disks and a CD-ROM, with no trouble, and
- * I've also heard from several others who have used it successfully.
- * This driver appears to work with both the 1443/1445 and the 1487/1489
- * chipsets.  I've added support for PIO mode 4 for the 1487.  This
- * seems to work just fine on the 1443 also, although I'm not sure it's
- * advertised as supporting mode 4.  (I've been running a WDC AC21200 in
- * mode 4 for a while now with no trouble.)  -Derek
- */
-
-#undef REALLY_SLOW_IO           /* most systems can safely undef this */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/* port addresses for auto-detection */
-#define ALI_NUM_PORTS 4
-static int ports[ALI_NUM_PORTS] __initdata = {0x074, 0x0f4, 0x034, 0x0e4};
-
-/* register initialization data */
-typedef struct { byte reg, data; } RegInitializer;
-
-static RegInitializer initData[] __initdata = {
-	{0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
-	{0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
-	{0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
-	{0x29, 0x00}, {0x2a, 0x00}, {0x2f, 0x00}, {0x2b, 0x00},
-	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x30, 0x00},
-	{0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0xff},
-	{0x35, 0x03}, {0x00, 0x00}
-};
-
-#define ALI_MAX_PIO 4
-
-/* timing parameter registers for each drive */
-static struct { byte reg1, reg2, reg3, reg4; } regTab[4] = {
-	{0x03, 0x26, 0x04, 0x27},     /* drive 0 */
-	{0x05, 0x28, 0x06, 0x29},     /* drive 1 */
-	{0x2b, 0x30, 0x2c, 0x31},     /* drive 2 */
-	{0x2d, 0x32, 0x2e, 0x33},     /* drive 3 */
-};
-
-static int basePort;	/* base port address */
-static int regPort;	/* port for register number */
-static int dataPort;	/* port for register data */
-static byte regOn;	/* output to base port to access registers */
-static byte regOff;	/* output to base port to close registers */
-
-/*------------------------------------------------------------------------*/
-
-/*
- * Read a controller register.
- */
-static inline byte inReg (byte reg)
-{
-	outb_p(reg, regPort);
-	return inb(dataPort);
-}
-
-/*
- * Write a controller register.
- */
-static void outReg (byte data, byte reg)
-{
-	outb_p(reg, regPort);
-	outb_p(data, dataPort);
-}
-
-/*
- * Set PIO mode for the specified drive.
- * This function computes timing parameters
- * and sets controller registers accordingly.
- */
-static void ali14xx_tune_drive (ide_drive_t *drive, byte pio)
-{
-	int driveNum;
-	int time1, time2;
-	byte param1, param2, param3, param4;
-	unsigned long flags;
-	ide_pio_data_t d;
-	int bus_speed = system_bus_clock();
-
-	pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d);
-
-	/* calculate timing, according to PIO mode */
-	time1 = d.cycle_time;
-	time2 = ide_pio_timings[pio].active_time;
-	param3 = param1 = (time2 * bus_speed + 999) / 1000;
-	param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
-	if (pio < 3) {
-		param3 += 8;
-		param4 += 8;
-	}
-	printk("%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n",
-		drive->name, pio, time1, time2, param1, param2, param3, param4);
-
-	/* stuff timing parameters into controller registers */
-	driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit;
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-	outb_p(regOn, basePort);
-	outReg(param1, regTab[driveNum].reg1);
-	outReg(param2, regTab[driveNum].reg2);
-	outReg(param3, regTab[driveNum].reg3);
-	outReg(param4, regTab[driveNum].reg4);
-	outb_p(regOff, basePort);
-	restore_flags(flags);	/* all CPUs */
-}
-
-/*
- * Auto-detect the IDE controller port.
- */
-static int __init findPort (void)
-{
-	int i;
-	byte t;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	for (i = 0; i < ALI_NUM_PORTS; ++i) {
-		basePort = ports[i];
-		regOff = inb(basePort);
-		for (regOn = 0x30; regOn <= 0x33; ++regOn) {
-			outb_p(regOn, basePort);
-			if (inb(basePort) == regOn) {
-				regPort = basePort + 4;
-				dataPort = basePort + 8;
-				t = inReg(0) & 0xf0;
-				outb_p(regOff, basePort);
-				__restore_flags(flags);	/* local CPU only */
-				if (t != 0x50)
-					return 0;
-				return 1;  /* success */
-			}
-		}
-		outb_p(regOff, basePort);
-	}
-	__restore_flags(flags);	/* local CPU only */
-	return 0;
-}
-
-/*
- * Initialize controller registers with default values.
- */
-static int __init initRegisters (void) {
-	RegInitializer *p;
-	byte t;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	outb_p(regOn, basePort);
-	for (p = initData; p->reg != 0; ++p)
-		outReg(p->data, p->reg);
-	outb_p(0x01, regPort);
-	t = inb(regPort) & 0x01;
-	outb_p(regOff, basePort);
-	__restore_flags(flags);	/* local CPU only */
-	return t;
-}
-
-void __init init_ali14xx (void)
-{
-	/* auto-detect IDE controller port */
-	if (!findPort()) {
-		printk("\nali14xx: not found");
-		return;
-	}
-
-	printk("\nali14xx: base= 0x%03x, regOn = 0x%02x", basePort, regOn);
-	ide_hwifs[0].chipset = ide_ali14xx;
-	ide_hwifs[1].chipset = ide_ali14xx;
-	ide_hwifs[0].tuneproc = &ali14xx_tune_drive;
-	ide_hwifs[1].tuneproc = &ali14xx_tune_drive;
-	ide_hwifs[0].mate = &ide_hwifs[1];
-	ide_hwifs[1].mate = &ide_hwifs[0];
-	ide_hwifs[1].channel = 1;
-
-	/* initialize controller registers */
-	if (!initRegisters()) {
-		printk("\nali14xx: Chip initialization failed");
-		return;
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/alim15x3.c linux-2.4.21/drivers/ide/alim15x3.c
--- linux-2.4.20/drivers/ide/alim15x3.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/alim15x3.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,705 +0,0 @@
-/*
- * linux/drivers/ide/alim15x3.c		Version 0.10	Jun. 9, 2000
- *
- *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
- *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
- *  Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer
- *
- *  Copyright (C) 1998-2000 Andre Hedrick (andre@linux-ide.org)
- *  May be copied or modified under the terms of the GNU General Public License
- *
- *  (U)DMA capable version of ali 1533/1543(C), 1535(D)
- *
- **********************************************************************
- *  9/7/99 --Parts from the above author are included and need to be
- *  converted into standard interface, once I finish the thought.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_ALI_TIMINGS
-
-#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int ali_get_info(char *buffer, char **addr, off_t offset, int count);
-extern int (*ali_display_info)(char *, char **, off_t, int);  /* ide-proc.c */
-static struct pci_dev *bmide_dev;
-
-char *fifo[4] = {
-	"FIFO Off",
-	"FIFO On ",
-	"DMA mode",
-	"PIO mode" };
-
-char *udmaT[8] = {
-	"1.5T",
-	"  2T",
-	"2.5T",
-	"  3T",
-	"3.5T",
-	"  4T",
-	"  6T",
-	"  8T"
-};
-
-char *channel_status[8] = {
-	"OK            ",
-	"busy          ",
-	"DRQ           ",
-	"DRQ busy      ",
-	"error         ",
-	"error busy    ",
-	"error DRQ     ",
-	"error DRQ busy"
-};
-
-static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	byte reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1;
-	unsigned int bibma;
-	byte c0, c1;
-	byte rev, tmp;
-	char *p = buffer;
-	char *q;
-
-	/* fetch rev. */
-	pci_read_config_byte(bmide_dev, 0x08, &rev);
-	if (rev >= 0xc1)	/* M1543C or newer */
-		udmaT[7] = " ???";
-	else
-		fifo[3]  = "   ???  ";
-
-	/* first fetch bibma: */
-	pci_read_config_dword(bmide_dev, 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);
-
-	p += sprintf(p,
-		"\n                                Ali M15x3 Chipset.\n");
-	p += sprintf(p,
-		"                                ------------------\n");
-	pci_read_config_byte(bmide_dev, 0x78, &reg53h);
-	p += sprintf(p, "PCI Clock: %d.\n", reg53h);
-
-	pci_read_config_byte(bmide_dev, 0x53, &reg53h);
-	p += sprintf(p,
-		"CD_ROM FIFO:%s, CD_ROM DMA:%s\n",
-		(reg53h & 0x02) ? "Yes" : "No ",
-		(reg53h & 0x01) ? "Yes" : "No " );
-	pci_read_config_byte(bmide_dev, 0x74, &reg53h);
-	p += sprintf(p,
-		"FIFO Status: contains %d Words, runs%s%s\n\n",
-		(reg53h & 0x3f),
-		(reg53h & 0x40) ? " OVERWR" : "",
-		(reg53h & 0x80) ? " OVERRD." : "." );
-
-	p += sprintf(p,
-		"-------------------primary channel-------------------secondary channel---------\n\n");
-
-	pci_read_config_byte(bmide_dev, 0x09, &reg53h);
-	p += sprintf(p,
-		"channel status:       %s                               %s\n",
-		(reg53h & 0x20) ? "On " : "Off",
-		(reg53h & 0x10) ? "On " : "Off" );
-
-	p += sprintf(p,
-		"both channels togth:  %s                               %s\n",
-		(c0&0x80) ? "No " : "Yes",
-		(c1&0x80) ? "No " : "Yes" );
-
-	pci_read_config_byte(bmide_dev, 0x76, &reg53h);
-	p += sprintf(p,
-		"Channel state:        %s                    %s\n",
-		channel_status[reg53h & 0x07],
-		channel_status[(reg53h & 0x70) >> 4] );
-
-	pci_read_config_byte(bmide_dev, 0x58, &reg5xh);
-	pci_read_config_byte(bmide_dev, 0x5c, &reg5yh);
-	p += sprintf(p,
-		"Add. Setup Timing:    %dT                                %dT\n",
-		(reg5xh & 0x07) ? (reg5xh & 0x07) : 8,
-		(reg5yh & 0x07) ? (reg5yh & 0x07) : 8 );
-
-	pci_read_config_byte(bmide_dev, 0x59, &reg5xh);
-	pci_read_config_byte(bmide_dev, 0x5d, &reg5yh);
-	p += sprintf(p,
-		"Command Act. Count:   %dT                                %dT\n"
-		"Command Rec. Count:   %dT                               %dT\n\n",
-		(reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
-		(reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8, 
-		(reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
-		(reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16 );
-
-	p += sprintf(p,
-		"----------------drive0-----------drive1------------drive0-----------drive1------\n\n");
-	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 " );
-
-	pci_read_config_byte(bmide_dev, 0x54, &reg5xh);
-	pci_read_config_byte(bmide_dev, 0x55, &reg5yh);
-	q = "FIFO threshold:   %2d Words         %2d Words          %2d Words         %2d Words\n";
-	if (rev < 0xc1) {
-		if ((rev == 0x20) && (pci_read_config_byte(bmide_dev, 0x4f, &tmp), (tmp &= 0x20))) {
-			p += sprintf(p, q, 8, 8, 8, 8);
-		} else {
-			p += sprintf(p, q,
-				(reg5xh & 0x03) + 12,
-				((reg5xh & 0x30)>>4) + 12,
-				(reg5yh & 0x03) + 12,
-				((reg5yh & 0x30)>>4) + 12 );
-		}
-	} else {
-		int t1 = (tmp = (reg5xh & 0x03)) ? (tmp << 3) : 4;
-		int t2 = (tmp = ((reg5xh & 0x30)>>4)) ? (tmp << 3) : 4;
-		int t3 = (tmp = (reg5yh & 0x03)) ? (tmp << 3) : 4;
-		int t4 = (tmp = ((reg5yh & 0x30)>>4)) ? (tmp << 3) : 4;
-		p += sprintf(p, q, t1, t2, t3, t4);
-	}
-
-#if 0
-	p += sprintf(p, 
-		"FIFO threshold:   %2d Words         %2d Words          %2d Words         %2d Words\n",
-		(reg5xh & 0x03) + 12,
-		((reg5xh & 0x30)>>4) + 12,
-		(reg5yh & 0x03) + 12,
-		((reg5yh & 0x30)>>4) + 12 );
-#endif
-
-	p += sprintf(p,
-		"FIFO mode:        %s         %s          %s         %s\n",
-		fifo[((reg5xh & 0x0c) >> 2)],
-		fifo[((reg5xh & 0xc0) >> 6)],
-		fifo[((reg5yh & 0x0c) >> 2)],
-		fifo[((reg5yh & 0xc0) >> 6)] );
-
-	pci_read_config_byte(bmide_dev, 0x5a, &reg5xh);
-	pci_read_config_byte(bmide_dev, 0x5b, &reg5xh1);
-	pci_read_config_byte(bmide_dev, 0x5e, &reg5yh);
-	pci_read_config_byte(bmide_dev, 0x5f, &reg5yh1);
-
-	p += sprintf(p,/*
-		"------------------drive0-----------drive1------------drive0-----------drive1------\n")*/
-		"Dt RW act. Cnt    %2dT              %2dT               %2dT              %2dT\n"
-		"Dt RW rec. Cnt    %2dT              %2dT               %2dT              %2dT\n\n",
-		(reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
-		(reg5xh1 & 0x70) ? ((reg5xh1 & 0x70) >> 4) : 8,
-		(reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8,
-		(reg5yh1 & 0x70) ? ((reg5yh1 & 0x70) >> 4) : 8,
-		(reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
-		(reg5xh1 & 0x0f) ? (reg5xh1 & 0x0f) : 16,
-		(reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16,
-		(reg5yh1 & 0x0f) ? (reg5yh1 & 0x0f) : 16 );
-
-	p += sprintf(p,
-		"-----------------------------------UDMA Timings--------------------------------\n\n");
-
-	pci_read_config_byte(bmide_dev, 0x56, &reg5xh);
-	pci_read_config_byte(bmide_dev, 0x57, &reg5yh);
-	p += sprintf(p,
-		"UDMA:             %s               %s                %s               %s\n"
-		"UDMA timings:     %s             %s              %s             %s\n\n",
-		(reg5xh & 0x08) ? "OK" : "No",
-		(reg5xh & 0x80) ? "OK" : "No",
-		(reg5yh & 0x08) ? "OK" : "No",
-		(reg5yh & 0x80) ? "OK" : "No",
-		udmaT[(reg5xh & 0x07)],
-		udmaT[(reg5xh & 0x70) >> 4],
-		udmaT[reg5yh & 0x07],
-		udmaT[(reg5yh & 0x70) >> 4] );
-
-	return p-buffer; /* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-static byte m5229_revision;
-static byte chip_is_1543c_e;
-
-byte ali_proc = 0;
-static struct pci_dev *isa_dev;
-
-static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
-{
-	ide_pio_data_t d;
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
-	int s_time, a_time, c_time;
-	byte s_clc, a_clc, r_clc;
-	unsigned long flags;
-	int bus_speed = system_bus_clock();
-	int port = hwif->index ? 0x5c : 0x58;
-	int portFIFO = hwif->channel ? 0x55 : 0x54;
-	byte cd_dma_fifo = 0;
-
-	pio = ide_get_best_pio_mode(drive, pio, 5, &d);
-	s_time = ide_pio_timings[pio].setup_time;
-	a_time = ide_pio_timings[pio].active_time;
-	if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
-		s_clc = 0;
-	if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8)
-		a_clc = 0;
-	c_time = ide_pio_timings[pio].cycle_time;
-
-#if 0
-	if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16)
-		r_clc = 0;
-#endif
-
-	if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) {
-		r_clc = 1;
-	} else {
-		if (r_clc >= 16)
-			r_clc = 0;
-	}
-	__save_flags(flags);
-	__cli();
-	
-	/* 
-	 * PIO mode => ATA FIFO on, ATAPI FIFO off
-	 */
-	pci_read_config_byte(dev, portFIFO, &cd_dma_fifo);
-	if (drive->media==ide_disk) {
-		if (hwif->index) {
-			pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0x0F) | 0x50);
-		} else {
-			pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0xF0) | 0x05);
-		}
-	} else {
-		if (hwif->index) {
-			pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0x0F);
-		} else {
-			pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0xF0);
-		}
-	}
-	
-	pci_write_config_byte(dev, port, s_clc);
-	pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc);
-	__restore_flags(flags);
-
-	/*
-	 * setup   active  rec
-	 * { 70,   165,    365 },   PIO Mode 0
-	 * { 50,   125,    208 },   PIO Mode 1
-	 * { 30,   100,    110 },   PIO Mode 2
-	 * { 30,   80,     70  },   PIO Mode 3 with IORDY
-	 * { 25,   70,     25  },   PIO Mode 4 with IORDY  ns
-	 * { 20,   50,     30  }    PIO Mode 5 with IORDY (nonstandard)
-	 */
-
-}
-
-static int ali15x3_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte unit		= (drive->select.b.unit & 0x01);
-	byte tmpbyte		= 0x00;
-	int m5229_udma		= hwif->channel? 0x57 : 0x56;
-	int err			= 0;
-
-	if (speed < XFER_UDMA_0) {
-		byte ultra_enable	= (unit) ? 0x7f : 0xf7;
-		/*
-		 * clear "ultra enable" bit
-		 */
-		pci_read_config_byte(dev, m5229_udma, &tmpbyte);
-		tmpbyte &= ultra_enable;
-		pci_write_config_byte(dev, m5229_udma, tmpbyte);
-	}
-
-	err = ide_config_drive_speed(drive, speed);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (speed >= XFER_SW_DMA_0) {
-		unsigned long dma_base = hwif->dma_base;
-
-		outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-	}
-
-	if (speed >= XFER_UDMA_0) {
-		pci_read_config_byte(dev, m5229_udma, &tmpbyte);
-		tmpbyte &= (0x0f << ((1-unit) << 2));
-		/*
-		 * enable ultra dma and set timing
-		 */
-		tmpbyte |= ((0x08 | ((4-speed)&0x07)) << (unit << 2));
-		pci_write_config_byte(dev, m5229_udma, tmpbyte);
-		if (speed >= XFER_UDMA_3) {
-			pci_read_config_byte(dev, 0x4b, &tmpbyte);
-			tmpbyte |= 1;
-			pci_write_config_byte(dev, 0x4b, tmpbyte);
-		}
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	drive->current_speed = speed;
-
-	return (err);
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-	ali15x3_tune_drive(drive, 5);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra33)
-{
-	struct hd_driveid *id	= drive->id;
-	byte speed		= 0x00;
-	byte ultra66		= eighty_ninty_three(drive);
-	byte ultra100		= (m5229_revision>=0xc4) ? 1 : 0;
-	int  rval;
-
-	if ((id->dma_ultra & 0x0020) && (ultra100) && (ultra66) && (ultra33)) {
-		speed = XFER_UDMA_5;
-	} else if ((id->dma_ultra & 0x0010) && (ultra66) && (ultra33)) {
-		speed = XFER_UDMA_4;
-	} else if ((id->dma_ultra & 0x0008) && (ultra66) && (ultra33)) {
-		speed = XFER_UDMA_3;
-	} else if ((id->dma_ultra & 0x0004) && (ultra33)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra33)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra33)) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_mword & 0x0001) {
-		speed = XFER_MW_DMA_0;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-	} else if (id->dma_1word & 0x0002) {
-		speed = XFER_SW_DMA_1;
-	} else if (id->dma_1word & 0x0001) {
-		speed = XFER_SW_DMA_0;
-	} else {
-		return ((int) ide_dma_off_quietly);
-	}
-
-	(void) ali15x3_tune_chipset(drive, speed);
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	rval = (int)(	((id->dma_ultra >> 11) & 3) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-
-	return rval;
-}
-
-static byte ali15x3_can_ultra (ide_drive_t *drive)
-{
-#ifndef CONFIG_WDC_ALI15X3
-	struct hd_driveid *id	= drive->id;
-#endif /* CONFIG_WDC_ALI15X3 */
-
-	if (m5229_revision <= 0x20) {
-		return 0;
-	} else if ((m5229_revision < 0xC2) &&
-#ifndef CONFIG_WDC_ALI15X3
-		   ((chip_is_1543c_e && strstr(id->model, "WDC ")) ||
-		    (drive->media!=ide_disk))) {
-#else /* CONFIG_WDC_ALI15X3 */
-		   (drive->media!=ide_disk)) {
-#endif /* CONFIG_WDC_ALI15X3 */
-		return 0;
-	} else {
-		return 1;
-	}
-}
-
-static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
-{
-	struct hd_driveid *id		= drive->id;
-	ide_hwif_t *hwif		= HWIF(drive);
-	ide_dma_action_t dma_func	= ide_dma_on;
-	byte can_ultra_dma		= ali15x3_can_ultra(drive);
-
-	if ((m5229_revision<=0x20) && (drive->media!=ide_disk))
-		return hwif->dmaproc(ide_dma_off_quietly, drive);
-
-	if ((id != NULL) && ((id->capability & 1) != 0) && hwif->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive, can_ultra_dma);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive, can_ultra_dma);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive, can_ultra_dma);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		config_chipset_for_pio(drive);
-	}
-	return hwif->dmaproc(dma_func, drive);
-}
-
-static int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch(func) {
-		case ide_dma_check:
-			return ali15x3_config_drive_for_dma(drive);
-		case ide_dma_write:
-			if ((m5229_revision < 0xC2) && (drive->media != ide_disk))
-				return 1;	/* try PIO instead of DMA */
-			break;
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
-{
-	unsigned long fixdma_base = pci_resource_start(dev, 4);
-
-	pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision);
-
-	isa_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
-
-	if (!fixdma_base) {
-		/*
-		 *
-		 */
-	} else {
-		/*
-		 * enable DMA capable bit, and "not" simplex only
-		 */
-		outb(inb(fixdma_base+2) & 0x60, fixdma_base+2);
-
-		if (inb(fixdma_base+2) & 0x80)
-			printk("%s: simplex device: DMA will fail!!\n", name);
-	}
-
-#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!ali_proc) {
-		ali_proc = 1;
-		bmide_dev = dev;
-		ali_display_info = &ali_get_info;
-	}
-#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-	return 0;
-}
-
-/*
- * This checks if the controller and the cable are capable
- * of UDMA66 transfers. It doesn't check the drives.
- * But see note 2 below!
- */
-unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned int ata66	= 0;
-	byte cable_80_pin[2]	= { 0, 0 };
-
-	unsigned long flags;
-	byte tmpbyte;
-
-	__save_flags(flags);
-	__cli();
-
-	if (m5229_revision >= 0xC2) {
-		/*
-		 * 1543C-B?, 1535, 1535D, 1553
-		 * Note 1: not all "motherboard" support this detection
-		 * Note 2: if no udma 66 device, the detection may "error".
-		 *         but in this case, we will not set the device to
-		 *         ultra 66, the detection result is not important
-		 */
-
-		/*
-		 * enable "Cable Detection", m5229, 0x4b, bit3
-		 */
-		pci_read_config_byte(dev, 0x4b, &tmpbyte);
-		pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08);
-
-		/*
-		 * set south-bridge's enable bit, m1533, 0x79
-		 */
-		pci_read_config_byte(isa_dev, 0x79, &tmpbyte);
-		if (m5229_revision == 0xC2) {
-			/*
-			 * 1543C-B0 (m1533, 0x79, bit 2)
-			 */
-			pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04);
-		} else if (m5229_revision >= 0xC3) {
-			/*
-			 * 1553/1535 (m1533, 0x79, bit 1)
-			 */
-			pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
-		}
-		/*
-		 * Ultra66 cable detection (from Host View)
-		 * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin
-		 */
-		pci_read_config_byte(dev, 0x4a, &tmpbyte);
-		/*
-		 * 0x4a, bit0 is 0 => primary channel
-		 * has 80-pin (from host view)
-		 */
-		if (!(tmpbyte & 0x01)) cable_80_pin[0] = 1;
-		/*
-		 * 0x4a, bit1 is 0 => secondary channel
-		 * has 80-pin (from host view)
-		 */
-		if (!(tmpbyte & 0x02)) cable_80_pin[1] = 1;
-		/*
-		 * Allow ata66 if cable of current channel has 80 pins
-		 */
-		ata66 = (hwif->channel)?cable_80_pin[1]:cable_80_pin[0];
-	} else {
-		/*
-		 * revision 0x20 (1543-E, 1543-F)
-		 * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E)
-		 * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7
-		 */
-		pci_read_config_byte(dev, 0x4b, &tmpbyte);
-		/*
-		 * clear bit 7
-		 */
-		pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
-		/*
-		 * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
-		 */
-		pci_read_config_byte(isa_dev, 0x5e, &tmpbyte);
-		chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0;
-	}
-
-	/*
-	 * CD_ROM DMA on (m5229, 0x53, bit0)
-	 *      Enable this bit even if we want to use PIO
-	 * PIO FIFO off (m5229, 0x53, bit1)
-	 *      The hardware will use 0x54h and 0x55h to control PIO FIFO
-	 */
-	pci_read_config_byte(dev, 0x53, &tmpbyte);
-	tmpbyte = (tmpbyte & (~0x02)) | 0x01;
-
-	pci_write_config_byte(dev, 0x53, tmpbyte);
-
-	__restore_flags(flags);
-
-	return(ata66);
-}
-
-void __init ide_init_ali15x3 (ide_hwif_t *hwif)
-{
-#ifndef CONFIG_SPARC64
-	byte ideic, inmir;
-	byte irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
-				      1, 11, 0, 12, 0, 14, 0, 15 };
-
-	hwif->irq = hwif->channel ? 15 : 14;
-
-	if (isa_dev) {
-		/*
-		 * read IDE interface control
-		 */
-		pci_read_config_byte(isa_dev, 0x58, &ideic);
-
-		/* bit0, bit1 */
-		ideic = ideic & 0x03;
-
-		/* get IRQ for IDE Controller */
-		if ((hwif->channel && ideic == 0x03) || (!hwif->channel && !ideic)) {
-			/*
-			 * get SIRQ1 routing table
-			 */
-			pci_read_config_byte(isa_dev, 0x44, &inmir);
-			inmir = inmir & 0x0f;
-			hwif->irq = irq_routing_table[inmir];
-		} else if (hwif->channel && !(ideic & 0x01)) {
-			/*
-			 * get SIRQ2 routing table
-			 */
-			pci_read_config_byte(isa_dev, 0x75, &inmir);
-			inmir = inmir & 0x0f;
-			hwif->irq = irq_routing_table[inmir];
-		}
-	}
-#endif /* CONFIG_SPARC64 */
-
-	hwif->tuneproc = &ali15x3_tune_drive;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->speedproc = &ali15x3_tune_chipset;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if ((hwif->dma_base) && (m5229_revision >= 0x20)) {
-		/*
-		 * M1543C or newer for DMAing
-		 */
-		hwif->dmaproc = &ali15x3_dmaproc;
-		hwif->autodma = 1;
-	}
-
-	if (noautodma)
-		hwif->autodma = 0;
-#else
-	hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-void __init ide_dmacapable_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
-{
-	if ((dmabase) && (m5229_revision < 0x20)) {
-		return;
-	}
-	ide_setup_dma(hwif, dmabase, 8);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/amd74xx.c linux-2.4.21/drivers/ide/amd74xx.c
--- linux-2.4.20/drivers/ide/amd74xx.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/amd74xx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,513 +0,0 @@
-/*
- * linux/drivers/ide/amd74xx.c		Version 0.05	June 9, 2000
- *
- * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
- * May be copied or modified under the terms of the GNU General Public License
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_VIPER_TIMINGS
-
-#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int amd74xx_get_info(char *, char **, off_t, int);
-extern int (*amd74xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-
-static int amd74xx_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-	u8 c0 = 0, c1 = 0;
-
-	/*
-	 * at that point bibma+0x2 et bibma+0xa are byte registers
-	 * to investigate:
-	 */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p, "\n                                AMD %04X VIPER Chipset.\n", bmide_dev->device);
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %sabled                         %sabled\n",
-			(c0&0x80) ? "dis" : " en",
-			(c1&0x80) ? "dis" : " en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	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 " );
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "DMA\n");
-	p += sprintf(p, "PIO\n");
-
-	return p-buffer;	/* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte amd74xx_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-static unsigned int amd74xx_swdma_check (struct pci_dev *dev)
-{
-	unsigned int class_rev;
-
-	if ((dev->device == PCI_DEVICE_ID_AMD_VIPER_7411) ||
-	    (dev->device == PCI_DEVICE_ID_AMD_VIPER_7441))
-		return 0;
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-	return ((int) (class_rev >= 7) ? 1 : 0);
-}
-
-static int amd74xx_swdma_error(ide_drive_t *drive)
-{
-	printk("%s: single-word DMA not support (revision < C4)\n", drive->name);
-	return 0;
-}
-
-/*
- * Here is where all the hard work goes to program the chipset.
- *
- */
-static int amd74xx_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	int err			= 0;
-	byte unit		= (drive->select.b.unit & 0x01);
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	unsigned long dma_base	= hwif->dma_base;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	byte drive_pci		= 0x00;
-	byte drive_pci2		= 0x00;
-	byte ultra_timing	= 0x00;
-	byte dma_pio_timing	= 0x00;
-	byte pio_timing		= 0x00;
-
-        switch (drive->dn) {
-		case 0: drive_pci = 0x53; drive_pci2 = 0x4b; break;
-		case 1: drive_pci = 0x52; drive_pci2 = 0x4a; break;
-		case 2: drive_pci = 0x51; drive_pci2 = 0x49; break;
-		case 3: drive_pci = 0x50; drive_pci2 = 0x48; break;
-		default:
-                        return -1;
-        }
-
-	pci_read_config_byte(dev, drive_pci, &ultra_timing);
-	pci_read_config_byte(dev, drive_pci2, &dma_pio_timing);
-	pci_read_config_byte(dev, 0x4c, &pio_timing);
-
-#ifdef DEBUG
-	printk("%s:%d: Speed 0x%02x UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n",
-		drive->name, drive->dn, speed, ultra_timing, dma_pio_timing, pio_timing);
-#endif
-
-	ultra_timing	&= ~0xC7;
-	dma_pio_timing	&= ~0xFF;
-	pio_timing	&= ~(0x03 << drive->dn);
-
-#ifdef DEBUG
-	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n",
-		drive->name, ultra_timing, dma_pio_timing, pio_timing);
-#endif
-
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_UDMA_7:
-		case XFER_UDMA_6:
-			speed = XFER_UDMA_5;
-		case XFER_UDMA_5:
-			ultra_timing |= 0x46;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_UDMA_4:
-			ultra_timing |= 0x45;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_UDMA_3:
-			ultra_timing |= 0x44;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_UDMA_2:
-			ultra_timing |= 0x40;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_UDMA_1:
-			ultra_timing |= 0x41;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_UDMA_0:
-		ultra_timing |= 0x42;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_MW_DMA_2:
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_MW_DMA_1:
-			dma_pio_timing |= 0x21;
-			break;
-		case XFER_MW_DMA_0:
-			dma_pio_timing |= 0x77;
-			break;
-		case XFER_SW_DMA_2:
-			if (!amd74xx_swdma_check(dev))
-				return amd74xx_swdma_error(drive);
-			dma_pio_timing |= 0x42;
-			break;
-		case XFER_SW_DMA_1:
-			if (!amd74xx_swdma_check(dev))
-				return amd74xx_swdma_error(drive);
-			dma_pio_timing |= 0x65;
-			break;
-		case XFER_SW_DMA_0:
-			if (!amd74xx_swdma_check(dev))
-				return amd74xx_swdma_error(drive);
-			dma_pio_timing |= 0xA8;
-			break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_PIO_3:
-			dma_pio_timing |= 0x22;
-			break;
-		case XFER_PIO_2:
-			dma_pio_timing |= 0x42;
-			break;
-		case XFER_PIO_1:
-			dma_pio_timing |= 0x65;
-			break;
-		case XFER_PIO_0:
-		default:
-			dma_pio_timing |= 0xA8;
-			break;
-        }
-
-	pio_timing |= (0x03 << drive->dn);
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	pci_write_config_byte(dev, drive_pci, ultra_timing);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	pci_write_config_byte(dev, drive_pci2, dma_pio_timing);
-	pci_write_config_byte(dev, 0x4c, pio_timing);
-
-#ifdef DEBUG
-	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n",
-		drive->name, ultra_timing, dma_pio_timing, pio_timing);
-#endif
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (speed > XFER_PIO_4) {
-		outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-	} else {
-		outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return (err);
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-	unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
-	unsigned short xfer_pio	= drive->id->eide_pio_modes;
-	byte			timing, speed, pio;
-
-	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-	if (xfer_pio> 4)
-		xfer_pio = 0;
-
-	if (drive->id->eide_pio_iordy > 0) {
-		for (xfer_pio = 5;
-			xfer_pio>0 &&
-			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
-			xfer_pio--);
-	} else {
-		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
-			   (drive->id->eide_pio_modes & 2) ? 0x04 :
-			   (drive->id->eide_pio_modes & 1) ? 0x03 :
-			   (drive->id->tPIO & 2) ? 0x02 :
-			   (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
-	}
-
-	timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
-	switch(timing) {
-		case 4: speed = XFER_PIO_4;break;
-		case 3: speed = XFER_PIO_3;break;
-		case 2: speed = XFER_PIO_2;break;
-		case 1: speed = XFER_PIO_1;break;
-		default:
-			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
-			break;
-	}
-	(void) amd74xx_tune_chipset(drive, speed);
-	drive->current_speed = speed;
-}
-
-static void amd74xx_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-	switch(pio) {
-		case 4:		speed = XFER_PIO_4;break;
-		case 3:		speed = XFER_PIO_3;break;
-		case 2:		speed = XFER_PIO_2;break;
-		case 1:		speed = XFER_PIO_1;break;
-		default:	speed = XFER_PIO_0;break;
-	}
-	(void) amd74xx_tune_chipset(drive, speed);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * This allows the configuration of ide_pci chipset registers
- * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.
- */
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	struct hd_driveid *id	= drive->id;
-	byte udma_66		= eighty_ninty_three(drive);
-	byte udma_100		= ((dev->device==PCI_DEVICE_ID_AMD_VIPER_7411)||
-				   (dev->device==PCI_DEVICE_ID_AMD_VIPER_7441)) ? 1 : 0;
-	byte speed		= 0x00;
-	int  rval;
-
-	if (udma_100)
-		udma_66 = eighty_ninty_three(drive);
-
-	if ((id->dma_ultra & 0x0020) && (udma_66) && (udma_100)) {
-		speed = XFER_UDMA_5;
-	} else if ((id->dma_ultra & 0x0010) && (udma_66)) {
-		speed = XFER_UDMA_4;
-	} else if ((id->dma_ultra & 0x0008) && (udma_66)) {
-		speed = XFER_UDMA_3;
-	} else if (id->dma_ultra & 0x0004) {
-		speed = XFER_UDMA_2;
-	} else if (id->dma_ultra & 0x0002) {
-		speed = XFER_UDMA_1;
-	} else if (id->dma_ultra & 0x0001) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_mword & 0x0001) {
-		speed = XFER_MW_DMA_0;
-	} else {
-		return ((int) ide_dma_off_quietly);
-	}
-
-	(void) amd74xx_tune_chipset(drive, speed);
-
-	rval = (int)(	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-
-	return rval;
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    ((id->dma_1word & 0x007) &&
-			     (amd74xx_swdma_check(HWIF(drive)->pci_dev)))) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-			
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-
-		config_chipset_for_pio(drive);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * amd74xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- */
-
-int amd74xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-unsigned int __init pci_init_amd74xx (struct pci_dev *dev, const char *name)
-{
-	unsigned long fixdma_base = pci_resource_start(dev, 4);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (!amd74xx_swdma_check(dev))
-		printk("%s: disabling single-word DMA support (revision < C4)\n", name);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	if (!fixdma_base) {
-		/*
-		 *
-		 */
-	} else {
-		/*
-		 * enable DMA capable bit, and "not" simplex only
-		 */
-		outb(inb(fixdma_base+2) & 0x60, fixdma_base+2);
-
-		if (inb(fixdma_base+2) & 0x80)
-			printk("%s: simplex device: DMA will fail!!\n", name);
-	}
-#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!amd74xx_proc) {
-		amd74xx_proc = 1;
-		bmide_dev = dev;
-		amd74xx_display_info = &amd74xx_get_info;
-	}
-#endif /* DISPLAY_VIPER_TIMINGS && CONFIG_PROC_FS */
-
-	return 0;
-}
-
-unsigned int __init ata66_amd74xx (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte cable_80_pin[2]	= { 0, 0 };
-	byte ata66		= 0;
-	byte tmpbyte;
-
-	/*
-	 * Ultra66 cable detection (from Host View)
-	 * 7411, 7441, 0x42, bit0: primary, bit2: secondary 80 pin
-	 */
-	pci_read_config_byte(dev, 0x42, &tmpbyte);
-
-	/*
-	 * 0x42, bit0 is 1 => primary channel
-	 * has 80-pin (from host view)
-	 */
-	if (tmpbyte & 0x01) cable_80_pin[0] = 1;
-
-	/*
-	 * 0x42, bit2 is 1 => secondary channel
-	 * has 80-pin (from host view)
-	 */
-	if (tmpbyte & 0x04) cable_80_pin[1] = 1;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_AMD_VIPER_7441:
-		case PCI_DEVICE_ID_AMD_VIPER_7411:
-			ata66 = (hwif->channel) ?
-				cable_80_pin[1] :
-				cable_80_pin[0];
-		default:
-			break;
-	}
-#ifdef CONFIG_AMD74XX_OVERRIDE
-	return(1);
-#else
-	return (unsigned int) ata66;
-#endif /* CONFIG_AMD74XX_OVERRIDE */
-}
-
-void __init ide_init_amd74xx (ide_hwif_t *hwif)
-{
-	hwif->tuneproc = &amd74xx_tune_drive;
-	hwif->speedproc = &amd74xx_tune_chipset;
-
-#ifndef CONFIG_BLK_DEV_IDEDMA
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-	return;
-#else
-
-	if (hwif->dma_base) {
-		hwif->dmaproc = &amd74xx_dmaproc;
-		if (!noautodma)
-			hwif->autodma = 1;
-	} else {
-		hwif->autodma = 0;
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-void __init ide_dmacapable_amd74xx (ide_hwif_t *hwif, unsigned long dmabase)
-{
-	ide_setup_dma(hwif, dmabase, 8);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/arm/Makefile linux-2.4.21/drivers/ide/arm/Makefile
--- linux-2.4.20/drivers/ide/arm/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/arm/Makefile	2002-12-18 18:58:09.000000000 +0000
@@ -0,0 +1,12 @@
+
+O_TARGET := idedriver-arm.o
+
+obj-y		:=
+obj-m		:=
+
+obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
+obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)	+= rapide.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/arm/icside.c linux-2.4.21/drivers/ide/arm/icside.c
--- linux-2.4.20/drivers/ide/arm/icside.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/arm/icside.c	2002-12-18 18:58:03.000000000 +0000
@@ -0,0 +1,875 @@
+/*
+ * linux/drivers/ide/icside.c
+ *
+ * Copyright (c) 1996,1997 Russell King.
+ *
+ * Changelog:
+ *  08-Jun-1996	RMK	Created
+ *  12-Sep-1997	RMK	Added interrupt enable/disable
+ *  17-Apr-1999	RMK	Added support for V6 EASI
+ *  22-May-1999	RMK	Added support for V6 DMA
+ */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/errno.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/dma.h>
+#include <asm/ecard.h>
+#include <asm/io.h>
+
+#include "ide-noise.h"
+
+/*
+ * FIXME: We want to drop the the MACRO CRAP!
+ *
+ * ec->iops->in{b/w/l}
+ * ec->iops->in{b/w/l}_p
+ * ec->iops->out{b/w/l}
+ * ec->iops->out{b/w/l}_p
+ *
+ * the new core supports clean MMIO calls and other goodies
+ */
+
+/*
+ * Maximum number of interfaces per card
+ */
+#define MAX_IFS	2
+
+#define ICS_IDENT_OFFSET		0x8a0
+
+#define ICS_ARCIN_V5_INTRSTAT		0x000
+#define ICS_ARCIN_V5_INTROFFSET		0x001
+#define ICS_ARCIN_V5_IDEOFFSET		0xa00
+#define ICS_ARCIN_V5_IDEALTOFFSET	0xae0
+#define ICS_ARCIN_V5_IDESTEPPING	4
+
+#define ICS_ARCIN_V6_IDEOFFSET_1	0x800
+#define ICS_ARCIN_V6_INTROFFSET_1	0x880
+#define ICS_ARCIN_V6_INTRSTAT_1		0x8a4
+#define ICS_ARCIN_V6_IDEALTOFFSET_1	0x8e0
+#define ICS_ARCIN_V6_IDEOFFSET_2	0xc00
+#define ICS_ARCIN_V6_INTROFFSET_2	0xc80
+#define ICS_ARCIN_V6_INTRSTAT_2		0xca4
+#define ICS_ARCIN_V6_IDEALTOFFSET_2	0xce0
+#define ICS_ARCIN_V6_IDESTEPPING	4
+
+struct cardinfo {
+	unsigned int dataoffset;
+	unsigned int ctrloffset;
+	unsigned int stepping;
+};
+
+static struct cardinfo icside_cardinfo_v5 = {
+	ICS_ARCIN_V5_IDEOFFSET,
+	ICS_ARCIN_V5_IDEALTOFFSET,
+	ICS_ARCIN_V5_IDESTEPPING
+};
+
+static struct cardinfo icside_cardinfo_v6_1 = {
+	ICS_ARCIN_V6_IDEOFFSET_1,
+	ICS_ARCIN_V6_IDEALTOFFSET_1,
+	ICS_ARCIN_V6_IDESTEPPING
+};
+
+static struct cardinfo icside_cardinfo_v6_2 = {
+	ICS_ARCIN_V6_IDEOFFSET_2,
+	ICS_ARCIN_V6_IDEALTOFFSET_2,
+	ICS_ARCIN_V6_IDESTEPPING
+};
+
+static const card_ids icside_cids[] = {
+	{ MANU_ICS,  PROD_ICS_IDE  },
+	{ MANU_ICS2, PROD_ICS2_IDE },
+	{ 0xffff, 0xffff }
+};
+
+typedef enum {
+	ics_if_unknown,
+	ics_if_arcin_v5,
+	ics_if_arcin_v6
+} iftype_t;
+
+/* ---------------- Version 5 PCB Support Functions --------------------- */
+/* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ * Purpose  : enable interrupts from card
+ */
+static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+{
+	unsigned int memc_port = (unsigned int)ec->irq_data;
+	outb(0, memc_port + ICS_ARCIN_V5_INTROFFSET);
+}
+
+/* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ * Purpose  : disable interrupts from card
+ */
+static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+{
+	unsigned int memc_port = (unsigned int)ec->irq_data;
+	inb(memc_port + ICS_ARCIN_V5_INTROFFSET);
+}
+
+static const expansioncard_ops_t icside_ops_arcin_v5 = {
+	icside_irqenable_arcin_v5,
+	icside_irqdisable_arcin_v5,
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+
+/* ---------------- Version 6 PCB Support Functions --------------------- */
+/* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ * Purpose  : enable interrupts from card
+ */
+static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+{
+	unsigned int ide_base_port = (unsigned int)ec->irq_data;
+
+	outb(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
+	outb(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
+}
+
+/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ * Purpose  : disable interrupts from card
+ */
+static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+{
+	unsigned int ide_base_port = (unsigned int)ec->irq_data;
+
+	inb(ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
+	inb(ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
+}
+
+/* Prototype: icside_irqprobe(struct expansion_card *ec)
+ * Purpose  : detect an active interrupt from card
+ */
+static int icside_irqpending_arcin_v6(struct expansion_card *ec)
+{
+	unsigned int ide_base_port = (unsigned int)ec->irq_data;
+
+	return inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
+	       inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
+}
+
+static const expansioncard_ops_t icside_ops_arcin_v6 = {
+	icside_irqenable_arcin_v6,
+	icside_irqdisable_arcin_v6,
+	icside_irqpending_arcin_v6,
+	NULL,
+	NULL,
+	NULL
+};
+
+/* Prototype: icside_identifyif (struct expansion_card *ec)
+ * Purpose  : identify IDE interface type
+ * Notes    : checks the description string
+ */
+static iftype_t __init icside_identifyif (struct expansion_card *ec)
+{
+	unsigned int addr;
+	iftype_t iftype;
+	int id = 0;
+
+	iftype = ics_if_unknown;
+
+	addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET;
+
+	id = inb(addr) & 1;
+	id |= (inb(addr + 1) & 1) << 1;
+	id |= (inb(addr + 2) & 1) << 2;
+	id |= (inb(addr + 3) & 1) << 3;
+
+	switch (id) {
+	case 0: /* A3IN */
+		printk("icside: A3IN unsupported\n");
+		break;
+
+	case 1: /* A3USER */
+		printk("icside: A3USER unsupported\n");
+		break;
+
+	case 3:	/* ARCIN V6 */
+		printk(KERN_DEBUG "icside: detected ARCIN V6 in slot %d\n", ec->slot_no);
+		iftype = ics_if_arcin_v6;
+		break;
+
+	case 15:/* ARCIN V5 (no id) */
+		printk(KERN_DEBUG "icside: detected ARCIN V5 in slot %d\n", ec->slot_no);
+		iftype = ics_if_arcin_v5;
+		break;
+
+	default:/* we don't know - complain very loudly */
+		printk("icside: ***********************************\n");
+		printk("icside: *** UNKNOWN ICS INTERFACE id=%d ***\n", id);
+		printk("icside: ***********************************\n");
+		printk("icside: please report this to linux@arm.linux.org.uk\n");
+		printk("icside: defaulting to ARCIN V5\n");
+		iftype = ics_if_arcin_v5;
+		break;
+	}
+
+	return iftype;
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
+/*
+ * SG-DMA support.
+ *
+ * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers.
+ * There is only one DMA controller per card, which means that only
+ * one drive can be accessed at one time.  NOTE! We do not enforce that
+ * here, but we rely on the main IDE driver spotting that both
+ * interfaces use the same IRQ, which should guarantee this.
+ */
+#define NR_ENTRIES 256
+#define TABLE_SIZE (NR_ENTRIES * 8)
+
+static int ide_build_sglist(ide_hwif_t *hwif, struct request *rq)
+{
+	struct buffer_head *bh;
+	struct scatterlist *sg = hwif->sg_table;
+	int nents = 0;
+
+	if (rq->cmd == READ)
+		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+	else
+		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+	bh = rq->bh;
+	do {
+		unsigned char *virt_addr = bh->b_data;
+		unsigned int size = bh->b_size;
+
+		while ((bh = bh->b_reqnext) != NULL) {
+			if ((virt_addr + size) != (unsigned char *)bh->b_data)
+				break;
+			size += bh->b_size;
+		}
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = size;
+		nents++;
+	} while (bh != NULL);
+
+	return pci_map_sg(NULL, sg, nents, hwif->sg_dma_direction);
+}
+
+static int
+icside_build_dmatable(ide_drive_t *drive, int ddir)
+{
+	return HWIF(drive)->sg_nents = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq, ddir);
+}
+
+/* Teardown mappings after DMA has completed.  */
+static void icside_destroy_dmatable(ide_drive_t *drive)
+{
+	struct scatterlist *sg = HWIF(drive)->sg_table;
+	int nents = HWIF(drive)->sg_nents;
+
+	pci_unmap_sg(NULL, sg, nents, HWIF(drive)->sg_dma_direction);
+}
+
+static int
+icside_config_if(ide_drive_t *drive, int xfer_mode)
+{
+	int func = ide_dma_off;
+
+	switch (xfer_mode) {
+	case XFER_MW_DMA_2:
+		/*
+		 * The cycle time is limited to 250ns by the r/w
+		 * pulse width (90ns), however we should still
+		 * have a maximum burst transfer rate of 8MB/s.
+		 */
+		drive->drive_data = 250;
+		break;
+
+	case XFER_MW_DMA_1:
+		drive->drive_data = 250;
+		break;
+
+	case XFER_MW_DMA_0:
+		drive->drive_data = 480;
+		break;
+
+	default:
+		drive->drive_data = 0;
+		break;
+	}
+
+	if (!drive->init_speed)
+		drive->init_speed = (u8) xfer_mode;
+
+	if (drive->drive_data &&
+	    ide_config_drive_speed(drive, (u8) xfer_mode) == 0)
+		func = ide_dma_on;
+	else
+		drive->drive_data = 480;
+
+	printk("%s: %s selected (peak %dMB/s)\n", drive->name,
+		ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
+
+	drive->current_speed = (u8) xfer_mode;
+
+	return func;
+}
+
+static int
+icside_set_speed(ide_drive_t *drive, u8 speed)
+{
+	return icside_config_if(drive, speed);
+}
+
+/*
+ * dma_intr() is the handler for disk read/write DMA interrupts
+ */
+static ide_startstop_t icside_dmaintr(ide_drive_t *drive)
+{
+	u8 dma_stat	= HWIF(drive)->ide_dma_end(drive);
+	/* get drive status */
+	u8 stat		= HWIF(drive)->INB(IDE_STATUS_REG);
+	int i;
+
+	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
+		if (!dma_stat) {
+			struct request *rq = HWGROUP(drive)->rq;
+			rq = HWGROUP(drive)->rq;
+			for (i = rq->nr_sectors; i > 0;) {
+				i -= rq->current_nr_sectors;
+				DRIVER(drive)->end_request(drive, 1);
+			}
+			return ide_stopped;
+		}
+		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
+		       drive->name, dma_stat);
+	}
+	return DRIVER(drive)->error(drive, "dma_intr", stat);
+}
+
+/*
+ * The following is a sick duplication from ide-dma.c ;(
+ *
+ * This should be defined in one place only.
+ */
+struct drive_list_entry {
+	char * id_model;
+	char * id_firmware;
+};
+
+static struct drive_list_entry drive_whitelist [] = {
+	{ "Micropolis 2112A",			"ALL"		},
+	{ "CONNER CTMA 4000",			"ALL"		},
+	{ "CONNER CTT8000-A",			"ALL"		},
+	{ "ST34342A",				"ALL"		},
+	{ NULL,					0		}
+};
+
+static struct drive_list_entry drive_blacklist [] = {
+	{ "WDC AC11000H",			"ALL"		},
+	{ "WDC AC22100H",			"ALL"		},
+	{ "WDC AC32500H",			"ALL"		},
+	{ "WDC AC33100H",			"ALL"		},
+	{ "WDC AC31600H",			"ALL"		},
+	{ "WDC AC32100H",			"24.09P07"	},
+	{ "WDC AC23200L",			"21.10N21"	},
+	{ "Compaq CRD-8241B",			"ALL"		},
+	{ "CRD-8400B",				"ALL"		},
+	{ "CRD-8480B",				"ALL"		},
+	{ "CRD-8480C",				"ALL"		},
+	{ "CRD-8482B",				"ALL"		},
+ 	{ "CRD-84",				"ALL"		},
+	{ "SanDisk SDP3B",			"ALL"		},
+	{ "SanDisk SDP3B-64",			"ALL"		},
+	{ "SANYO CD-ROM CRD",			"ALL"		},
+	{ "HITACHI CDR-8",			"ALL"		},
+	{ "HITACHI CDR-8335",			"ALL"		},
+	{ "HITACHI CDR-8435",			"ALL"		},
+	{ "Toshiba CD-ROM XM-6202B",		"ALL"		},
+	{ "CD-532E-A",				"ALL"		},
+	{ "E-IDE CD-ROM CR-840",		"ALL"		},
+	{ "CD-ROM Drive/F5A",			"ALL"		},
+	{ "RICOH CD-R/RW MP7083A",		"ALL"		},
+	{ "WPI CDD-820",			"ALL"		},
+	{ "SAMSUNG CD-ROM SC-148C",		"ALL"		},
+	{ "SAMSUNG CD-ROM SC-148F",		"ALL"		},
+	{ "SAMSUNG CD-ROM SC",			"ALL"		},
+	{ "SanDisk SDP3B-64",			"ALL"		},
+	{ "SAMSUNG CD-ROM SN-124",		"ALL"		},
+	{ "PLEXTOR CD-R PX-W8432T",		"ALL"		},
+	{ "ATAPI CD-ROM DRIVE 40X MAXIMUM",	"ALL"		},
+	{ "_NEC DV5800A",			"ALL"		},
+	{ NULL,					0		}
+};
+
+static int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
+{
+	for ( ; drive_table->id_model ; drive_table++)
+		if ((!strcmp(drive_table->id_model, id->model)) &&
+		    ((!strstr(drive_table->id_firmware, id->fw_rev)) ||
+		     (!strcmp(drive_table->id_firmware, "ALL"))))
+			return 1;
+	return 0;
+}
+
+/*
+ *  For both Blacklisted and Whitelisted drives.
+ *  This is setup to be called as an extern for future support
+ *  to other special driver code.
+ */
+int check_drive_good_lists (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	return in_drive_list(id, drive_whitelist);
+}
+
+int check_drive_bad_lists (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	int blacklist = in_drive_list(id, drive_blacklist);
+	if (blacklist)
+		printk("%s: Disabling DMA for %s\n", drive->name, id->model);
+	return(blacklist);
+}
+
+int icside_dma_check(ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	ide_hwif_t *hwif = HWIF(drive);
+	int autodma = hwif->autodma;
+	int xfer_mode = XFER_PIO_2;
+
+	if (!id || !(id->capability & 1) || !autodma)
+		return hwif->ide_dma_off_quietly(drive);
+
+	/*
+	 * Consult the list of known "bad" drives
+	 */
+	if (check_drive_bad_lists(drive))
+		return hwif->ide_dma_off(drive);
+
+	/*
+	 * Enable DMA on any drive that has multiword DMA
+	 */
+	if (id->field_valid & 2) {
+		if (id->dma_mword & 4) {
+			xfer_mode = XFER_MW_DMA_2;
+		} else if (id->dma_mword & 2) {
+			xfer_mode = XFER_MW_DMA_1;
+		} else if (id->dma_mword & 1) {
+			xfer_mode = XFER_MW_DMA_0;
+		}
+		goto out;
+	}
+
+	/*
+	 * Consult the list of known "good" drives
+	 */
+	if (check_drive_good_lists(drive)) {
+		if (id->eide_dma_time > 150)
+			goto out;
+		xfer_mode = XFER_MW_DMA_1;
+	}
+
+out:
+	if (icside_config_if(drive, xfer_mode))
+		return hwif->ide_dma_on(drive);
+	return hwif->ide_dma_off(drive);
+}
+
+int icside_dma_verbose(ide_drive_t *drive)
+{
+	printk(", DMA");
+	return 1;
+}
+
+int icside_dma_test_irq(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	return inb((unsigned long)hwif->hw.priv) & 1;
+}
+
+int icside_dma_host_off(ide_drive_t *drive)
+{
+	return 0;
+}
+
+int icside_dma_off_quietly(ide_drive_t *drive)
+{
+	drive->using_dma = 0;
+	return icside_dma_host_off(drive);
+}
+
+int icside_dma_off(ide_drive_t *drive)
+{
+	printk("%s: DMA disabled\n", drive->name);
+	return icside_dma_off_quietly(drive);
+}
+
+int icside_dma_host_on(ide_drive_t *drive)
+{
+	return 0;
+}
+
+int icside_dma_on(ide_drive_t *drive)
+{
+	drive->using_dma = 1;
+	return icside_dma_host_on(drive);
+}
+
+int icside_dma_begin(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	enable_dma(hwif->hw.dma);
+	return 0;
+}
+
+int icside_dma_end(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+ 
+	drive->waiting_for_dma = 0;
+	disable_dma(hwif->hw.dma);
+	icside_destroy_dmatable(drive);
+	return get_dma_residue(hwif->hw.dma) != 0;
+}
+
+int icside_dma_count (ide_drive_t *drive)
+{
+        return icside_dma_begin(drive);
+}
+
+int icside_dma_read(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+//	ide_task_t *args	= HWGROUP(drive)->rq->special;
+	int count		= 0;
+	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+
+	count = icside_build_dmatable(drive, PCI_DMA_FROMDEVICE);
+	if (!count)
+		return 1;
+	disable_dma(hwif->hw.dma);
+
+	/* Route the DMA signals to
+	 * to the correct interface.
+	 */
+	HWIF(drive)->OUTB(hwif->select_data, hwif->config_data);
+
+	/* Select the correct timing
+	 * for this drive
+	 */
+	set_dma_speed(hwif->hw.dma, drive->drive_data);
+
+	set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count);
+	set_dma_mode(hwif->hw.dma, DMA_MODE_READ);
+
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = HWGROUP(drive)->rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA;
+		if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
+		ide_task_t *args = HWGROUP(drive)->rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	HWIF(drive)->OUTB(command, IDE_COMMAND_REG);
+
+	return icside_dma_count(drive);
+}
+
+int icside_dma_write(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+//	ide_task_t *args	= HWGROUP(drive)->rq->special;
+	int count		= 0;
+	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+
+	count = icside_build_dmatable(drive, PCI_DMA_TODEVICE);
+	if (!count)
+		return 1;
+	disable_dma(hwif->hw.dma);
+
+	/* Route the DMA signals to
+	 * to the correct interface.
+	 */
+	HWIF(drive)->OUTB(hwif->select_data, hwif->config_data);
+
+	/* Select the correct timing
+	 * for this drive
+	 */
+	set_dma_speed(hwif->hw.dma, drive->drive_data);
+
+	set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count);
+	set_dma_mode(hwif->hw.dma, DMA_MODE_WRITE);
+
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = HWGROUP(drive)->rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+	if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
+		ide_task_t *args = HWGROUP(drive)->rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	HWIF(drive)->OUTB(command, IDE_COMMAND_REG);
+
+	return icside_dma_count(drive);
+}
+
+static int
+icside_setup_dma(ide_hwif_t *hwif, int autodma)
+{
+	printk("    %s: SG-DMA", hwif->name);
+
+	hwif->sg_table = kmalloc(sizeof(struct scatterlist) * NR_ENTRIES,
+				 GFP_KERNEL);
+	if (!hwif->sg_table)
+		goto failed;
+
+	hwif->dmatable_cpu = NULL;
+	hwif->dmatable_dma = 0;
+	hwif->speedproc = icside_set_speed;
+	hwif->autodma = autodma;
+
+	hwif->ide_dma_check = icside_dma_check;
+	hwif->ide_dma_host_off = icside_dma_host_off;
+	hwif->ide_dma_off_quietly = icside_dma_off_quietly;
+	hwif->ide_dma_off = icside_dma_off;
+	hwif->ide_dma_host_on = icside_dma_host_on;
+	hwif->ide_dma_on = icside_dma_on;
+	hwif->ide_dma_read = icside_dma_read;
+	hwif->ide_dma_write = icside_dma_write;
+	hwif->ide_dma_count = icside_dma_count;
+	hwif->ide_dma_begin = icside_dma_begin;
+	hwif->ide_dma_end = icside_dma_end;
+	hwif->ide_dma_verbose = icside_dma_verbose;
+	hwif->ide_dma_bad_drive = check_drive_bad_lists;
+	hwif->ide_dma_good_drive = check_drive_good_lists;
+	hwif->ide_dma_test_irq = icside_dma_test_irq;
+
+	printk(" capable%s\n", autodma ?
+		", auto-enable" : "");
+
+	return 1;
+
+failed:
+	printk(" -- ERROR, unable to allocate DMA table\n");
+	return 0;
+}
+#endif
+
+static ide_hwif_t *
+icside_find_hwif(unsigned long dataport)
+{
+	ide_hwif_t *hwif;
+	int index;
+
+	for (index = 0; index < MAX_HWIFS; ++index) {
+		hwif = &ide_hwifs[index];
+		if (hwif->io_ports[IDE_DATA_OFFSET] == (ide_ioreg_t)dataport)
+			goto found;
+	}
+
+	for (index = 0; index < MAX_HWIFS; ++index) {
+		hwif = &ide_hwifs[index];
+		if (!hwif->io_ports[IDE_DATA_OFFSET])
+			goto found;
+	}
+
+	return NULL;
+found:
+	return hwif;
+}
+
+static ide_hwif_t *
+icside_setup(unsigned long base, struct cardinfo *info, int irq)
+{
+	unsigned long port = base + info->dataoffset;
+	ide_hwif_t *hwif;
+
+	hwif = icside_find_hwif(base);
+	if (hwif) {
+		int i;
+
+		memset(&hwif->hw, 0, sizeof(hw_regs_t));
+
+		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+			hwif->hw.io_ports[i] = (ide_ioreg_t)port;
+			hwif->io_ports[i] = (ide_ioreg_t)port;
+			port += 1 << info->stepping;
+		}
+		hwif->hw.io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
+		hwif->io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
+		hwif->hw.irq  = irq;
+		hwif->irq     = irq;
+		hwif->hw.dma  = NO_DMA;
+		hwif->noprobe = 0;
+		hwif->chipset = ide_acorn;
+	}
+
+	return hwif;
+}
+
+static int __init icside_register_v5(struct expansion_card *ec, int autodma)
+{
+	unsigned long slot_port;
+	ide_hwif_t *hwif;
+
+	slot_port = ecard_address(ec, ECARD_MEMC, 0);
+
+	ec->irqaddr  = (unsigned char *)ioaddr(slot_port + ICS_ARCIN_V5_INTRSTAT);
+	ec->irqmask  = 1;
+	ec->irq_data = (void *)slot_port;
+	ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v5;
+
+	/*
+	 * Be on the safe side - disable interrupts
+	 */
+	inb(slot_port + ICS_ARCIN_V5_INTROFFSET);
+
+	hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec->irq);
+
+	return hwif ? 0 : -1;
+}
+
+static int __init icside_register_v6(struct expansion_card *ec, int autodma)
+{
+	unsigned long slot_port, port;
+	ide_hwif_t *hwif, *mate;
+	int sel = 0;
+
+	slot_port = ecard_address(ec, ECARD_IOC, ECARD_FAST);
+	port      = ecard_address(ec, ECARD_EASI, ECARD_FAST);
+
+	if (port == 0)
+		port = slot_port;
+	else
+		sel = 1 << 5;
+
+	outb(sel, slot_port);
+
+	ec->irq_data = (void *)port;
+	ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v6;
+
+	/*
+	 * Be on the safe side - disable interrupts
+	 */
+	inb(port + ICS_ARCIN_V6_INTROFFSET_1);
+	inb(port + ICS_ARCIN_V6_INTROFFSET_2);
+
+	hwif = icside_setup(port, &icside_cardinfo_v6_1, ec->irq);
+	mate = icside_setup(port, &icside_cardinfo_v6_2, ec->irq);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
+	if (ec->dma != NO_DMA) {
+		if (request_dma(ec->dma, hwif->name))
+			goto no_dma;
+
+		if (hwif) {
+			hwif->config_data = slot_port;
+			hwif->select_data = sel;
+			hwif->hw.dma  = ec->dma;
+			hwif->hw.priv = (void *)
+					(port + ICS_ARCIN_V6_INTRSTAT_1);
+			hwif->channel = 0;
+			icside_setup_dma(hwif, autodma);
+			hwif->drives[0].autodma = autodma;
+			hwif->drives[1].autodma = autodma;
+		}
+		if (mate) {
+			mate->config_data = slot_port;
+			mate->select_data = sel | 1;
+			mate->hw.dma  = ec->dma;
+			mate->hw.priv = (void *)
+					(port + ICS_ARCIN_V6_INTRSTAT_2);
+			mate->channel = 1;
+			icside_setup_dma(mate, autodma);
+			mate->drives[0].autodma = autodma;
+			mate->drives[1].autodma = autodma;
+		}
+	}
+no_dma:
+#endif
+	return hwif || mate ? 0 : -1;
+}
+
+int __init icside_init(void)
+{
+	int autodma = 0;
+
+#ifdef CONFIG_IDEDMA_ICS_AUTO
+	autodma = 1;
+#endif
+
+	ecard_startfind ();
+
+	do {
+		struct expansion_card *ec;
+		int result;
+
+		ec = ecard_find(0, icside_cids);
+		if (ec == NULL)
+			break;
+
+		ecard_claim(ec);
+
+		switch (icside_identifyif(ec)) {
+		case ics_if_arcin_v5:
+			result = icside_register_v5(ec, autodma);
+			break;
+
+		case ics_if_arcin_v6:
+			result = icside_register_v6(ec, autodma);
+			break;
+
+		default:
+			result = -1;
+			break;
+		}
+
+		if (result)
+			ecard_release(ec);
+	} while (1);
+
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/arm/rapide.c linux-2.4.21/drivers/ide/arm/rapide.c
--- linux-2.4.20/drivers/ide/arm/rapide.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/arm/rapide.c	2002-12-18 18:58:05.000000000 +0000
@@ -0,0 +1,94 @@
+/*
+ * linux/drivers/ide/rapide.c
+ *
+ * Copyright (c) 1996-1998 Russell King.
+ *
+ * Changelog:
+ *  08-06-1996	RMK	Created
+ *  13-04-1998	RMK	Added manufacturer and product IDs
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/errno.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/ecard.h>
+
+static card_ids __init rapide_cids[] = {
+	{ MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 },
+	{ 0xffff, 0xffff }
+};
+
+static struct expansion_card *ec[MAX_ECARDS];
+static int result[MAX_ECARDS];
+
+static inline int rapide_register(struct expansion_card *ec)
+{
+	unsigned long port = ecard_address (ec, ECARD_MEMC, 0);
+	hw_regs_t hw;
+
+	int i;
+
+	memset(&hw, 0, sizeof(hw));
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		hw.io_ports[i] = (ide_ioreg_t)port;
+		port += 1 << 4;
+	}
+	hw.io_ports[IDE_CONTROL_OFFSET] = port + 0x206;
+	hw.irq = ec->irq;
+
+	return ide_register_hw(&hw, NULL);
+}
+
+int __init rapide_init(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_ECARDS; i++)
+		ec[i] = NULL;
+
+	ecard_startfind();
+
+	for (i = 0; ; i++) {
+		if ((ec[i] = ecard_find(0, rapide_cids)) == NULL)
+			break;
+
+		ecard_claim(ec[i]);
+		result[i] = rapide_register(ec[i]);
+	}
+	for (i = 0; i < MAX_ECARDS; i++)
+		if (ec[i] && result[i] < 0) {
+			ecard_release(ec[i]);
+			ec[i] = NULL;
+	}
+	return 0;
+}
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+int init_module (void)
+{
+	return rapide_init();
+}
+
+void cleanup_module (void)
+{
+	int i;
+
+	for (i = 0; i < MAX_ECARDS; i++)
+		if (ec[i]) {
+			unsigned long port;
+			port = ecard_address(ec[i], ECARD_MEMC, 0);
+
+			ide_unregister_port(port, ec[i]->irq, 16);
+			ecard_release(ec[i]);
+			ec[i] = NULL;
+		}
+}
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ataraid.c linux-2.4.21/drivers/ide/ataraid.c
--- linux-2.4.20/drivers/ide/ataraid.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ide/ataraid.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,313 +0,0 @@
-/*
-   ataraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
-
-   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, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-   
-   Authors: 	Arjan van de Ven <arjanv@redhat.com>
-   		
-   
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <asm/semaphore.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/ioctl.h>
-#include <linux/kdev_t.h>
-#include <linux/swap.h>
-
-#include <linux/ide.h>
-#include <asm/uaccess.h>
-
-#include "ataraid.h"
-
-                                        
-static int ataraid_hardsect_size[256];
-static int ataraid_blksize_size[256];
-
-static struct raid_device_operations* ataraid_ops[16];
-
-static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int ataraid_open(struct inode * inode, struct file * filp);
-static int ataraid_release(struct inode * inode, struct file * filp);
-static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh);
-
-
-struct gendisk ataraid_gendisk;
-static int ataraid_gendisk_sizes[256];
-static int ataraid_readahead[256];
-
-static struct block_device_operations ataraid_fops = {
-	owner:			THIS_MODULE,
-	open:                   ataraid_open,
-	release:                ataraid_release,
-	ioctl:                  ataraid_ioctl,
-};
-                
-
-
-static DECLARE_MUTEX(ataraid_sem);
-
-/* Bitmap for the devices currently in use */
-static unsigned int ataraiduse;
-
-
-/* stub fops functions */
-
-static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)  
-{
-	int minor;
-	minor = MINOR(inode->i_rdev)>>SHIFT;
-	
-	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->ioctl))
-		return (ataraid_ops[minor]->ioctl)(inode,file,cmd,arg);
-	return -EINVAL;
-}
-
-static int ataraid_open(struct inode * inode, struct file * filp)
-{
-	int minor;
-	minor = MINOR(inode->i_rdev)>>SHIFT;
-
-	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->open))
-		return (ataraid_ops[minor]->open)(inode,filp);
-	return -EINVAL;
-}
-
-
-static int ataraid_release(struct inode * inode, struct file * filp)
-{
-	int minor;
-	minor = MINOR(inode->i_rdev)>>SHIFT;
-
-	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->release))
-		return (ataraid_ops[minor]->release)(inode,filp);
-	return -EINVAL;
-}
-
-static int ataraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	int minor;
-	int retval;
-	minor = MINOR(bh->b_rdev)>>SHIFT;
-
-	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->make_request)) {
-		
-		retval= (ataraid_ops[minor]->make_request)(q,rw,bh);
-		if (retval == -1) {
-			ataraid_split_request(q,rw,bh);		
-			return 0;
-		} else
-			return retval;
-	}
-	return -EINVAL;
-}
-
-struct buffer_head *ataraid_get_bhead(void)
-{
-	void *ptr = NULL;
-	while (!ptr) {
-		ptr=kmalloc(sizeof(struct buffer_head),GFP_NOIO);
-		if (!ptr)
-			yield();
-	}
-	return ptr;
-}
-
-EXPORT_SYMBOL(ataraid_get_bhead);
-
-struct ataraid_bh_private *ataraid_get_private(void)
-{
-	void *ptr = NULL;
-	while (!ptr) {
-		ptr=kmalloc(sizeof(struct ataraid_bh_private),GFP_NOIO);
-		if (!ptr)
-			yield();
-	}
-	return ptr;
-}
-
-EXPORT_SYMBOL(ataraid_get_private);
-
-void ataraid_end_request(struct buffer_head *bh, int uptodate)
-{
-	struct ataraid_bh_private *private = bh->b_private;
-
-	if (private==NULL)
-		BUG();
-
-	if (atomic_dec_and_test(&private->count)) {
-		private->parent->b_end_io(private->parent,uptodate);
-		private->parent = NULL;
-		kfree(private);
-	}
-	kfree(bh);
-}
-
-EXPORT_SYMBOL(ataraid_end_request);
-
-static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	struct buffer_head *bh1,*bh2;
-	struct ataraid_bh_private *private;
-	bh1=ataraid_get_bhead();
-	bh2=ataraid_get_bhead();
-
-	/* If either of those ever fails we're doomed */
-	if ((!bh1)||(!bh2))
-		BUG();
-	private = ataraid_get_private();
-	if (private==NULL)
-		BUG();
-	
-	memcpy(bh1, bh, sizeof(*bh));
-	memcpy(bh2, bh, sizeof(*bh));
-	
-	bh1->b_end_io = ataraid_end_request;
-	bh2->b_end_io = ataraid_end_request;
-
-	bh2->b_rsector += bh->b_size >> 10;
-	bh1->b_size /= 2;
-	bh2->b_size /= 2;
-	private->parent = bh;
-
-	bh1->b_private = private;
-	bh2->b_private = private;
-	atomic_set(&private->count,2);
-
-	bh2->b_data +=  bh->b_size/2;
-
-	generic_make_request(rw,bh1);
-	generic_make_request(rw,bh2);
-}
-
-
-
-
-/* device register / release functions */
-
-
-int ataraid_get_device(struct raid_device_operations *fops)
-{
-	int bit;
-	down(&ataraid_sem);
-	if (ataraiduse==~0U) {
-		up(&ataraid_sem);
-		return -ENODEV;
-	}
-	bit=ffz(ataraiduse); 
-	ataraiduse |= 1<<bit;
-	ataraid_ops[bit] = fops;
-	up(&ataraid_sem);
-	return bit;
-}
-
-void ataraid_release_device(int device)
-{
-	down(&ataraid_sem);
-	
-	if ((ataraiduse & (1<<device))==0)
-		BUG();	/* device wasn't registered at all */
-	
-	ataraiduse &= ~(1<<device);
-	ataraid_ops[device] = NULL;
-	up(&ataraid_sem);
-}
-
-void ataraid_register_disk(int device,long size)
-{
-	register_disk(&ataraid_gendisk, MKDEV(ATAMAJOR,16*device),16,
-		&ataraid_fops,size);
-
-}
-
-static __init int ataraid_init(void) 
-{
-	int i;
-        for(i=0;i<256;i++)
-	{
-        	ataraid_hardsect_size[i] = 512;
-		ataraid_blksize_size[i] = 1024;  
-		ataraid_readahead[i] = 1023;
-	}
-	
-	if (blksize_size[ATAMAJOR]==NULL)
-		blksize_size[ATAMAJOR] = ataraid_blksize_size;
-	if (hardsect_size[ATAMAJOR]==NULL)
-		hardsect_size[ATAMAJOR] = ataraid_hardsect_size;
-	
-	
-	/* setup the gendisk structure */	
-	ataraid_gendisk.part = kmalloc(256 * sizeof(struct hd_struct),GFP_KERNEL);
-	if (ataraid_gendisk.part==NULL) {
-		printk(KERN_ERR "ataraid: Couldn't allocate memory, aborting \n");
-		return -1;
-	}
-	
-	memset(&ataraid_gendisk.part[0],0,256*sizeof(struct hd_struct));
-	
-	
-	ataraid_gendisk.major       = ATAMAJOR;
-	ataraid_gendisk.major_name  = "ataraid";
-	ataraid_gendisk.minor_shift = 4;
-	ataraid_gendisk.max_p	    = 15;
-	ataraid_gendisk.sizes	    = &ataraid_gendisk_sizes[0];
-	ataraid_gendisk.nr_real	    = 16;
-	ataraid_gendisk.fops        = &ataraid_fops;
-	
-	
-	add_gendisk(&ataraid_gendisk);
-			
-	if (register_blkdev(ATAMAJOR, "ataraid", &ataraid_fops)) {
-		printk(KERN_ERR "ataraid: Could not get major %d \n",ATAMAJOR);
-		return -1;
-	}
-	
-	                
-	
-	blk_queue_make_request(BLK_DEFAULT_QUEUE(ATAMAJOR),ataraid_make_request);
-                                                                                     	
-	return 0;                                                        	
-}
-
-
-static void __exit ataraid_exit(void)
-{
-	unregister_blkdev(ATAMAJOR, "ataraid");
-	hardsect_size[ATAMAJOR] = NULL;
-	blk_size[ATAMAJOR] = NULL;
-	blksize_size[ATAMAJOR] = NULL;                       
-	max_readahead[ATAMAJOR] = NULL;
-
-	del_gendisk(&ataraid_gendisk);
-        
-	if (ataraid_gendisk.part) {
-		kfree(ataraid_gendisk.part);
-		ataraid_gendisk.part = NULL;
-	}
-}
-
-module_init(ataraid_init);
-module_exit(ataraid_exit);
-
-
-
-EXPORT_SYMBOL(ataraid_get_device);
-EXPORT_SYMBOL(ataraid_release_device);
-EXPORT_SYMBOL(ataraid_gendisk);
-EXPORT_SYMBOL(ataraid_register_disk);
-MODULE_LICENSE("GPL");
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ataraid.h linux-2.4.21/drivers/ide/ataraid.h
--- linux-2.4.20/drivers/ide/ataraid.h	2001-10-08 20:32:28.000000000 +0000
+++ linux-2.4.21/drivers/ide/ataraid.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,72 +0,0 @@
-/*
-   ataraid.h  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
-
-   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, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-   
-   Authors: 	Arjan van de Ven <arjanv@redhat.com>
-   		
-   
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <asm/semaphore.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/ioctl.h>
-
-#include <linux/ide.h>
-#include <asm/uaccess.h>
-
-#define ATAMAJOR 114
-#define SHIFT 4
-#define MINOR_MASK 15
-#define MAJOR_MASK 15
-
-                                        
-/* raid_device_operations is a light struct block_device_operations with an
-   added method for make_request */
-struct raid_device_operations {
-	int (*open) (struct inode *, struct file *);
-	int (*release) (struct inode *, struct file *);
-	int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
-	int (*make_request) (request_queue_t *q, int rw, struct buffer_head * bh);
-};
-
-
-struct geom {
-	unsigned char heads;
-	unsigned int cylinders;
-	unsigned char sectors;
-};
-
-/* structure for the splitting of bufferheads */
-
-struct ataraid_bh_private {
-	struct buffer_head *parent;
-	atomic_t count;
-};
-
-extern struct gendisk ataraid_gendisk;
-
-extern int ataraid_get_device(struct raid_device_operations *fops);
-extern void ataraid_release_device(int device);
-extern int get_blocksize(kdev_t dev);
-extern void ataraid_register_disk(int device,long size);
-extern struct buffer_head *ataraid_get_bhead(void);
-extern struct ataraid_bh_private *ataraid_get_private(void);
-extern void ataraid_end_request(struct buffer_head *bh, int uptodate);
-
-
-
-
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/buddha.c linux-2.4.21/drivers/ide/buddha.c
--- linux-2.4.20/drivers/ide/buddha.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/buddha.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,225 +0,0 @@
-/*
- *  linux/drivers/ide/buddha.c -- Amiga Buddha, Catweasel and X-Surf IDE Driver
- *
- *	Copyright (C) 1997, 2001 by Geert Uytterhoeven and others
- *
- *  This driver was written based on the specifications in README.buddha and
- *  the X-Surf info from Inside_XSurf.txt available at
- *  http://www.jschoenfeld.com
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- *
- *  TODO:
- *    - test it :-)
- *    - tune the timings using the speed-register
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/zorro.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-
-
-    /*
-     *  The Buddha has 2 IDE interfaces, the Catweasel has 3, X-Surf has 2
-     */
-
-#define BUDDHA_NUM_HWIFS	2
-#define CATWEASEL_NUM_HWIFS	3
-#define XSURF_NUM_HWIFS         2
-
-    /*
-     *  Bases of the IDE interfaces (relative to the board address)
-     */
-
-#define BUDDHA_BASE1	0x800
-#define BUDDHA_BASE2	0xa00
-#define BUDDHA_BASE3	0xc00
-
-#define XSURF_BASE1     0xb000 /* 2.5" Interface */
-#define XSURF_BASE2     0xd000 /* 3.5" Interface */
-
-static u_int buddha_bases[CATWEASEL_NUM_HWIFS] __initdata = {
-    BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
-};
-
-static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = {
-     XSURF_BASE1, XSURF_BASE2
-};
-
-
-    /*
-     *  Offsets from one of the above bases
-     */
-
-#define BUDDHA_DATA	0x00
-#define BUDDHA_ERROR	0x06		/* see err-bits */
-#define BUDDHA_NSECTOR	0x0a		/* nr of sectors to read/write */
-#define BUDDHA_SECTOR	0x0e		/* starting sector */
-#define BUDDHA_LCYL	0x12		/* starting cylinder */
-#define BUDDHA_HCYL	0x16		/* high byte of starting cyl */
-#define BUDDHA_SELECT	0x1a		/* 101dhhhh , d=drive, hhhh=head */
-#define BUDDHA_STATUS	0x1e		/* see status-bits */
-#define BUDDHA_CONTROL	0x11a
-#define XSURF_CONTROL   -1              /* X-Surf has no CS1* (Control/AltStat) */
-
-static int buddha_offsets[IDE_NR_PORTS] __initdata = {
-    BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
-    BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL, -1
-};
-
-static int xsurf_offsets[IDE_NR_PORTS] __initdata = {
-    BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
-    BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, XSURF_CONTROL, -1
-};
-
-    /*
-     *  Other registers
-     */
-
-#define BUDDHA_IRQ1	0xf00		/* MSB = 1, Harddisk is source of */
-#define BUDDHA_IRQ2	0xf40		/* interrupt */
-#define BUDDHA_IRQ3	0xf80
-
-#define XSURF_IRQ1      0x7e
-#define XSURF_IRQ2      0x7e
-
-static int buddha_irqports[CATWEASEL_NUM_HWIFS] __initdata = {
-    BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3
-};
-
-static int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = {
-    XSURF_IRQ1, XSURF_IRQ2
-};
-
-#define BUDDHA_IRQ_MR	0xfc0		/* master interrupt enable */
-
-
-    /*
-     *  Board information
-     */
-
-typedef enum BuddhaType_Enum {
-    BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
-} BuddhaType;
-
-
-    /*
-     *  Check and acknowledge the interrupt status
-     */
-
-static int buddha_ack_intr(ide_hwif_t *hwif)
-{
-    unsigned char ch;
-
-    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
-    if (!(ch & 0x80))
-	    return 0;
-    return 1;
-}
-
-static int xsurf_ack_intr(ide_hwif_t *hwif)
-{
-    unsigned char ch;
-
-    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
-    /* X-Surf needs a 0 written to IRQ register to ensure ISA bit A11 stays at 0 */
-    z_writeb(0, hwif->io_ports[IDE_IRQ_OFFSET]); 
-    if (!(ch & 0x80))
-	    return 0;
-    return 1;
-}
-
-    /*
-     *  Probe for a Buddha or Catweasel IDE interface
-     */
-
-void __init buddha_init(void)
-{
-	hw_regs_t hw;
-	int i, index;
-
-	struct zorro_dev *z = NULL;
-	u_long buddha_board = 0;
-	BuddhaType type;
-	int buddha_num_hwifs;
-
-	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
-		unsigned long board;
-		if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
-			buddha_num_hwifs = BUDDHA_NUM_HWIFS;
-			type=BOARD_BUDDHA;
-		} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL) {
-			buddha_num_hwifs = CATWEASEL_NUM_HWIFS;
-			type=BOARD_CATWEASEL;
-		} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF) {
-			buddha_num_hwifs = XSURF_NUM_HWIFS;
-			type=BOARD_XSURF;
-		} else 
-			continue;
-		
-		board = z->resource.start;
-		
-		if(type != BOARD_XSURF) {
-			if (!request_mem_region(board+BUDDHA_BASE1, 0x800, "IDE"))
-				continue;
-		} else {
-			if (!request_mem_region(board+XSURF_BASE1, 0x1000, "IDE"))
-				continue;
-			if (!request_mem_region(board+XSURF_BASE2, 0x1000, "IDE"))
-				goto fail_base2;
-			if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE")) {
-				release_mem_region(board+XSURF_BASE2, 0x1000);
-fail_base2:
-				release_mem_region(board+XSURF_BASE1, 0x1000);
-				continue;
-			}
-		}	  
-		buddha_board = ZTWO_VADDR(board);
-		
-		/* write to BUDDHA_IRQ_MR to enable the board IRQ */
-		/* X-Surf doesn't have this.  IRQs are always on */
-		if (type != BOARD_XSURF)
-			z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
-		
-		for(i=0;i<buddha_num_hwifs;i++) {
-			if(type != BOARD_XSURF) {
-				ide_setup_ports(&hw, (ide_ioreg_t)(buddha_board+buddha_bases[i]),
-						buddha_offsets, 0,
-						(ide_ioreg_t)(buddha_board+buddha_irqports[i]),
-						buddha_ack_intr, IRQ_AMIGA_PORTS);
-			} else {
-				ide_setup_ports(&hw, (ide_ioreg_t)(buddha_board+xsurf_bases[i]),
-						xsurf_offsets, 0,
-						(ide_ioreg_t)(buddha_board+xsurf_irqports[i]),
-						xsurf_ack_intr, IRQ_AMIGA_PORTS);
-			}	
-			
-			index = ide_register_hw(&hw, NULL);
-			if (index != -1) {
-				printk("ide%d: ", index);
-				switch(type) {
-				case BOARD_BUDDHA:
-					printk("Buddha");
-					break;
-				case BOARD_CATWEASEL:
-					printk("Catweasel");
-					break;
-				case BOARD_XSURF:
-					printk("X-Surf");
-					break;
-				}
-				printk(" IDE interface\n");	    
-			}		      
-		}
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/cmd640.c linux-2.4.21/drivers/ide/cmd640.c
--- linux-2.4.20/drivers/ide/cmd640.c	2001-02-17 00:02:36.000000000 +0000
+++ linux-2.4.21/drivers/ide/cmd640.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,856 +0,0 @@
-/*
- *  linux/drivers/ide/cmd640.c		Version 1.02  Sep 01, 1996
- *
- *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below)
- */
-
-/*
- *  Original authors:	abramov@cecmow.enet.dec.com (Igor Abramov)
- *  			mlord@pobox.com (Mark Lord)
- *
- *  See linux/MAINTAINERS for address of current maintainer.
- *
- *  This file provides support for the advanced features and bugs
- *  of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
- *
- *  These chips are basically fucked by design, and getting this driver
- *  to work on every motherboard design that uses this screwed chip seems
- *  bloody well impossible.  However, we're still trying.
- *
- *  Version 0.97 worked for everybody.
- *
- *  User feedback is essential.  Many thanks to the beta test team:
- *
- *  A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com,
- *  bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz,
- *  chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de,
- *  derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de,
- *  flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net,
- *  j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net,
- *  kerouac@ssnet.com, meskes@informatik.rwth-aachen.de, hzoli@cs.elte.hu,
- *  peter@udgaard.isgtec.com, phil@tazenda.demon.co.uk, roadcapw@cfw.com,
- *  s0033las@sun10.vsz.bme.hu, schaffer@tam.cornell.edu, sjd@slip.net,
- *  steve@ei.org, ulrpeg@bigcomm.gun.de, ism@tardis.ed.ac.uk, mack@cray.com
- *  liug@mama.indstate.edu, and others.
- *
- *  Version 0.01	Initial version, hacked out of ide.c,
- *			and #include'd rather than compiled separately.
- *			This will get cleaned up in a subsequent release.
- *
- *  Version 0.02	Fixes for vlb initialization code, enable prefetch
- *			for versions 'B' and 'C' of chip by default,
- *			some code cleanup.
- *
- *  Version 0.03	Added reset of secondary interface,
- *			and black list for devices which are not compatible
- *			with prefetch mode. Separate function for setting
- *			prefetch is added, possibly it will be called some
- *			day from ioctl processing code.
- *
- *  Version 0.04	Now configs/compiles separate from ide.c
- *
- *  Version 0.05	Major rewrite of interface timing code.
- *			Added new function cmd640_set_mode to set PIO mode
- *			from ioctl call. New drives added to black list.
- *
- *  Version 0.06	More code cleanup. Prefetch is enabled only for
- *			detected hard drives, not included in prefetch
- *			black list.
- *
- *  Version 0.07	Changed to more conservative drive tuning policy.
- *			Unknown drives, which report PIO < 4 are set to
- *			(reported_PIO - 1) if it is supported, or to PIO0.
- *			List of known drives extended by info provided by
- *			CMD at their ftp site.
- *
- *  Version 0.08	Added autotune/noautotune support.
- *
- *  Version 0.09	Try to be smarter about 2nd port enabling.
- *  Version 0.10	Be nice and don't reset 2nd port.
- *  Version 0.11	Try to handle more weird situations.
- *
- *  Version 0.12	Lots of bug fixes from Laszlo Peter
- *			irq unmasking disabled for reliability.
- *			try to be even smarter about the second port.
- *			tidy up source code formatting.
- *  Version 0.13	permit irq unmasking again.
- *  Version 0.90	massive code cleanup, some bugs fixed.
- *			defaults all drives to PIO mode0, prefetch off.
- *			autotune is OFF by default, with compile time flag.
- *			prefetch can be turned OFF/ON using "hdparm -p8/-p9"
- *			 (requires hdparm-3.1 or newer)
- *  Version 0.91	first release to linux-kernel list.
- *  Version 0.92	move initial reg dump to separate callable function
- *			change "readahead" to "prefetch" to avoid confusion
- *  Version 0.95	respect original BIOS timings unless autotuning.
- *			tons of code cleanup and rearrangement.
- *			added CONFIG_BLK_DEV_CMD640_ENHANCED option
- *			prevent use of unmask when prefetch is on
- *  Version 0.96	prevent use of io_32bit when prefetch is off
- *  Version 0.97	fix VLB secondary interface for sjd@slip.net
- *			other minor tune-ups:  0.96 was very good.
- *  Version 0.98	ignore PCI version when disabled by BIOS
- *  Version 0.99	display setup/active/recovery clocks with PIO mode
- *  Version 1.00	Mmm.. cannot depend on PCMD_ENA in all systems
- *  Version 1.01	slow/fast devsel can be selected with "hdparm -p6/-p7"
- *			 ("fast" is necessary for 32bit I/O in some systems)
- *  Version 1.02	fix bug that resulted in slow "setup times"
- *			 (patch courtesy of Zoltan Hidvegi)
- */
-
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-#define CMD640_PREFETCH_MASKS 1
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/*
- * This flag is set in ide.c by the parameter:  ide0=cmd640_vlb
- */
-int cmd640_vlb = 0;
-
-/*
- * CMD640 specific registers definition.
- */
-
-#define VID		0x00
-#define DID		0x02
-#define PCMD		0x04
-#define   PCMD_ENA	0x01
-#define PSTTS		0x06
-#define REVID		0x08
-#define PROGIF		0x09
-#define SUBCL		0x0a
-#define BASCL		0x0b
-#define BaseA0		0x10
-#define BaseA1		0x14
-#define BaseA2		0x18
-#define BaseA3		0x1c
-#define INTLINE		0x3c
-#define INPINE		0x3d
-
-#define	CFR		0x50
-#define   CFR_DEVREV		0x03
-#define   CFR_IDE01INTR		0x04
-#define	  CFR_DEVID		0x18
-#define	  CFR_AT_VESA_078h	0x20
-#define	  CFR_DSA1		0x40
-#define	  CFR_DSA0		0x80
-
-#define CNTRL		0x51
-#define	  CNTRL_DIS_RA0		0x40
-#define   CNTRL_DIS_RA1		0x80
-#define	  CNTRL_ENA_2ND		0x08
-
-#define	CMDTIM		0x52
-#define	ARTTIM0		0x53
-#define	DRWTIM0		0x54
-#define ARTTIM1 	0x55
-#define DRWTIM1		0x56
-#define ARTTIM23	0x57
-#define   ARTTIM23_DIS_RA2	0x04
-#define   ARTTIM23_DIS_RA3	0x08
-#define DRWTIM23	0x58
-#define BRST		0x59
-
-/*
- * Registers and masks for easy access by drive index:
- */
-static byte prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
-static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
-
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-
-static byte arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
-static byte drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23};
-
-/*
- * Current cmd640 timing values for each drive.
- * The defaults for each are the slowest possible timings.
- */
-static byte setup_counts[4]    = {4, 4, 4, 4};     /* Address setup count (in clocks) */
-static byte active_counts[4]   = {16, 16, 16, 16}; /* Active count   (encoded) */
-static byte recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */
-
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-
-/*
- * These are initialized to point at the devices we control
- */
-static ide_hwif_t  *cmd_hwif0, *cmd_hwif1;
-static ide_drive_t *cmd_drives[4];
-
-/*
- * Interface to access cmd640x registers
- */
-static unsigned int cmd640_key;
-static void (*put_cmd640_reg)(unsigned short reg, byte val);
-static byte (*get_cmd640_reg)(unsigned short reg);
-
-/*
- * This is read from the CFR reg, and is used in several places.
- */
-static unsigned int cmd640_chip_version;
-
-/*
- * The CMD640x chip does not support DWORD config write cycles, but some
- * of the BIOSes use them to implement the config services.
- * Therefore, we must use direct IO instead.
- */
-
-/* PCI method 1 access */
-
-static void put_cmd640_reg_pci1 (unsigned short reg, byte val)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
-	outb_p(val, (reg & 3) | 0xcfc);
-	restore_flags(flags);
-}
-
-static byte get_cmd640_reg_pci1 (unsigned short reg)
-{
-	byte b;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
-	b = inb_p((reg & 3) | 0xcfc);
-	restore_flags(flags);
-	return b;
-}
-
-/* PCI method 2 access (from CMD datasheet) */
-
-static void put_cmd640_reg_pci2 (unsigned short reg, byte val)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outb_p(0x10, 0xcf8);
-	outb_p(val, cmd640_key + reg);
-	outb_p(0, 0xcf8);
-	restore_flags(flags);
-}
-
-static byte get_cmd640_reg_pci2 (unsigned short reg)
-{
-	byte b;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outb_p(0x10, 0xcf8);
-	b = inb_p(cmd640_key + reg);
-	outb_p(0, 0xcf8);
-	restore_flags(flags);
-	return b;
-}
-
-/* VLB access */
-
-static void put_cmd640_reg_vlb (unsigned short reg, byte val)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outb_p(reg, cmd640_key);
-	outb_p(val, cmd640_key + 4);
-	restore_flags(flags);
-}
-
-static byte get_cmd640_reg_vlb (unsigned short reg)
-{
-	byte b;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outb_p(reg, cmd640_key);
-	b = inb_p(cmd640_key + 4);
-	restore_flags(flags);
-	return b;
-}
-
-static int __init match_pci_cmd640_device (void)
-{
-	const byte ven_dev[4] = {0x95, 0x10, 0x40, 0x06};
-	unsigned int i;
-	for (i = 0; i < 4; i++) {
-		if (get_cmd640_reg(i) != ven_dev[i])
-			return 0;
-	}
-#ifdef STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT
-	if ((get_cmd640_reg(PCMD) & PCMD_ENA) == 0) {
-		printk("ide: cmd640 on PCI disabled by BIOS\n");
-		return 0;
-	}
-#endif /* STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT */
-	return 1; /* success */
-}
-
-/*
- * Probe for CMD640x -- pci method 1
- */
-static int __init probe_for_cmd640_pci1 (void)
-{
-	get_cmd640_reg = get_cmd640_reg_pci1;
-	put_cmd640_reg = put_cmd640_reg_pci1;
-	for (cmd640_key = 0x80000000; cmd640_key <= 0x8000f800; cmd640_key += 0x800) {
-		if (match_pci_cmd640_device())
-			return 1; /* success */
-	}
-	return 0;
-}
-
-/*
- * Probe for CMD640x -- pci method 2
- */
-static int __init probe_for_cmd640_pci2 (void)
-{
-	get_cmd640_reg = get_cmd640_reg_pci2;
-	put_cmd640_reg = put_cmd640_reg_pci2;
-	for (cmd640_key = 0xc000; cmd640_key <= 0xcf00; cmd640_key += 0x100) {
-		if (match_pci_cmd640_device())
-			return 1; /* success */
-	}
-	return 0;
-}
-
-/*
- * Probe for CMD640x -- vlb
- */
-static int __init probe_for_cmd640_vlb (void)
-{
-	byte b;
-
-	get_cmd640_reg = get_cmd640_reg_vlb;
-	put_cmd640_reg = put_cmd640_reg_vlb;
-	cmd640_key = 0x178;
-	b = get_cmd640_reg(CFR);
-	if (b == 0xff || b == 0x00 || (b & CFR_AT_VESA_078h)) {
-		cmd640_key = 0x78;
-		b = get_cmd640_reg(CFR);
-		if (b == 0xff || b == 0x00 || !(b & CFR_AT_VESA_078h))
-			return 0;
-	}
-	return 1; /* success */
-}
-
-/*
- *  Returns 1 if an IDE interface/drive exists at 0x170,
- *  Returns 0 otherwise.
- */
-static int __init secondary_port_responding (void)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-
-	outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET);	/* select drive0 */
-	udelay(100);
-	if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x0a) {
-		outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */
-		udelay(100);
-		if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) {
-			restore_flags(flags);
-			return 0; /* nothing responded */
-		}
-	}
-	restore_flags(flags);
-	return 1; /* success */
-}
-
-#ifdef CMD640_DUMP_REGS
-/*
- * Dump out all cmd640 registers.  May be called from ide.c
- */
-void cmd640_dump_regs (void)
-{
-	unsigned int reg = cmd640_vlb ? 0x50 : 0x00;
-
-	/* Dump current state of chip registers */
-	printk("ide: cmd640 internal register dump:");
-	for (; reg <= 0x59; reg++) {
-		if (!(reg & 0x0f))
-			printk("\n%04x:", reg);
-		printk(" %02x", get_cmd640_reg(reg));
-	}
-	printk("\n");
-}
-#endif
-
-/*
- * Check whether prefetch is on for a drive,
- * and initialize the unmask flags for safe operation.
- */
-static void __init check_prefetch (unsigned int index)
-{
-	ide_drive_t *drive = cmd_drives[index];
-	byte b = get_cmd640_reg(prefetch_regs[index]);
-
-	if (b & prefetch_masks[index]) {	/* is prefetch off? */
-		drive->no_unmask = 0;
-		drive->no_io_32bit = 1;
-		drive->io_32bit = 0;
-	} else {
-#if CMD640_PREFETCH_MASKS
-		drive->no_unmask = 1;
-		drive->unmask = 0;
-#endif
-		drive->no_io_32bit = 0;
-	}
-}
-
-/*
- * Figure out which devices we control
- */
-static void __init setup_device_ptrs (void)
-{
-	unsigned int i;
-
-	cmd_hwif0 = &ide_hwifs[0]; /* default, if not found below */
-	cmd_hwif1 = &ide_hwifs[1]; /* default, if not found below */
-	for (i = 0; i < MAX_HWIFS; i++) {
-		ide_hwif_t *hwif = &ide_hwifs[i];
-		if (hwif->chipset == ide_unknown || hwif->chipset == ide_generic) {
-			if (hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0)
-				cmd_hwif0 = hwif;
-			else if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
-				cmd_hwif1 = hwif;
-		}
-	}
-	cmd_drives[0] = &cmd_hwif0->drives[0];
-	cmd_drives[1] = &cmd_hwif0->drives[1];
-	cmd_drives[2] = &cmd_hwif1->drives[0];
-	cmd_drives[3] = &cmd_hwif1->drives[1];
-}
-
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-
-/*
- * Sets prefetch mode for a drive.
- */
-static void set_prefetch_mode (unsigned int index, int mode)
-{
-	ide_drive_t *drive = cmd_drives[index];
-	int reg = prefetch_regs[index];
-	byte b;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	b = get_cmd640_reg(reg);
-	if (mode) {	/* want prefetch on? */
-#if CMD640_PREFETCH_MASKS
-		drive->no_unmask = 1;
-		drive->unmask = 0;
-#endif
-		drive->no_io_32bit = 0;
-		b &= ~prefetch_masks[index];	/* enable prefetch */
-	} else {
-		drive->no_unmask = 0;
-		drive->no_io_32bit = 1;
-		drive->io_32bit = 0;
-		b |= prefetch_masks[index];	/* disable prefetch */
-	}
-	put_cmd640_reg(reg, b);
-	restore_flags(flags);
-}
-
-/*
- * Dump out current drive clocks settings
- */
-static void display_clocks (unsigned int index)
-{
-	byte active_count, recovery_count;
-
-	active_count = active_counts[index];
-	if (active_count == 1)
-		++active_count;
-	recovery_count = recovery_counts[index];
-	if (active_count > 3 && recovery_count == 1)
-		++recovery_count;
-	if (cmd640_chip_version > 1)
-		recovery_count += 1;  /* cmd640b uses (count + 1)*/
-	printk(", clocks=%d/%d/%d\n", setup_counts[index], active_count, recovery_count);
-}
-
-/*
- * Pack active and recovery counts into single byte representation
- * used by controller
- */
-inline static byte pack_nibbles (byte upper, byte lower)
-{
-	return ((upper & 0x0f) << 4) | (lower & 0x0f);
-}
-
-/*
- * This routine retrieves the initial drive timings from the chipset.
- */
-static void __init retrieve_drive_counts (unsigned int index)
-{
-	byte b;
-
-	/*
-	 * Get the internal setup timing, and convert to clock count
-	 */
-	b = get_cmd640_reg(arttim_regs[index]) & ~0x3f;
-	switch (b) {
-		case 0x00: b = 4; break;
-		case 0x80: b = 3; break;
-		case 0x40: b = 2; break;
-		default:   b = 5; break;
-	}
-	setup_counts[index] = b;
-
-	/*
-	 * Get the active/recovery counts
-	 */
-	b = get_cmd640_reg(drwtim_regs[index]);
-	active_counts[index]   = (b >> 4)   ? (b >> 4)   : 0x10;
-	recovery_counts[index] = (b & 0x0f) ? (b & 0x0f) : 0x10;
-}
-
-
-/*
- * This routine writes the prepared setup/active/recovery counts
- * for a drive into the cmd640 chipset registers to active them.
- */
-static void program_drive_counts (unsigned int index)
-{
-	unsigned long flags;
-	byte setup_count    = setup_counts[index];
-	byte active_count   = active_counts[index];
-	byte recovery_count = recovery_counts[index];
-
-	/*
-	 * Set up address setup count and drive read/write timing registers.
-	 * Primary interface has individual count/timing registers for
-	 * each drive.  Secondary interface has one common set of registers,
-	 * so we merge the timings, using the slowest value for each timing.
-	 */
-	if (index > 1) {
-		unsigned int mate;
-		if (cmd_drives[mate = index ^ 1]->present) {
-			if (setup_count < setup_counts[mate])
-				setup_count = setup_counts[mate];
-			if (active_count < active_counts[mate])
-				active_count = active_counts[mate];
-			if (recovery_count < recovery_counts[mate])
-				recovery_count = recovery_counts[mate];
-		}
-	}
-
-	/*
-	 * Convert setup_count to internal chipset representation
-	 */
-	switch (setup_count) {
-		case 4:	 setup_count = 0x00; break;
-		case 3:	 setup_count = 0x80; break;
-		case 1:
-		case 2:	 setup_count = 0x40; break;
-		default: setup_count = 0xc0; /* case 5 */
-	}
-
-	/*
-	 * Now that everything is ready, program the new timings
-	 */
-	save_flags (flags);
-	cli();
-	/*
-	 * Program the address_setup clocks into ARTTIM reg,
-	 * and then the active/recovery counts into the DRWTIM reg
-	 * (this converts counts of 16 into counts of zero -- okay).
-	 */
-	setup_count |= get_cmd640_reg(arttim_regs[index]) & 0x3f;
-	put_cmd640_reg(arttim_regs[index], setup_count);
-	put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count));
-	restore_flags(flags);
-}
-
-/*
- * Set a specific pio_mode for a drive
- */
-static void cmd640_set_mode (unsigned int index, byte pio_mode, unsigned int cycle_time)
-{
-	int setup_time, active_time, recovery_time, clock_time;
-	byte setup_count, active_count, recovery_count, recovery_count2, cycle_count;
-	int bus_speed = system_bus_clock();
-
-	if (pio_mode > 5)
-		pio_mode = 5;
-	setup_time  = ide_pio_timings[pio_mode].setup_time;
-	active_time = ide_pio_timings[pio_mode].active_time;
-	recovery_time = cycle_time - (setup_time + active_time);
-	clock_time = 1000 / bus_speed;
-	cycle_count = (cycle_time + clock_time - 1) / clock_time;
-
-	setup_count = (setup_time + clock_time - 1) / clock_time;
-
-	active_count = (active_time + clock_time - 1) / clock_time;
-	if (active_count < 2)
-		active_count = 2; /* minimum allowed by cmd640 */
-
-	recovery_count = (recovery_time + clock_time - 1) / clock_time;
-	recovery_count2 = cycle_count - (setup_count + active_count);
-	if (recovery_count2 > recovery_count)
-		recovery_count = recovery_count2;
-	if (recovery_count < 2)
-		recovery_count = 2; /* minimum allowed by cmd640 */
-	if (recovery_count > 17) {
-		active_count += recovery_count - 17;
-		recovery_count = 17;
-	}
-	if (active_count > 16)
-		active_count = 16; /* maximum allowed by cmd640 */
-	if (cmd640_chip_version > 1)
-		recovery_count -= 1;  /* cmd640b uses (count + 1)*/
-	if (recovery_count > 16)
-		recovery_count = 16; /* maximum allowed by cmd640 */
-
-	setup_counts[index]    = setup_count;
-	active_counts[index]   = active_count;
-	recovery_counts[index] = recovery_count;
-
-	/*
-	 * In a perfect world, we might set the drive pio mode here
-	 * (using WIN_SETFEATURE) before continuing.
-	 *
-	 * But we do not, because:
-	 *	1) this is the wrong place to do it (proper is do_special() in ide.c)
-	 * 	2) in practice this is rarely, if ever, necessary
-	 */
-	program_drive_counts (index);
-}
-
-/*
- * Drive PIO mode selection:
- */
-static void cmd640_tune_drive (ide_drive_t *drive, byte mode_wanted)
-{
-	byte b;
-	ide_pio_data_t  d;
-	unsigned int index = 0;
-
-	while (drive != cmd_drives[index]) {
-		if (++index > 3) {
-			printk("%s: bad news in cmd640_tune_drive\n", drive->name);
-			return;
-		}
-	}
-	switch (mode_wanted) {
-		case 6: /* set fast-devsel off */
-		case 7: /* set fast-devsel on */
-			mode_wanted &= 1;
-			b = get_cmd640_reg(CNTRL) & ~0x27;
-			if (mode_wanted)
-				b |= 0x27;
-			put_cmd640_reg(CNTRL, b);
-			printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis");
-			return;
-
-		case 8: /* set prefetch off */
-		case 9: /* set prefetch on */
-			mode_wanted &= 1;
-			set_prefetch_mode(index, mode_wanted);
-			printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");
-			return;
-	}
-
-	(void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
-	cmd640_set_mode (index, d.pio_mode, d.cycle_time);
-
-	printk ("%s: selected cmd640 PIO mode%d (%dns)%s",
-		drive->name,
-		d.pio_mode,
-		d.cycle_time,
-		d.overridden ? " (overriding vendor mode)" : "");
-	display_clocks(index);
-	return;
-}
-
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-
-/*
- * Probe for a cmd640 chipset, and initialize it if found.  Called from ide.c
- */
-int __init ide_probe_for_cmd640x (void)
-{
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-	int second_port_toggled = 0;
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-	int second_port_cmd640 = 0;
-	const char *bus_type, *port2;
-	unsigned int index;
-	byte b, cfr;
-
-	if (cmd640_vlb && probe_for_cmd640_vlb()) {
-		bus_type = "VLB";
-	} else {
-		cmd640_vlb = 0;
-		if (probe_for_cmd640_pci1())
-			bus_type = "PCI (type1)";
-		else if (probe_for_cmd640_pci2())
-			bus_type = "PCI (type2)";
-		else
-			return 0;
-	}
-	/*
-	 * Undocumented magic (there is no 0x5b reg in specs)
-	 */
-	put_cmd640_reg(0x5b, 0xbd);
-	if (get_cmd640_reg(0x5b) != 0xbd) {
-		printk("ide: cmd640 init failed: wrong value in reg 0x5b\n");
-		return 0;
-	}
-	put_cmd640_reg(0x5b, 0);
-
-#ifdef CMD640_DUMP_REGS
-	CMD640_DUMP_REGS;
-#endif
-
-	/*
-	 * Documented magic begins here
-	 */
-	cfr = get_cmd640_reg(CFR);
-	cmd640_chip_version = cfr & CFR_DEVREV;
-	if (cmd640_chip_version == 0) {
-		printk ("ide: bad cmd640 revision: %d\n", cmd640_chip_version);
-		return 0;
-	}
-
-	/*
-	 * Initialize data for primary port
-	 */
-	setup_device_ptrs ();
-	printk("%s: buggy cmd640%c interface on %s, config=0x%02x\n",
-	       cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr);
-	cmd_hwif0->chipset = ide_cmd640;
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-	cmd_hwif0->tuneproc = &cmd640_tune_drive;
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-
-	/*
-	 * Ensure compatibility by always using the slowest timings
-	 * for access to the drive's command register block,
-	 * and reset the prefetch burstsize to default (512 bytes).
-	 *
-	 * Maybe we need a way to NOT do these on *some* systems?
-	 */
-	put_cmd640_reg(CMDTIM, 0);
-	put_cmd640_reg(BRST, 0x40);
-
-	/*
-	 * Try to enable the secondary interface, if not already enabled
-	 */
-	if (cmd_hwif1->noprobe) {
-		port2 = "not probed";
-	} else {
-		b = get_cmd640_reg(CNTRL);
-		if (secondary_port_responding()) {
-			if ((b & CNTRL_ENA_2ND)) {
-				second_port_cmd640 = 1;
-				port2 = "okay";
-			} else if (cmd640_vlb) {
-				second_port_cmd640 = 1;
-				port2 = "alive";
-			} else
-				port2 = "not cmd640";
-		} else {
-			put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */
-			if (secondary_port_responding()) {
-				second_port_cmd640 = 1;
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-				second_port_toggled = 1;
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-				port2 = "enabled";
-			} else {
-				put_cmd640_reg(CNTRL, b); /* restore original setting */
-				port2 = "not responding";
-			}
-		}
-	}
-
-	/*
-	 * Initialize data for secondary cmd640 port, if enabled
-	 */
-	if (second_port_cmd640) {
-		cmd_hwif0->serialized = 1;
-		cmd_hwif1->serialized = 1;
-		cmd_hwif1->chipset = ide_cmd640;
-		cmd_hwif0->mate = cmd_hwif1;
-		cmd_hwif1->mate = cmd_hwif0;
-		cmd_hwif1->channel = 1;
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-		cmd_hwif1->tuneproc = &cmd640_tune_drive;
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-	}
-	printk("%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
-		cmd_hwif0->serialized ? "" : "not ", port2);
-
-	/*
-	 * Establish initial timings/prefetch for all drives.
-	 * Do not unnecessarily disturb any prior BIOS setup of these.
-	 */
-	for (index = 0; index < (2 + (second_port_cmd640 << 1)); index++) {
-		ide_drive_t *drive = cmd_drives[index];
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-		if (drive->autotune || ((index > 1) && second_port_toggled)) {
-	 		/*
-	 		 * Reset timing to the slowest speed and turn off prefetch.
-			 * This way, the drive identify code has a better chance.
-			 */
-			setup_counts    [index] = 4;	/* max possible */
-			active_counts   [index] = 16;	/* max possible */
-			recovery_counts [index] = 16;	/* max possible */
-			program_drive_counts (index);
-			set_prefetch_mode (index, 0);
-			printk("cmd640: drive%d timings/prefetch cleared\n", index);
-		} else {
-			/*
-			 * Record timings/prefetch without changing them.
-			 * This preserves any prior BIOS setup.
-			 */
-			retrieve_drive_counts (index);
-			check_prefetch (index);
-			printk("cmd640: drive%d timings/prefetch(%s) preserved",
-				index, drive->no_io_32bit ? "off" : "on");
-			display_clocks(index);
-		}
-#else
-		/*
-		 * Set the drive unmask flags to match the prefetch setting
-		 */
-		check_prefetch (index);
-		printk("cmd640: drive%d timings/prefetch(%s) preserved\n",
-			index, drive->no_io_32bit ? "off" : "on");
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-	}
-
-#ifdef CMD640_DUMP_REGS
-	CMD640_DUMP_REGS;
-#endif
-	return 1;
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/cmd64x.c linux-2.4.21/drivers/ide/cmd64x.c
--- linux-2.4.20/drivers/ide/cmd64x.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/cmd64x.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1163 +0,0 @@
-/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
- *
- * linux/drivers/ide/cmd64x.c		Version 1.22	June 9, 2000
- *
- * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
- *           Note, this driver is not used at all on other systems because
- *           there the "BIOS" has done all of the following already.
- *           Due to massive hardware bugs, UltraDMA is only supported
- *           on the 646U2 and not on the 646U.
- *
- * Copyright (C) 1998       Eddie C. Dost  (ecd@skynet.be)
- * Copyright (C) 1998       David S. Miller (davem@redhat.com)
- * Copyright (C) 1999-2000  Andre Hedrick <andre@linux-ide.org>
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-
-#define CMD_DEBUG 0
-
-#if CMD_DEBUG
-#define cmdprintk(x...)	printk(##x)
-#else
-#define cmdprintk(x...)
-#endif
-
-/*
- * CMD64x specific registers definition.
- */
-
-#define CFR		0x50
-#define   CFR_INTR_CH0		0x02
-#define CNTRL		0x51
-#define	  CNTRL_DIS_RA0		0x40
-#define   CNTRL_DIS_RA1		0x80
-#define	  CNTRL_ENA_2ND		0x08
-
-#define	CMDTIM		0x52
-#define	ARTTIM0		0x53
-#define	DRWTIM0		0x54
-#define ARTTIM1 	0x55
-#define DRWTIM1		0x56
-#define ARTTIM23	0x57
-#define   ARTTIM23_DIS_RA2	0x04
-#define   ARTTIM23_DIS_RA3	0x08
-#define   ARTTIM23_INTR_CH1	0x10
-#define ARTTIM2		0x57
-#define ARTTIM3		0x57
-#define DRWTIM23	0x58
-#define DRWTIM2		0x58
-#define BRST		0x59
-#define DRWTIM3		0x5b
-
-#define BMIDECR0	0x70
-#define MRDMODE		0x71
-#define   MRDMODE_INTR_CH0	0x04
-#define   MRDMODE_INTR_CH1	0x08
-#define   MRDMODE_BLK_CH0	0x10
-#define   MRDMODE_BLK_CH1	0x20
-#define BMIDESR0	0x72
-#define UDIDETCR0	0x73
-#define DTPR0		0x74
-#define BMIDECR1	0x78
-#define BMIDECSR	0x79
-#define BMIDESR1	0x7A
-#define UDIDETCR1	0x7B
-#define DTPR1		0x7C
-
-#define DISPLAY_CMD64X_TIMINGS
-
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int cmd64x_get_info(char *, char **, off_t, int);
-static int cmd680_get_info(char *, char **, off_t, int);
-extern int (*cmd64x_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-
-static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u8 reg53 = 0, reg54 = 0, reg55 = 0, reg56 = 0;	/* primary */
-	u8 reg57 = 0, reg58 = 0, reg5b;			/* secondary */
-	u8 reg72 = 0, reg73 = 0;			/* primary */
-	u8 reg7a = 0, reg7b = 0;			/* secondary */
-	u8 reg50 = 0, reg71 = 0;			/* extra */
-	u8 hi_byte = 0, lo_byte = 0;
-
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_CMD_649:
-			p += sprintf(p, "\n                                CMD649 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_CMD_648:
-			p += sprintf(p, "\n                                CMD648 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_CMD_646:
-			p += sprintf(p, "\n                                CMD646 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_CMD_643:
-			p += sprintf(p, "\n                                CMD643 Chipset.\n");
-			break;
-		default:
-			p += sprintf(p, "\n                                CMD64? Chipse.\n");
-			break;
-	}
-	(void) pci_read_config_byte(bmide_dev, CFR,       &reg50);
-	(void) pci_read_config_byte(bmide_dev, ARTTIM0,   &reg53);
-	(void) pci_read_config_byte(bmide_dev, DRWTIM0,   &reg54);
-	(void) pci_read_config_byte(bmide_dev, ARTTIM1,   &reg55);
-	(void) pci_read_config_byte(bmide_dev, DRWTIM1,   &reg56);
-	(void) pci_read_config_byte(bmide_dev, ARTTIM2,   &reg57);
-	(void) pci_read_config_byte(bmide_dev, DRWTIM2,   &reg58);
-	(void) pci_read_config_byte(bmide_dev, DRWTIM3,   &reg5b);
-	(void) pci_read_config_byte(bmide_dev, MRDMODE,   &reg71);
-	(void) pci_read_config_byte(bmide_dev, BMIDESR0,  &reg72);
-	(void) pci_read_config_byte(bmide_dev, UDIDETCR0, &reg73);
-	(void) pci_read_config_byte(bmide_dev, BMIDESR1,  &reg7a);
-	(void) pci_read_config_byte(bmide_dev, UDIDETCR1, &reg7b);
-
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %sabled                         %sabled\n",
-		(reg72&0x80)?"dis":" en",(reg7a&0x80)?"dis":" en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-		(reg72&0x20)?"yes":"no ",(reg72&0x40)?"yes":"no ",(reg7a&0x20)?"yes":"no ",(reg7a&0x40)?"yes":"no ");
-	p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)         %s(%s)           %s(%s)\n",
-		(reg72&0x20)?((reg73&0x01)?"UDMA":" DMA"):" PIO",
-		(reg72&0x20)?(  ((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"):
-				((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"):
-				((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"):
-				((reg73&0x00)==0x00)?(((reg73&0x05)==0x05)?"5":"2"):"X"):"?",
-		(reg72&0x40)?((reg73&0x02)?"UDMA":" DMA"):" PIO",
-		(reg72&0x40)?(	((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"):
-				((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"):
-				((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"):
-				((reg73&0x00)==0x00)?(((reg73&0x0A)==0x0A)?"5":"2"):"X"):"?",
-		(reg7a&0x20)?((reg7b&0x01)?"UDMA":" DMA"):" PIO",
-		(reg7a&0x20)?(	((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"):
-				((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"):
-				((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"):
-				((reg7b&0x00)==0x00)?(((reg7b&0x05)==0x05)?"5":"2"):"X"):"?",
-		(reg7a&0x40)?((reg7b&0x02)?"UDMA":" DMA"):" PIO",
-		(reg7a&0x40)?(	((reg7b&0xC0)==0xC0)?(((reg7b&0xC5)==0xC5)?"3":"0"):
-				((reg7b&0x80)==0x80)?(((reg7b&0x85)==0x85)?"3":"1"):
-				((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"):
-				((reg7b&0x00)==0x00)?(((reg7b&0x0A)==0x0A)?"5":"2"):"X"):"?" );
-	p += sprintf(p, "PIO Mode:       %s                %s               %s                 %s\n",
-		"?", "?", "?", "?");
-	p += sprintf(p, "                %s                     %s\n",
-		(reg50 & CFR_INTR_CH0) ? "interrupting" : "polling     ",
-		(reg57 & ARTTIM23_INTR_CH1) ? "interrupting" : "polling");
-	p += sprintf(p, "                %s                          %s\n",
-		(reg71 & MRDMODE_INTR_CH0) ? "pending" : "clear  ",
-		(reg71 & MRDMODE_INTR_CH1) ? "pending" : "clear");
-	p += sprintf(p, "                %s                          %s\n",
-		(reg71 & MRDMODE_BLK_CH0) ? "blocked" : "enabled",
-		(reg71 & MRDMODE_BLK_CH1) ? "blocked" : "enabled");
-
-	SPLIT_BYTE(reg50, hi_byte, lo_byte);
-	p += sprintf(p, "CFR       = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg50, hi_byte, lo_byte);
-	SPLIT_BYTE(reg57, hi_byte, lo_byte);
-	p += sprintf(p, "ARTTIM23  = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg57, hi_byte, lo_byte);
-	SPLIT_BYTE(reg71, hi_byte, lo_byte);
-	p += sprintf(p, "MRDMODE   = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg71, hi_byte, lo_byte);
-
-	return p-buffer;	/* => must be less than 4k! */
-}
-
-static int cmd680_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	p += sprintf(p, "\n                                CMD680 Chipset.\n");
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "PIO Mode:       %s                %s               %s                 %s\n",
-		"?", "?", "?", "?");
-	return p-buffer;	/* => must be less than 4k! */
-}
-
-#endif	/* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte cmd64x_proc = 0;
-byte cmd680_proc = 0;
-
-/*
- * Registers and masks for easy access by drive index:
- */
-#if 0
-static byte prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
-static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
-#endif
-
-/*
- * This routine writes the prepared setup/active/recovery counts
- * for a drive into the cmd646 chipset registers to active them.
- */
-static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count)
-{
-	unsigned long flags;
-	ide_drive_t *drives = HWIF(drive)->drives;
-	byte temp_b;
-	static const byte setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
-	static const byte recovery_counts[] =
-		{15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
-	static const byte arttim_regs[2][2] = {
-			{ ARTTIM0, ARTTIM1 },
-			{ ARTTIM23, ARTTIM23 }
-		};
-	static const byte drwtim_regs[2][2] = {
-			{ DRWTIM0, DRWTIM1 },
-			{ DRWTIM2, DRWTIM3 }
-		};
-	int channel = (int) HWIF(drive)->channel;
-	int slave = (drives != drive);  /* Is this really the best way to determine this?? */
-
-	cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n", setup_count,
-		active_count, recovery_count, drive->present);
-	/*
-	 * Set up address setup count registers.
-	 * Primary interface has individual count/timing registers for
-	 * each drive.  Secondary interface has one common set of registers,
-	 * for address setup so we merge these timings, using the slowest
-	 * value.
-	 */
-	if (channel) {
-		drive->drive_data = setup_count;
-		setup_count = IDE_MAX(drives[0].drive_data, drives[1].drive_data);
-		cmdprintk("Secondary interface, setup_count = %d\n", setup_count);
-	}
-
-	/*
-	 * Convert values to internal chipset representation
-	 */
-	setup_count = (setup_count > 5) ? 0xc0 : (int) setup_counts[setup_count];
-	active_count &= 0xf; /* Remember, max value is 16 */
-	recovery_count = (int) recovery_counts[recovery_count];
-
-	cmdprintk("Final values = %d,%d,%d\n", setup_count, active_count, recovery_count);
-
-	/*
-	 * Now that everything is ready, program the new timings
-	 */
-	__save_flags (flags);
-	__cli();
-	/*
-	 * Program the address_setup clocks into ARTTIM reg,
-	 * and then the active/recovery counts into the DRWTIM reg
-	 */
-	(void) pci_read_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave], &temp_b);
-	(void) pci_write_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave],
-		((byte) setup_count) | (temp_b & 0x3f));
-	(void) pci_write_config_byte(HWIF(drive)->pci_dev, drwtim_regs[channel][slave],
-		(byte) ((active_count << 4) | recovery_count));
-	cmdprintk ("Write %x to %x\n", ((byte) setup_count) | (temp_b & 0x3f), arttim_regs[channel][slave]);
-	cmdprintk ("Write %x to %x\n", (byte) ((active_count << 4) | recovery_count), drwtim_regs[channel][slave]);
-	__restore_flags(flags);
-}
-
-/*
- * Attempts to set the interface PIO mode.
- * The preferred method of selecting PIO modes (e.g. mode 4) is 
- * "echo 'piomode:4' > /proc/ide/hdx/settings".  Special cases are
- * 8: prefetch off, 9: prefetch on, 255: auto-select best mode.
- * Called with 255 at boot time.
- */
-static void cmd64x_tuneproc (ide_drive_t *drive, byte mode_wanted)
-{
-	int setup_time, active_time, recovery_time, clock_time, pio_mode, cycle_time;
-	byte recovery_count2, cycle_count;
-	int setup_count, active_count, recovery_count;
-	int bus_speed = system_bus_clock();
-	/*byte b;*/
-	ide_pio_data_t  d;
-
-	switch (mode_wanted) {
-		case 8: /* set prefetch off */
-		case 9: /* set prefetch on */
-			mode_wanted &= 1;
-			/*set_prefetch_mode(index, mode_wanted);*/
-			cmdprintk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");
-			return;
-	}
-
-	mode_wanted = ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
-	pio_mode = d.pio_mode;
-	cycle_time = d.cycle_time;
-
-	/*
-	 * I copied all this complicated stuff from cmd640.c and made a few minor changes.
-	 * For now I am just going to pray that it is correct.
-	 */
-	if (pio_mode > 5)
-		pio_mode = 5;
-	setup_time  = ide_pio_timings[pio_mode].setup_time;
-	active_time = ide_pio_timings[pio_mode].active_time;
-	recovery_time = cycle_time - (setup_time + active_time);
-	clock_time = 1000 / bus_speed;
-	cycle_count = (cycle_time + clock_time - 1) / clock_time;
-
-	setup_count = (setup_time + clock_time - 1) / clock_time;
-
-	active_count = (active_time + clock_time - 1) / clock_time;
-
-	recovery_count = (recovery_time + clock_time - 1) / clock_time;
-	recovery_count2 = cycle_count - (setup_count + active_count);
-	if (recovery_count2 > recovery_count)
-		recovery_count = recovery_count2;
-	if (recovery_count > 16) {
-		active_count += recovery_count - 16;
-		recovery_count = 16;
-	}
-	if (active_count > 16)
-		active_count = 16; /* maximum allowed by cmd646 */
-
-	/*
-	 * In a perfect world, we might set the drive pio mode here
-	 * (using WIN_SETFEATURE) before continuing.
-	 *
-	 * But we do not, because:
-	 *	1) this is the wrong place to do it (proper is do_special() in ide.c)
-	 * 	2) in practice this is rarely, if ever, necessary
-	 */
-	program_drive_counts (drive, setup_count, active_count, recovery_count);
-
-	cmdprintk("%s: selected cmd646 PIO mode%d : %d (%dns)%s, clocks=%d/%d/%d\n",
-		drive->name, pio_mode, mode_wanted, cycle_time,
-		d.overridden ? " (overriding vendor mode)" : "",
-		setup_count, active_count, recovery_count);
-}
-
-static byte cmd680_taskfile_timing (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte addr_mask		= (hwif->channel) ? 0xB2 : 0xA2;
-	unsigned short		timing;
-
-	pci_read_config_word(dev, addr_mask, &timing);
-
-	switch (timing) {
-		case 0x10c1:	return 4;
-		case 0x10c3:	return 3;
-		case 0x1281:	return 2;
-		case 0x2283:	return 1;
-		case 0x328a:
-		default:	return 0;
-	}
-}
-
-static void cmd680_tuneproc (ide_drive_t *drive, byte mode_wanted)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte			drive_pci;
-	unsigned short		speedt;
-
-	switch (drive->dn) {
-		case 0: drive_pci = 0xA4; break;
-		case 1: drive_pci = 0xA6; break;
-		case 2: drive_pci = 0xB4; break;
-		case 3: drive_pci = 0xB6; break;
-		default: return;
-        }
-
-	pci_read_config_word(dev, drive_pci, &speedt);
-
-	/* cheat for now and use the docs */
-//	switch(cmd680_taskfile_timing(hwif)) {
-	switch(mode_wanted) {
-		case 4:		speedt = 0x10c1; break;
-		case 3:		speedt = 0x10C3; break;
-		case 2:		speedt = 0x1104; break;
-		case 1:		speedt = 0x2283; break;
-		case 0:
-		default:	speedt = 0x328A; break;
-	}
-	pci_write_config_word(dev, drive_pci, speedt);
-}
-
-static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
-{
-	byte speed	= 0x00;
-	byte set_pio	= ide_get_best_pio_mode(drive, 4, 5, NULL);
-
-	cmd64x_tuneproc(drive, set_pio);
-	speed = XFER_PIO_0 + set_pio;
-	if (set_speed)
-		(void) ide_config_drive_speed(drive, speed);
-}
-
-static void config_cmd680_chipset_for_pio (ide_drive_t *drive, byte set_speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	u8 unit			= (drive->select.b.unit & 0x01);
-	u8 addr_mask		= (hwif->channel) ? 0x84 : 0x80;
-	u8 speed		= 0x00;
-	u8 mode_pci		= 0x00;
-	u8 channel_timings	= cmd680_taskfile_timing(hwif);
-	u8 set_pio		= ide_get_best_pio_mode(drive, 4, 5, NULL);
-
-	pci_read_config_byte(dev, addr_mask, &mode_pci);
-	mode_pci &= ~((unit) ? 0x30 : 0x03);
-
-	/* WARNING PIO timing mess is going to happen b/w devices, argh */
-	if ((channel_timings != set_pio) && (set_pio > channel_timings))
-		set_pio = channel_timings;
-
-	cmd680_tuneproc(drive, set_pio);
-	speed = XFER_PIO_0 + set_pio;
-	if (set_speed) {
-		(void) ide_config_drive_speed(drive, speed);
-		drive->current_speed = speed;
-	}
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
-{
-        if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680) {
-		config_cmd680_chipset_for_pio(drive, set_speed);
-	} else {
-		config_cmd64x_chipset_for_pio(drive, set_speed);
-	}
-}
-
-static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	int err			= 0;
-
-	u8 unit			= (drive->select.b.unit & 0x01);
-	u8 pciU			= (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
-	u8 pciD			= (hwif->channel) ? BMIDESR1 : BMIDESR0;
-	u8 regU			= 0;
-	u8 regD			= 0;
-
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))	return 1;
-
-	(void) pci_read_config_byte(dev, pciD, &regD);
-	(void) pci_read_config_byte(dev, pciU, &regU);
-	regD &= ~(unit ? 0x40 : 0x20);
-	regU &= ~(unit ? 0xCA : 0x35);
-	(void) pci_write_config_byte(dev, pciD, regD);
-	(void) pci_write_config_byte(dev, pciU, regU);
-
-	(void) pci_read_config_byte(dev, pciD, &regD);
-	(void) pci_read_config_byte(dev, pciU, &regU);
-	switch(speed) {
-		case XFER_UDMA_5:	regU |= (unit ? 0x0A : 0x05); break;
-		case XFER_UDMA_4:	regU |= (unit ? 0x4A : 0x15); break;
-		case XFER_UDMA_3:	regU |= (unit ? 0x8A : 0x25); break;
-		case XFER_UDMA_2:	regU |= (unit ? 0x42 : 0x11); break;
-		case XFER_UDMA_1:	regU |= (unit ? 0x82 : 0x21); break;
-		case XFER_UDMA_0:	regU |= (unit ? 0xC2 : 0x31); break;
-		case XFER_MW_DMA_2:	regD |= (unit ? 0x40 : 0x10); break;
-		case XFER_MW_DMA_1:	regD |= (unit ? 0x80 : 0x20); break;
-		case XFER_MW_DMA_0:	regD |= (unit ? 0xC0 : 0x30); break;
-		case XFER_SW_DMA_2:	regD |= (unit ? 0x40 : 0x10); break;
-		case XFER_SW_DMA_1:	regD |= (unit ? 0x80 : 0x20); break;
-		case XFER_SW_DMA_0:	regD |= (unit ? 0xC0 : 0x30); break;
-#else
-	int err			= 0;
-
-		switch(speed) {
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:	cmd64x_tuneproc(drive, 4); break;
-		case XFER_PIO_3:	cmd64x_tuneproc(drive, 3); break;
-		case XFER_PIO_2:	cmd64x_tuneproc(drive, 2); break;
-		case XFER_PIO_1:	cmd64x_tuneproc(drive, 1); break;
-		case XFER_PIO_0:	cmd64x_tuneproc(drive, 0); break;
-
-		default:
-			return 1;
-	}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	(void) pci_write_config_byte(dev, pciU, regU);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	err = ide_config_drive_speed(drive, speed);
-
-	drive->current_speed = speed;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	regD |= (unit ? 0x40 : 0x20);
-	(void) pci_write_config_byte(dev, pciD, regD);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	return err;
-}
-
-static int cmd680_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	u8 addr_mask		= (hwif->channel) ? 0x84 : 0x80;
-	u8 unit			= (drive->select.b.unit & 0x01);
-	u8 dma_pci		= 0;
-	u8 udma_pci		= 0;
-	u8 mode_pci		= 0;
-	u8 scsc			= 0;
-	u16 ultra		= 0;
-	u16 multi		= 0;
-	int err			= 0;
-
-        pci_read_config_byte(dev, addr_mask, &mode_pci);
-	pci_read_config_byte(dev, 0x8A, &scsc);
-
-        switch (drive->dn) {
-		case 0: dma_pci = 0xA8; udma_pci = 0xAC; break;
-		case 1: dma_pci = 0xAA; udma_pci = 0xAE; break;
-		case 2: dma_pci = 0xB8; udma_pci = 0xBC; break;
-		case 3: dma_pci = 0xBA; udma_pci = 0xBE; break;
-		default: return 1;
-	}
-
-	pci_read_config_byte(dev, addr_mask, &mode_pci);
-	mode_pci &= ~((unit) ? 0x30 : 0x03);
-	pci_read_config_word(dev, dma_pci, &multi);
-	pci_read_config_word(dev, udma_pci, &ultra);
-
-	if ((speed == XFER_UDMA_6) && (scsc & 0x30) == 0x00) {
-		pci_write_config_byte(dev, 0x8A, scsc|0x01);
-		pci_read_config_byte(dev, 0x8A, &scsc);
-	}
-
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_UDMA_6:
-			if ((scsc & 0x30) == 0x00)
-				goto speed_break;
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= 0x01;
-			break;
-speed_break :
-			speed = XFER_UDMA_5;
-		case XFER_UDMA_5:
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= (((scsc & 0x30) == 0x00) ? 0x01 : 0x02);
-			break;
-		case XFER_UDMA_4:
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= (((scsc & 0x30) == 0x00) ? 0x02 : 0x03);
-			break;
-		case XFER_UDMA_3:
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= (((scsc & 0x30) == 0x00) ? 0x04 : 0x05);
-			break;
-		case XFER_UDMA_2:
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= (((scsc & 0x30) == 0x00) ? 0x05 : 0x07);
-			break;
-		case XFER_UDMA_1:
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= (((scsc & 0x30) == 0x00) ? 0x07 : 0x0B);
-			break;
-		case XFER_UDMA_0:
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= (((scsc & 0x30) == 0x00) ? 0x0C : 0x0F);
-			break;
-		case XFER_MW_DMA_2:
-			multi = 0x10C1;
-			break;
-		case XFER_MW_DMA_1:
-			multi = 0x10C2;
-			break;
-		case XFER_MW_DMA_0:
-			multi = 0x2208;
-			break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:	cmd680_tuneproc(drive, 4); break;
-		case XFER_PIO_3:	cmd680_tuneproc(drive, 3); break;
-		case XFER_PIO_2:	cmd680_tuneproc(drive, 2); break;
-		case XFER_PIO_1:	cmd680_tuneproc(drive, 1); break;
-		case XFER_PIO_0:	cmd680_tuneproc(drive, 0); break;
-		default:
-			return 1;
-	}
-
-	
-	if (speed >= XFER_MW_DMA_0) 
-		config_cmd680_chipset_for_pio(drive, 0);
-
-	if (speed >= XFER_UDMA_0)
-		mode_pci |= ((unit) ? 0x30 : 0x03);
-	else if (speed >= XFER_MW_DMA_0)
-		mode_pci |= ((unit) ? 0x20 : 0x02);
-	else
-		mode_pci |= ((unit) ? 0x10 : 0x01);
-
-	pci_write_config_byte(dev, addr_mask, mode_pci);
-	pci_write_config_word(dev, dma_pci, multi);
-	pci_write_config_word(dev, udma_pci, ultra);
-
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return err;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_cmd64x_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	byte speed		= 0x00;
-	byte set_pio		= 0x00;
-	byte udma_33		= ((rev >= 0x05) || (ultra_66)) ? 1 : 0;
-	byte udma_66		= eighty_ninty_three(drive);
-	byte udma_100		= 0;
-	int rval;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_649: udma_100 = 1; break;
-		case PCI_DEVICE_ID_CMD_648:
-		case PCI_DEVICE_ID_CMD_646:
-		case PCI_DEVICE_ID_CMD_643:
-		default:
-			break;
-	}
-
-	if (drive->media != ide_disk) {
-		cmdprintk("CMD64X: drive->media != ide_disk at double check, inital check failed!!\n");
-		return ((int) ide_dma_off);
-	}
-
-	/* UltraDMA only supported on PCI646U and PCI646U2,
-	 * which correspond to revisions 0x03, 0x05 and 0x07 respectively.
-	 * Actually, although the CMD tech support people won't
-	 * tell me the details, the 0x03 revision cannot support
-	 * UDMA correctly without hardware modifications, and even
-	 * then it only works with Quantum disks due to some
-	 * hold time assumptions in the 646U part which are fixed
-	 * in the 646U2.
-	 * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
-	 */
-	if ((id->dma_ultra & 0x0020) && (udma_100) && (udma_66) && (udma_33)) {
-		speed = XFER_UDMA_5;
-	} else if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33)) {
-		speed = XFER_UDMA_4;
-	} else if ((id->dma_ultra & 0x0008) && (udma_66) && (udma_33)) {
-		speed = XFER_UDMA_3;
-	} else if ((id->dma_ultra & 0x0004) && (udma_33)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (udma_33)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (udma_33)) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_mword & 0x0001) {
-		speed = XFER_MW_DMA_0;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-	} else if (id->dma_1word & 0x0002) {
-		speed = XFER_SW_DMA_1;
-	} else if (id->dma_1word & 0x0001) {
-		speed = XFER_SW_DMA_0;
-	} else {
-		set_pio = 1;
-	}
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	config_chipset_for_pio(drive, set_pio);
-
-	if (set_pio)
-		return ((int) ide_dma_off_quietly);
-
-	if (cmd64x_tune_chipset(drive, speed))
-		return ((int) ide_dma_off);
-
-	rval = (int)(	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-
-	return rval;
-}
-
-static int config_cmd680_chipset_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	byte udma_66		= eighty_ninty_three(drive);
-	byte speed		= 0x00;
-	byte set_pio		= 0x00;
-	int rval;
-
-	if ((id->dma_ultra & 0x0040) && (udma_66))	speed = XFER_UDMA_6;
-	else if ((id->dma_ultra & 0x0020) && (udma_66))	speed = XFER_UDMA_5;
-	else if ((id->dma_ultra & 0x0010) && (udma_66))	speed = XFER_UDMA_4;
-	else if ((id->dma_ultra & 0x0008) && (udma_66))	speed = XFER_UDMA_3;
-	else if (id->dma_ultra & 0x0004)		speed = XFER_UDMA_2;
-	else if (id->dma_ultra & 0x0002)		speed = XFER_UDMA_1;
-	else if (id->dma_ultra & 0x0001)		speed = XFER_UDMA_0;
-	else if (id->dma_mword & 0x0004)		speed = XFER_MW_DMA_2;
-	else if (id->dma_mword & 0x0002)		speed = XFER_MW_DMA_1;
-	else if (id->dma_mword & 0x0001)		speed = XFER_MW_DMA_0;
-	else {
-		set_pio = 1;
-	}
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	config_chipset_for_pio(drive, set_pio);
-
-	if (set_pio)
-		return ((int) ide_dma_off_quietly);
-
-	if (cmd680_tune_chipset(drive, speed))
-		return ((int) ide_dma_off);
-
-	rval = (int)(	((id->dma_ultra >> 14) & 3) ? ide_dma_on :
-			((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-	return rval;
-}
-
-static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
-{
-	if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680)
-		return (config_cmd680_chipset_for_dma(drive));
-	return (config_cmd64x_chipset_for_dma(drive, rev, ultra_66));
-}
-
-static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned int class_rev	= 0;
-	byte can_ultra_33	= 0;
-	byte can_ultra_66	= 0;
-	byte can_ultra_100	= 0;
-	byte can_ultra_133	= 0;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;	
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_680:
-			can_ultra_133 = 1;
-		case PCI_DEVICE_ID_CMD_649:
-			can_ultra_100 = 1;
-		case PCI_DEVICE_ID_CMD_648:
-			can_ultra_66  = 1;
-		case PCI_DEVICE_ID_CMD_643:
-			can_ultra_33  = 1;
-			break;
-		case PCI_DEVICE_ID_CMD_646:
-			can_ultra_33  = (class_rev >= 0x05) ? 1 : 0;
-			can_ultra_66  = 0;
-			can_ultra_100 = 0;
-			break;
-		default:
-			return hwif->dmaproc(ide_dma_off, drive);
-	}
-
-	if ((id != NULL) && ((id->capability & 1) != 0) &&
-	    hwif->autodma && (drive->media == ide_disk)) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if ((id->field_valid & 4) && (can_ultra_33)) {
-			if (id->dma_ultra & 0x007F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive, class_rev, can_ultra_66);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive, class_rev, 0);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive, class_rev, 0);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		config_chipset_for_pio(drive, 1);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-static int cmd680_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return cmd64x_config_drive_for_dma(drive);
-		default:
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-        return ide_dmaproc(func, drive);
-}
-
-static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	byte dma_stat		= 0;
-	byte dma_alt_stat	= 0;
-	byte mask		= (HWIF(drive)->channel) ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0;
-	unsigned long dma_base	= HWIF(drive)->dma_base;
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	byte jack_slap		= ((dev->device == PCI_DEVICE_ID_CMD_648) || (dev->device == PCI_DEVICE_ID_CMD_649)) ? 1 : 0;
-
-	switch (func) {
-		case ide_dma_check:
-			return cmd64x_config_drive_for_dma(drive);
-		case ide_dma_end: /* returns 1 on error, 0 otherwise */
-			drive->waiting_for_dma = 0;
-			outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-			dma_stat = inb(dma_base+2);		/* get DMA status */
-			outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
-			if (jack_slap) {
-				byte dma_intr	= 0;
-				byte dma_mask	= (HWIF(drive)->channel) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
-				byte dma_reg	= (HWIF(drive)->channel) ? ARTTIM2 : CFR;
-				(void) pci_read_config_byte(dev, dma_reg, &dma_intr);
-				/*
-				 * DAMN BMIDE is not connected to PCI space!
-				 * Have to manually jack-slap that bitch!
-				 * To allow the PCI side to read incoming interrupts.
-				 */
-				(void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask);	/* clear the INTR bit */
-			}
-			ide_destroy_dmatable(drive);		/* purge DMA mappings */
-			return (dma_stat & 7) != 4;		/* verify good DMA status */
-		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = inb(dma_base+2);
-			(void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat);
-#ifdef DEBUG
-			printk("%s: dma_stat: 0x%02x dma_alt_stat: 0x%02x mask: 0x%02x\n", drive->name, dma_stat, dma_alt_stat, mask);
-#endif
-			if (!(dma_alt_stat & mask)) {
-				return 0;
-			}
-			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-		default:
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-
-/*
- * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old
- * event order for DMA transfers.
- */
-static int cmd646_1_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned long dma_base = hwif->dma_base;
-	byte dma_stat;
-
-	switch (func) {
-		case ide_dma_check:
-			return cmd64x_config_drive_for_dma(drive);
-		case ide_dma_end:
-			drive->waiting_for_dma = 0;
-			dma_stat = inb(dma_base+2);		/* get DMA status */
-			outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-			outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
-			ide_destroy_dmatable(drive);		/* and free any DMA resources */
-			return (dma_stat & 7) != 4;		/* verify good DMA status */
-		default:
-			break;
-	}
-
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-static int cmd680_busproc (ide_drive_t * drive, int state)
-{
-#if 0
-	ide_hwif_t *hwif	= HWIF(drive);
-	u8 addr_mask		= (hwif->channel) ? 0xB0 : 0xA0;
-	u32 stat_config		= 0;
-
-        pci_read_config_dword(hwif->pci_dev, addr_mask, &stat_config);
-
-	if (!hwif)
-		return -EINVAL;
-
-	switch (state) {
-		case BUSSTATE_ON:
-			hwif->drives[0].failures = 0;
-			hwif->drives[1].failures = 0;
-			break;
-		case BUSSTATE_OFF:
-			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
-			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
-			break;
-		case BUSSTATE_TRISTATE:
-			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
-			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
-			break;
-		default:
-			return 0;
-	}
-	hwif->bus_state = state;
-#endif
-	return 0;
-}
-
-void cmd680_reset (ide_drive_t *drive)
-{
-#if 0
-	ide_hwif_t *hwif	= HWIF(drive);
-	u8 addr_mask		= (hwif->channel) ? 0xB0 : 0xA0;
-	byte reset		= 0;
-
-	pci_read_config_byte(hwif->pci_dev, addr_mask, &reset);
-	pci_write_config_byte(hwif->pci_dev, addr_mask, reset|0x03);
-#endif
-}
-
-unsigned int cmd680_pci_init (struct pci_dev *dev, const char *name)
-{
-	u8 tmpbyte	= 0;	
-	pci_write_config_byte(dev, 0x80, 0x00);
-	pci_write_config_byte(dev, 0x84, 0x00);
-	pci_read_config_byte(dev, 0x8A, &tmpbyte);
-	pci_write_config_byte(dev, 0x8A, tmpbyte|0x01);
-	pci_write_config_word(dev, 0xA2, 0x328A);
-	pci_write_config_dword(dev, 0xA4, 0x328A);
-	pci_write_config_dword(dev, 0xA8, 0x4392);
-	pci_write_config_dword(dev, 0xAC, 0x4009);
-	pci_write_config_word(dev, 0xB2, 0x328A);
-	pci_write_config_dword(dev, 0xB4, 0x328A);
-	pci_write_config_dword(dev, 0xB8, 0x4392);
-	pci_write_config_dword(dev, 0xBC, 0x4009);
-
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!cmd64x_proc) {
-		cmd64x_proc = 1;
-		bmide_dev = dev;
-		cmd64x_display_info = &cmd680_get_info;
-	}
-#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
-	return 0;
-}
-
-unsigned int cmd64x_pci_init (struct pci_dev *dev, const char *name)
-{
-	unsigned char mrdmode;
-	unsigned int class_rev;
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-
-#ifdef __i386__
-	if (dev->resource[PCI_ROM_RESOURCE].start) {
-		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
-	}
-#endif
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_643:
-			break;
-		case PCI_DEVICE_ID_CMD_646:
-			printk("%s: chipset revision 0x%02X, ", name, class_rev);
-			switch(class_rev) {
-				case 0x07:
-				case 0x05:
-					printk("UltraDMA Capable");
-					break;
-				case 0x03:
-					printk("MultiWord DMA Force Limited");
-					break;
-				case 0x01:
-				default:
-					printk("MultiWord DMA Limited, IRQ workaround enabled");
-					break;
-				}
-			printk("\n");
-                        break;
-		case PCI_DEVICE_ID_CMD_648:
-		case PCI_DEVICE_ID_CMD_649:
-			break;
-		default:
-			break;
-	}
-
-	/* Set a good latency timer and cache line size value. */
-	(void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
-#ifdef __sparc_v9__
-	(void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10);
-#endif
-
-
-	/* Setup interrupts. */
-	(void) pci_read_config_byte(dev, MRDMODE, &mrdmode);
-	mrdmode &= ~(0x30);
-	(void) pci_write_config_byte(dev, MRDMODE, mrdmode);
-
-	/* Use MEMORY READ LINE for reads.
-	 * NOTE: Although not mentioned in the PCI0646U specs,
-	 *       these bits are write only and won't be read
-	 *       back as set or not.  The PCI0646U2 specs clarify
-	 *       this point.
-	 */
-	(void) pci_write_config_byte(dev, MRDMODE, mrdmode | 0x02);
-
-	/* Set reasonable active/recovery/address-setup values. */
-	(void) pci_write_config_byte(dev, ARTTIM0,  0x40);
-	(void) pci_write_config_byte(dev, DRWTIM0,  0x3f);
-	(void) pci_write_config_byte(dev, ARTTIM1,  0x40);
-	(void) pci_write_config_byte(dev, DRWTIM1,  0x3f);
-#ifdef __i386__
-	(void) pci_write_config_byte(dev, ARTTIM23, 0x1c);
-#else
-	(void) pci_write_config_byte(dev, ARTTIM23, 0x5c);
-#endif
-	(void) pci_write_config_byte(dev, DRWTIM23, 0x3f);
-	(void) pci_write_config_byte(dev, DRWTIM3,  0x3f);
-#ifdef CONFIG_PPC
-	(void) pci_write_config_byte(dev, UDIDETCR0, 0xf0);
-#endif /* CONFIG_PPC */
-
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!cmd64x_proc) {
-		cmd64x_proc = 1;
-		bmide_dev = dev;
-		cmd64x_display_info = &cmd64x_get_info;
-	}
-#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
-
-	return 0;
-}
-
-unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
-{
-	if (dev->device == PCI_DEVICE_ID_CMD_680)
-		return cmd680_pci_init (dev, name);
-	return cmd64x_pci_init (dev, name);
-}
-
-unsigned int cmd680_ata66 (ide_hwif_t *hwif)
-{
-	byte ata66	= 0;
-	byte addr_mask	= (hwif->channel) ? 0xB0 : 0xA0;
-
-	pci_read_config_byte(hwif->pci_dev, addr_mask, &ata66);
-	return (ata66 & 0x01) ? 1 : 0;
-}
-
-unsigned int cmd64x_ata66 (ide_hwif_t *hwif)
-{
-	byte ata66 = 0;
-	byte mask = (hwif->channel) ? 0x02 : 0x01;
-
-	pci_read_config_byte(hwif->pci_dev, BMIDECSR, &ata66);
-	return (ata66 & mask) ? 1 : 0;
-}
-
-unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev	= hwif->pci_dev;
-	if (dev->device == PCI_DEVICE_ID_CMD_680)
-		return cmd680_ata66(hwif);
-	return cmd64x_ata66(hwif);
-}
-
-void __init ide_init_cmd64x (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned int class_rev;
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-
-	if (!hwif->dma_base)
-		return;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_680:
-			hwif->busproc	= &cmd680_busproc;
-			hwif->dmaproc	= &cmd680_dmaproc;
-			hwif->resetproc = &cmd680_reset;
-			hwif->speedproc	= &cmd680_tune_chipset;
-			hwif->tuneproc	= &cmd680_tuneproc;
-			break;
-		case PCI_DEVICE_ID_CMD_649:
-		case PCI_DEVICE_ID_CMD_648:
-		case PCI_DEVICE_ID_CMD_643:
-			hwif->dmaproc	= &cmd64x_dmaproc;
-			hwif->tuneproc	= &cmd64x_tuneproc;
-			hwif->speedproc = &cmd64x_tune_chipset;
-			break;
-		case PCI_DEVICE_ID_CMD_646:
-			hwif->chipset = ide_cmd646;
-			if (class_rev == 0x01) {
-				hwif->dmaproc = &cmd646_1_dmaproc;
-			} else {
-				hwif->dmaproc = &cmd64x_dmaproc;
-			}
-			hwif->tuneproc	= &cmd64x_tuneproc;
-			hwif->speedproc	= &cmd64x_tune_chipset;
-			break;
-		default:
-			break;
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/cs5530.c linux-2.4.21/drivers/ide/cs5530.c
--- linux-2.4.20/drivers/ide/cs5530.c	2001-01-03 00:58:45.000000000 +0000
+++ linux-2.4.21/drivers/ide/cs5530.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,374 +0,0 @@
-/*
- * linux/drivers/ide/cs5530.c		Version 0.6	Mar. 18, 2000
- *
- * Copyright (C) 2000			Andre Hedrick <andre@linux-ide.org>
- * Ditto of GNU General Public License.
- *
- * Copyright (C) 2000			Mark Lord <mlord@pobox.com>
- * May be copied or modified under the terms of the GNU General Public License
- *
- * Development of this chipset driver was funded
- * by the nice folks at National Semiconductor.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_CS5530_TIMINGS
-
-#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int cs5530_get_info(char *, char **, off_t, int);
-extern int (*cs5530_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-
-static int cs5530_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-	u8  c0 = 0, c1 = 0;
-
-	/*
-	 * at that point bibma+0x2 et bibma+0xa are byte registers
-	 * to investigate:
-	 */
-
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p, "\n                                Cyrix 5530 Chipset.\n");
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %sabled                         %sabled\n",
-			(c0&0x80) ? "dis" : " en",
-			(c1&0x80) ? "dis" : " en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	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 " );
-
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "DMA\n");
-	p += sprintf(p, "PIO\n");
-
-	return p-buffer;
-}
-#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
-
-byte cs5530_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/*
- * Set a new transfer mode at the drive
- */
-int cs5530_set_xfer_mode (ide_drive_t *drive, byte mode)
-{
-	int error = 0;
-
-	printk("%s: cs5530_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode));
-	error = ide_config_drive_speed(drive, mode);
-
-	return error;
-}
-
-/*
- * Here are the standard PIO mode 0-4 timings for each "format".
- * Format-0 uses fast data reg timings, with slower command reg timings.
- * Format-1 uses fast timings for all registers, but won't work with all drives.
- */
-static unsigned int cs5530_pio_timings[2][5] =
-	{{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},
-	 {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}};
-
-/*
- * After chip reset, the PIO timings are set to 0x0000e132, which is not valid.
- */
-#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132)
-#define CS5530_BASEREG(hwif)	(((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20))
-
-/*
- * cs5530_tuneproc() handles selection/setting of PIO modes
- * for both the chipset and drive.
- *
- * The ide_init_cs5530() routine guarantees that all drives
- * will have valid default PIO timings set up before we get here.
- */
-static void cs5530_tuneproc (ide_drive_t *drive, byte pio)	/* pio=255 means "autotune" */
-{
-	ide_hwif_t	*hwif = HWIF(drive);
-	unsigned int	format, basereg = CS5530_BASEREG(hwif);
-	static byte	modes[5] = {XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4};
-
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-	if (!cs5530_set_xfer_mode(drive, modes[pio])) {
-		format = (inl(basereg+4) >> 31) & 1;
-		outl(cs5530_pio_timings[format][pio], basereg+(drive->select.b.unit<<3));
-	}
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * cs5530_config_dma() handles selection/setting of DMA/UDMA modes
- * for both the chipset and drive.
- */
-static int cs5530_config_dma (ide_drive_t *drive)
-{
-	int			udma_ok = 1, mode = 0;
-	ide_hwif_t		*hwif = HWIF(drive);
-	int			unit = drive->select.b.unit;
-	ide_drive_t		*mate = &hwif->drives[unit^1];
-	struct hd_driveid	*id = drive->id;
-	unsigned int		basereg, reg, timings;
-
-
-	/*
-	 * Default to DMA-off in case we run into trouble here.
-	 */
-	(void)hwif->dmaproc(ide_dma_off_quietly, drive);	/* turn off DMA while we fiddle */
-	outb(inb(hwif->dma_base+2)&~(unit?0x40:0x20), hwif->dma_base+2); /* clear DMA_capable bit */
-
-	/*
-	 * The CS5530 specifies that two drives sharing a cable cannot
-	 * mix UDMA/MDMA.  It has to be one or the other, for the pair,
-	 * though different timings can still be chosen for each drive.
-	 * We could set the appropriate timing bits on the fly,
-	 * but that might be a bit confusing.  So, for now we statically
-	 * handle this requirement by looking at our mate drive to see
-	 * what it is capable of, before choosing a mode for our own drive.
-	 */
-	if (mate->present) {
-		struct hd_driveid *mateid = mate->id;
-		if (mateid && (mateid->capability & 1) && !hwif->dmaproc(ide_dma_bad_drive, mate)) {
-			if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7))
-				udma_ok = 1;
-			else if ((mateid->field_valid & 2) && (mateid->dma_mword & 7))
-				udma_ok = 0;
-			else
-				udma_ok = 1;
-		}
-	}
-
-	/*
-	 * Now see what the current drive is capable of,
-	 * selecting UDMA only if the mate said it was ok.
-	 */
-	if (id && (id->capability & 1) && hwif->autodma && !hwif->dmaproc(ide_dma_bad_drive, drive)) {
-		if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) {
-			if      (id->dma_ultra & 4)
-				mode = XFER_UDMA_2;
-			else if (id->dma_ultra & 2)
-				mode = XFER_UDMA_1;
-			else if (id->dma_ultra & 1)
-				mode = XFER_UDMA_0;
-		}
-		if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) {
-			if      (id->dma_mword & 4)
-				mode = XFER_MW_DMA_2;
-			else if (id->dma_mword & 2)
-				mode = XFER_MW_DMA_1;
-			else if (id->dma_mword & 1)
-				mode = XFER_MW_DMA_0;
-		}
-	}
-
-	/*
-	 * Tell the drive to switch to the new mode; abort on failure.
-	 */
-	if (!mode || cs5530_set_xfer_mode(drive, mode))
-		return 1;	/* failure */
-
-	/*
-	 * Now tune the chipset to match the drive:
-	 */
-	switch (mode) {
-		case XFER_UDMA_0:	timings = 0x00921250; break;
-		case XFER_UDMA_1:	timings = 0x00911140; break;
-		case XFER_UDMA_2:	timings = 0x00911030; break;
-		case XFER_MW_DMA_0:	timings = 0x00077771; break;
-		case XFER_MW_DMA_1:	timings = 0x00012121; break;
-		case XFER_MW_DMA_2:	timings = 0x00002020; break;
-		default:
-			printk("%s: cs5530_config_dma: huh? mode=%02x\n", drive->name, mode);
-			return 1;	/* failure */
-	}
-	basereg = CS5530_BASEREG(hwif);
-	reg = inl(basereg+4);			/* get drive0 config register */
-	timings |= reg & 0x80000000;		/* preserve PIO format bit */
-	if (unit == 0) {			/* are we configuring drive0? */
-		outl(timings, basereg+4);	/* write drive0 config register */
-	} else {
-		if (timings & 0x00100000)
-			reg |=  0x00100000;	/* enable UDMA timings for both drives */
-		else
-			reg &= ~0x00100000;	/* disable UDMA timings for both drives */
-		outl(reg,     basereg+4);	/* write drive0 config register */
-		outl(timings, basereg+12);	/* write drive1 config register */
-	}
-	outb(inb(hwif->dma_base+2)|(unit?0x40:0x20), hwif->dma_base+2);	/* set DMA_capable bit */
-
-	/*
-	 * Finally, turn DMA on in software, and exit.
-	 */
-	return hwif->dmaproc(ide_dma_on, drive);	/* success */
-}
-
-/*
- * This is a CS5530-specific wrapper for the standard ide_dmaproc().
- * We need it for our custom "ide_dma_check" function.
- * All other requests are forwarded to the standard ide_dmaproc().
- */
-int cs5530_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return cs5530_config_dma(drive);
-		default:
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * Initialize the cs5530 bridge for reliable IDE DMA operation.
- */
-unsigned int __init pci_init_cs5530 (struct pci_dev *dev, const char *name)
-{
-	struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
-	unsigned short pcicmd = 0;
-	unsigned long flags;
-
-#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!cs5530_proc) {
-		cs5530_proc = 1;
-		bmide_dev = dev;
-		cs5530_display_info = &cs5530_get_info;
-	}
-#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
-
-	pci_for_each_dev (dev) {
-		if (dev->vendor == PCI_VENDOR_ID_CYRIX) {
-			switch (dev->device) {
-				case PCI_DEVICE_ID_CYRIX_PCI_MASTER:
-					master_0 = dev;
-					break;
-				case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
-					cs5530_0 = dev;
-					break;
-			}
-		}
-	}
-	if (!master_0) {
-		printk("%s: unable to locate PCI MASTER function\n", name);
-		return 0;
-	}
-	if (!cs5530_0) {
-		printk("%s: unable to locate CS5530 LEGACY function\n", name);
-		return 0;
-	}
-
-	save_flags(flags);
-	cli();	/* all CPUs (there should only be one CPU with this chipset) */
-
-	/*
-	 * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530:
-	 * -->  OR 0x14 into 16-bit PCI COMMAND reg of function 0 of the cs5530
-	 */
-	pci_read_config_word (cs5530_0, PCI_COMMAND, &pcicmd);
-	pci_write_config_word(cs5530_0, PCI_COMMAND, pcicmd | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE);
-
-	/*
-	 * Set PCI CacheLineSize to 16-bytes:
-	 * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530
-	 */
-	pci_write_config_byte(cs5530_0, PCI_CACHE_LINE_SIZE, 0x04);
-
-	/*
-	 * Disable trapping of UDMA register accesses (Win98 hack):
-	 * --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530
-	 */
-	pci_write_config_word(cs5530_0, 0xd0, 0x5006);
-
-	/*
-	 * Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus:
-	 * The other settings are what is necessary to get the register
-	 * into a sane state for IDE DMA operation.
-	 */
-	pci_write_config_byte(master_0, 0x40, 0x1e);
-
-	/* 
-	 * Set max PCI burst size (16-bytes seems to work best):
-	 *	   16bytes: set bit-1 at 0x41 (reg value of 0x16)
-	 *	all others: clear bit-1 at 0x41, and do:
-	 *	  128bytes: OR 0x00 at 0x41
-	 *	  256bytes: OR 0x04 at 0x41
-	 *	  512bytes: OR 0x08 at 0x41
-	 *	 1024bytes: OR 0x0c at 0x41
-	 */
-	pci_write_config_byte(master_0, 0x41, 0x14);
-
-	/*
-	 * These settings are necessary to get the chip
-	 * into a sane state for IDE DMA operation.
-	 */
-	pci_write_config_byte(master_0, 0x42, 0x00);
-	pci_write_config_byte(master_0, 0x43, 0xc1);
-
-	restore_flags(flags);
-
-	return 0;
-}
-
-/*
- * This gets invoked by the IDE driver once for each channel,
- * and performs channel-specific pre-initialization before drive probing.
- */
-void __init ide_init_cs5530 (ide_hwif_t *hwif)
-{
-	if (hwif->mate)
-		hwif->serialized = hwif->mate->serialized = 1;
-	if (!hwif->dma_base) {
-		hwif->autodma = 0;
-	} else {
-		unsigned int basereg, d0_timings;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		hwif->dmaproc  = &cs5530_dmaproc;
-#else
-		hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-		hwif->tuneproc = &cs5530_tuneproc;
-		basereg = CS5530_BASEREG(hwif);
-		d0_timings = inl(basereg+0);
-		if (CS5530_BAD_PIO(d0_timings)) {	/* PIO timings not initialized? */
-			outl(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+0);
-			if (!hwif->drives[0].autotune)
-				hwif->drives[0].autotune = 1;	/* needs autotuning later */
-		}
-		if (CS5530_BAD_PIO(inl(basereg+8))) {	/* PIO timings not initialized? */
-			outl(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+8);
-			if (!hwif->drives[1].autotune)
-				hwif->drives[1].autotune = 1;	/* needs autotuning later */
-		}
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/cy82c693.c linux-2.4.21/drivers/ide/cy82c693.c
--- linux-2.4.20/drivers/ide/cy82c693.c	2001-05-20 00:43:06.000000000 +0000
+++ linux-2.4.21/drivers/ide/cy82c693.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,449 +0,0 @@
-/*
- * linux/drivers/ide/cy82c693.c		Version 0.34	Dec. 13, 1999
- *
- *  Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
- *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>, Integrater
- *
- * CYPRESS CY82C693 chipset IDE controller
- *
- * The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards.
- * Writting the driver was quite simple, since most of the job is
- * done by the generic pci-ide support. 
- * The hard part was finding the CY82C693's datasheet on Cypress's
- * web page :-(. But Altavista solved this problem :-).
- *
- *
- * Notes:
- * - I recently got a 16.8G IBM DTTA, so I was able to test it with
- *   a large and fast disk - the results look great, so I'd say the
- *   driver is working fine :-)
- *   hdparm -t reports 8.17 MB/sec at about 6% CPU usage for the DTTA 
- * - this is my first linux driver, so there's probably a lot  of room 
- *   for optimizations and bug fixing, so feel free to do it.
- * - use idebus=xx parameter to set PCI bus speed - needed to calc
- *   timings for PIO modes (default will be 40)
- * - if using PIO mode it's a good idea to set the PIO mode and 
- *   32-bit I/O support (if possible), e.g. hdparm -p2 -c1 /dev/hda
- * - I had some problems with my IBM DHEA with PIO modes < 2
- *   (lost interrupts) ?????
- * - first tests with DMA look okay, they seem to work, but there is a
- *   problem with sound - the BusMaster IDE TimeOut should fixed this
- *
- *
- * History:
- * AMH@1999-08-24: v0.34 init_cy82c693_chip moved to pci_init_cy82c693
- * ASK@1999-01-23: v0.33 made a few minor code clean ups
- *                       removed DMA clock speed setting by default
- *                       added boot message
- * ASK@1998-11-01: v0.32 added support to set BusMaster IDE TimeOut
- *                       added support to set DMA Controller Clock Speed
- * ASK@1998-10-31: v0.31 fixed problem with setting to high DMA modes on some drive
- * ASK@1998-10-29: v0.3 added support to set DMA modes
- * ASK@1998-10-28: v0.2 added support to set PIO modes
- * ASK@1998-10-27: v0.1 first version - chipset detection
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/* the current version */
-#define CY82_VERSION	"CY82C693U driver v0.34 99-13-12 Andreas S. Krebs (akrebs@altavista.net)"
-
-/*
- *	The following are used to debug the driver.
- */
-#define	CY82C693_DEBUG_LOGS	0
-#define	CY82C693_DEBUG_INFO	0
-
-/* define CY82C693_SETDMA_CLOCK to set DMA Controller Clock Speed to ATCLK */
-#undef CY82C693_SETDMA_CLOCK
-
-/*
- * note: the value for busmaster timeout is tricky and i got it by trial and error !
- *       using a to low value will cause DMA timeouts and drop IDE performance
- *       using a to high value will cause audio playback to scatter
- *       if you know a better value or how to calc it, please let me know 
- */
-#define BUSMASTER_TIMEOUT	0x50	/* twice the value written in cy82c693ub datasheet */
-/*
- * the value above was tested on my machine and it seems to work okay
- */
-
-/* here are the offset definitions for the registers */
-#define CY82_IDE_CMDREG		0x04
-#define CY82_IDE_ADDRSETUP	0x48
-#define CY82_IDE_MASTER_IOR	0x4C	
-#define CY82_IDE_MASTER_IOW	0x4D	
-#define CY82_IDE_SLAVE_IOR	0x4E	
-#define CY82_IDE_SLAVE_IOW	0x4F
-#define CY82_IDE_MASTER_8BIT	0x50	
-#define CY82_IDE_SLAVE_8BIT	0x51	
-
-#define CY82_INDEX_PORT		0x22
-#define CY82_DATA_PORT		0x23
-
-#define CY82_INDEX_CTRLREG1	0x01
-#define CY82_INDEX_CHANNEL0	0x30
-#define CY82_INDEX_CHANNEL1	0x31
-#define CY82_INDEX_TIMEOUT	0x32
-
-/* the max PIO mode - from datasheet */
-#define CY82C693_MAX_PIO	4
-
-/* the min and max PCI bus speed in MHz - from datasheet */
-#define CY82C963_MIN_BUS_SPEED	25
-#define CY82C963_MAX_BUS_SPEED	33
-
-/* the struct for the PIO mode timings */
-typedef struct pio_clocks_s {
-        byte	address_time;		/* Address setup (clocks) */
-	byte	time_16r;		/* clocks for 16bit IOR (0xF0=Active/data, 0x0F=Recovery) */
-	byte	time_16w;		/* clocks for 16bit IOW (0xF0=Active/data, 0x0F=Recovery) */
-	byte	time_8;			/* clocks for 8bit (0xF0=Active/data, 0x0F=Recovery) */
-} pio_clocks_t;
-
-/*
- * calc clocks using bus_speed
- * returns (rounded up) time in bus clocks for time in ns
- */
-static int calc_clk (int time, int bus_speed)
-{
-	int clocks;
-
-	clocks = (time*bus_speed+999)/1000 -1;
-
-	if (clocks < 0)
-		clocks = 0;
-
-	if (clocks > 0x0F)
-		clocks = 0x0F;
-
-	return clocks;
-}
-
-/*
- * compute the values for the clock registers for PIO
- * mode and pci_clk [MHz] speed
- *
- * NOTE: for mode 0,1 and 2 drives 8-bit IDE command control registers are used
- *       for mode 3 and 4 drives 8 and 16-bit timings are the same
- *
- */ 
-static void compute_clocks (byte pio, pio_clocks_t *p_pclk)
-{
-	int clk1, clk2;
-	int bus_speed = system_bus_clock();	/* get speed of PCI bus */
-
-	/* we don't check against CY82C693's min and max speed,
-	 * so you can play with the idebus=xx parameter
-	 */
-
-	if (pio > CY82C693_MAX_PIO)
-		pio = CY82C693_MAX_PIO;
-
-	/* let's calc the address setup time clocks */
-	p_pclk->address_time = (byte)calc_clk(ide_pio_timings[pio].setup_time, bus_speed);
-
-	/* let's calc the active and recovery time clocks */
-	clk1 = calc_clk(ide_pio_timings[pio].active_time, bus_speed);
-
-	/* calc recovery timing */
-	clk2 =	ide_pio_timings[pio].cycle_time -
-		ide_pio_timings[pio].active_time -
-		ide_pio_timings[pio].setup_time;
-
-	clk2 = calc_clk(clk2, bus_speed);
-
-	clk1 = (clk1<<4)|clk2;	/* combine active and recovery clocks */
-
-	/* note: we use the same values for 16bit IOR and IOW
-         *	those are all the same, since I don't have other
-	 *	timings than those from ide_modes.h
-	 */
-
-	p_pclk->time_16r = (byte)clk1;
-	p_pclk->time_16w = (byte)clk1;
-
-	/* what are good values for 8bit ?? */
-	p_pclk->time_8 = (byte)clk1;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * set DMA mode a specific channel for CY82C693
- */
-static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
-{
-        byte index;
-	byte data;
-
-        if (mode>2)	/* make sure we set a valid mode */
-		mode = 2;
-			   
-	if (mode > drive->id->tDMA)  /* to be absolutly sure we have a valid mode */
-		mode = drive->id->tDMA;
-	
-        index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
-
-#if CY82C693_DEBUG_LOGS
-       	/* for debug let's show the previous values */
-
-	OUT_BYTE(index, CY82_INDEX_PORT);
-	data = IN_BYTE(CY82_DATA_PORT);
-
-	printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, (data&0x3), ((data>>2)&1));
-#endif /* CY82C693_DEBUG_LOGS */
-
-	data = (byte)mode|(byte)(single<<2);
-
-	OUT_BYTE(index, CY82_INDEX_PORT);
-	OUT_BYTE(data, CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, mode, single);
-#endif /* CY82C693_DEBUG_INFO */
-
-	/* 
-	 * note: below we set the value for Bus Master IDE TimeOut Register
-	 * I'm not absolutly sure what this does, but it solved my problem
-	 * with IDE DMA and sound, so I now can play sound and work with
-	 * my IDE driver at the same time :-)
-	 *
-	 * If you know the correct (best) value for this register please
-	 * let me know - ASK
-	 */
-
-	data = BUSMASTER_TIMEOUT;
-	OUT_BYTE(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT);
-	OUT_BYTE(data, CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO	
-	printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n", drive->name, data);
-#endif /* CY82C693_DEBUG_INFO */
-}
-
-/* 
- * used to set DMA mode for CY82C693 (single and multi modes)
- */
-static int cy82c693_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	/*
-	 * if the function is dma on, set dma mode for drive everything
-	 * else is done by the defaul func
-	 */
-	if (func == ide_dma_on) {
-		struct hd_driveid *id = drive->id;
-
-#if CY82C693_DEBUG_INFO
-		printk (KERN_INFO "dma_on: %s\n", drive->name);
-#endif /* CY82C693_DEBUG_INFO */
-
-		if (id != NULL) {		
-                       /* Enable DMA on any drive that has DMA (multi or single) enabled */
-                       if (id->field_valid & 2) {       /* regular DMA */
-			       int mmode, smode;
-
-			       mmode = id->dma_mword & (id->dma_mword >> 8);
-			       smode = id->dma_1word & (id->dma_1word >> 8);
-			       		      
-		               if (mmode != 0)
-				     cy82c693_dma_enable(drive, (mmode >> 1), 0); /* enable multi */
-			       else if (smode != 0)
-				     cy82c693_dma_enable(drive, (smode >> 1), 1); /* enable single */
-			}
-		}
-	}
-        return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * tune ide drive - set PIO mode
- */
-static void cy82c693_tune_drive (ide_drive_t *drive, byte pio)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
-	pio_clocks_t pclk;
-	unsigned int addrCtrl;
-
-	/* select primary or secondary channel */
-	if (hwif->index > 0) {  /* drive is on the secondary channel */
-		dev = pci_find_slot(dev->bus->number, dev->devfn+1);
-		if (!dev) {
-			printk(KERN_ERR "%s: tune_drive: Cannot find secondary interface!\n", drive->name);
-			return;
-		}
-	}
-
-#if CY82C693_DEBUG_LOGS
-	/* for debug let's show the register values */
-	
-       	if (drive->select.b.unit == 0) {
-		/*
-		 * get master drive registers               	
-		 * address setup control register
-		 * is 32 bit !!!
-		 */ 
-	  	pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);                
-		addrCtrl &= 0x0F;
-
-		/* now let's get the remaining registers */
-		pci_read_config_byte(dev, CY82_IDE_MASTER_IOR, &pclk.time_16r);
-		pci_read_config_byte(dev, CY82_IDE_MASTER_IOW, &pclk.time_16w);
-		pci_read_config_byte(dev, CY82_IDE_MASTER_8BIT, &pclk.time_8);
-	} else {
-		/*
-		 * set slave drive registers
-		 * address setup control register
-		 * is 32 bit !!!
-		 */ 
-		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-
-		addrCtrl &= 0xF0;
-		addrCtrl >>= 4;
-
-		/* now let's get the remaining registers */
-		pci_read_config_byte(dev, CY82_IDE_SLAVE_IOR, &pclk.time_16r);
-		pci_read_config_byte(dev, CY82_IDE_SLAVE_IOW, &pclk.time_16w);
-		pci_read_config_byte(dev, CY82_IDE_SLAVE_8BIT, &pclk.time_8);
-	}
-
-	printk (KERN_INFO "%s (ch=%d, dev=%d): PIO timing is (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->channel, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
-#endif /* CY82C693_DEBUG_LOGS */
-
-        /* first let's calc the pio modes */
-	pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO, NULL);
-
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s: Selected PIO mode %d\n", drive->name, pio);
-#endif /* CY82C693_DEBUG_INFO */
-
-        compute_clocks(pio, &pclk);  /* let's calc the values for this PIO mode */
-
-	/* now let's write  the clocks registers */
-	if (drive->select.b.unit == 0) {
-		/*
-		 * set master drive
-		 * address setup control register
-		 * is 32 bit !!!
-		 */ 
-		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-		
-		addrCtrl &= (~0xF);
-		addrCtrl |= (unsigned int)pclk.address_time;
-		pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
-
-		/* now let's set the remaining registers */
-		pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, pclk.time_16r);
-		pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, pclk.time_16w);
-		pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, pclk.time_8);
-		
-		addrCtrl &= 0xF;
-	} else {
-		/*
-		 * set slave drive
-		 * address setup control register
-		 * is 32 bit !!!
-		 */ 
-		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-
-		addrCtrl &= (~0xF0);
-		addrCtrl |= ((unsigned int)pclk.address_time<<4);
-		pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
-
-		/* now let's set the remaining registers */
-		pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, pclk.time_16r);
-		pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, pclk.time_16w);
-		pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, pclk.time_8);
-
-		addrCtrl >>= 4;
-		addrCtrl &= 0xF;
-	}	
-
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->channel, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
-#endif /* CY82C693_DEBUG_INFO */
-}
-
-/*
- * this function is called during init and is used to setup the cy82c693 chip
- */
-/*
- * FIXME! "pci_init_cy82c693" really should replace
- * the "init_cy82c693_chip", it is the correct location to tinker/setup
- * the device prior to INIT.
- */
-
-unsigned int __init pci_init_cy82c693(struct pci_dev *dev, const char *name)
-{
-#ifdef CY82C693_SETDMA_CLOCK
-        byte data;
-#endif /* CY82C693_SETDMA_CLOCK */ 
-
-	/* write info about this verion of the driver */
-	printk (KERN_INFO CY82_VERSION "\n");
-
-#ifdef CY82C693_SETDMA_CLOCK
-       /* okay let's set the DMA clock speed */
-        
-        OUT_BYTE(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
-        data = IN_BYTE(CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n", name, data);
-#endif /* CY82C693_DEBUG_INFO */
-
-        /*
-	 * for some reason sometimes the DMA controller
-	 * speed is set to ATCLK/2 ???? - we fix this here
-	 * 
-	 * note: i don't know what causes this strange behaviour,
-	 *       but even changing the dma speed doesn't solve it :-(
-	 *       the ide performance is still only half the normal speed 
-	 * 
-	 *       if anybody knows what goes wrong with my machine, please
-	 *       let me know - ASK
-         */
-
-	data |= 0x03;
-
-        OUT_BYTE(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
-        OUT_BYTE(data, CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n", name, data);
-#endif /* CY82C693_DEBUG_INFO */
-
-#endif /* CY82C693_SETDMA_CLOCK */
-	return 0;
-}
-
-/*
- * the init function - called for each ide channel once
- */
-void __init ide_init_cy82c693(ide_hwif_t *hwif)
-{
-	hwif->chipset = ide_cy82c693;
-	hwif->tuneproc = &cy82c693_tune_drive;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		hwif->dmaproc = &cy82c693_dmaproc;
-		if (!noautodma)
-			hwif->autodma = 1;
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/dtc2278.c linux-2.4.21/drivers/ide/dtc2278.c
--- linux-2.4.20/drivers/ide/dtc2278.c	2000-04-14 05:54:26.000000000 +0000
+++ linux-2.4.21/drivers/ide/dtc2278.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,134 +0,0 @@
-/*
- *  linux/drivers/ide/dtc2278.c		Version 0.02	Feb 10, 1996
- *
- *  Copyright (C) 1996  Linus Torvalds & author (see below)
- */
-
-#undef REALLY_SLOW_IO           /* most systems can safely undef this */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/*
- * Changing this #undef to #define may solve start up problems in some systems.
- */
-#undef ALWAYS_SET_DTC2278_PIO_MODE
-
-/*
- * From: andy@cercle.cts.com (Dyan Wile)
- *
- * Below is a patch for DTC-2278 - alike software-programmable controllers
- * The code enables the secondary IDE controller and the PIO4 (3?) timings on
- * the primary (EIDE). You may probably have to enable the 32-bit support to
- * get the full speed. You better get the disk interrupts disabled ( hdparm -u0
- * /dev/hd.. ) for the drives connected to the EIDE interface. (I get my
- * filesystem  corrupted with -u1, but under heavy disk load only :-)
- *
- * This card is now forced to use the "serialize" feature,
- * and irq-unmasking is disallowed.  If io_32bit is enabled,
- * it must be done for BOTH drives on each interface.
- *
- * This code was written for the DTC2278E, but might work with any of these:
- *
- * DTC2278S has only a single IDE interface.
- * DTC2278D has two IDE interfaces and is otherwise identical to the S version.
- * DTC2278E also has serial ports and a printer port
- * DTC2278EB: has onboard BIOS, and "works like a charm" -- Kent Bradford <kent@theory.caltech.edu>
- *
- * There may be a fourth controller type. The S and D versions use the
- * Winbond chip, and I think the E version does also.
- *
- */
-
-static void sub22 (char b, char c)
-{
-	int i;
-
-	for(i = 0; i < 3; ++i) {
-		inb(0x3f6);
-		outb_p(b,0xb0);
-		inb(0x3f6);
-		outb_p(c,0xb4);
-		inb(0x3f6);
-		if(inb(0xb4) == c) {
-			outb_p(7,0xb0);
-			inb(0x3f6);
-			return;	/* success */
-		}
-	}
-}
-
-static void tune_dtc2278 (ide_drive_t *drive, byte pio)
-{
-	unsigned long flags;
-
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-
-	if (pio >= 3) {
-		save_flags(flags);	/* all CPUs */
-		cli();			/* all CPUs */
-		/*
-		 * This enables PIO mode4 (3?) on the first interface
-		 */
-		sub22(1,0xc3);
-		sub22(0,0xa0);
-		restore_flags(flags);	/* all CPUs */
-	} else {
-		/* we don't know how to set it back again.. */
-	}
-
-	/*
-	 * 32bit I/O has to be enabled for *both* drives at the same time.
-	 */
-	drive->io_32bit = 1;
-	HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1;
-}
-
-void __init init_dtc2278 (void)
-{
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	/*
-	 * This enables the second interface
-	 */
-	outb_p(4,0xb0);
-	inb(0x3f6);
-	outb_p(0x20,0xb4);
-	inb(0x3f6);
-#ifdef ALWAYS_SET_DTC2278_PIO_MODE
-	/*
-	 * This enables PIO mode4 (3?) on the first interface
-	 * and may solve start-up problems for some people.
-	 */
-	sub22(1,0xc3);
-	sub22(0,0xa0);
-#endif
-	__restore_flags(flags);	/* local CPU only */
-
-	ide_hwifs[0].serialized = 1;
-	ide_hwifs[1].serialized = 1;
-	ide_hwifs[0].chipset = ide_dtc2278;
-	ide_hwifs[1].chipset = ide_dtc2278;
-	ide_hwifs[0].tuneproc = &tune_dtc2278;
-	ide_hwifs[0].drives[0].no_unmask = 1;
-	ide_hwifs[0].drives[1].no_unmask = 1;
-	ide_hwifs[1].drives[0].no_unmask = 1;
-	ide_hwifs[1].drives[1].no_unmask = 1;
-	ide_hwifs[0].mate = &ide_hwifs[1];
-	ide_hwifs[1].mate = &ide_hwifs[0];
-	ide_hwifs[1].channel = 1;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/falconide.c linux-2.4.21/drivers/ide/falconide.c
--- linux-2.4.20/drivers/ide/falconide.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/falconide.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,68 +0,0 @@
-/*
- *  linux/drivers/ide/falconide.c -- Atari Falcon IDE Driver
- *
- *     Created 12 Jul 1997 by Geert Uytterhoeven
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/setup.h>
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#include <asm/atari_stdma.h>
-
-
-    /*
-     *  Base of the IDE interface
-     */
-
-#define ATA_HD_BASE	0xfff00000
-
-    /*
-     *  Offsets from the above base
-     */
-
-#define ATA_HD_DATA	0x00
-#define ATA_HD_ERROR	0x05		/* see err-bits */
-#define ATA_HD_NSECTOR	0x09		/* nr of sectors to read/write */
-#define ATA_HD_SECTOR	0x0d		/* starting sector */
-#define ATA_HD_LCYL	0x11		/* starting cylinder */
-#define ATA_HD_HCYL	0x15		/* high byte of starting cyl */
-#define ATA_HD_SELECT	0x19		/* 101dhhhh , d=drive, hhhh=head */
-#define ATA_HD_STATUS	0x1d		/* see status-bits */
-#define ATA_HD_CONTROL	0x39
-
-static int falconide_offsets[IDE_NR_PORTS] __initdata = {
-    ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL,
-    ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1
-};
-
-
-    /*
-     *  Probe for a Falcon IDE interface
-     */
-
-void __init falconide_init(void)
-{
-    if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) {
-	hw_regs_t hw;
-	int index;
-
-	ide_setup_ports(&hw, (ide_ioreg_t)ATA_HD_BASE, falconide_offsets,
-			0, 0, NULL, IRQ_MFP_IDE);
-	index = ide_register_hw(&hw, NULL);
-
-	if (index != -1)
-	    printk("ide%d: Falcon IDE interface\n", index);
-    }
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/gayle.c linux-2.4.21/drivers/ide/gayle.c
--- linux-2.4.20/drivers/ide/gayle.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/gayle.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,181 +0,0 @@
-/*
- *  linux/drivers/ide/gayle.c -- Amiga Gayle IDE Driver
- *
- *     Created 9 Jul 1997 by Geert Uytterhoeven
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/zorro.h>
-
-#include <asm/setup.h>
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#include <asm/amigayle.h>
-
-
-    /*
-     *  Bases of the IDE interfaces
-     */
-
-#define GAYLE_BASE_4000	0xdd2020	/* A4000/A4000T */
-#define GAYLE_BASE_1200	0xda0000	/* A1200/A600 */
-
-    /*
-     *  Offsets from one of the above bases
-     */
-
-#define GAYLE_DATA	0x00
-#define GAYLE_ERROR	0x06		/* see err-bits */
-#define GAYLE_NSECTOR	0x0a		/* nr of sectors to read/write */
-#define GAYLE_SECTOR	0x0e		/* starting sector */
-#define GAYLE_LCYL	0x12		/* starting cylinder */
-#define GAYLE_HCYL	0x16		/* high byte of starting cyl */
-#define GAYLE_SELECT	0x1a		/* 101dhhhh , d=drive, hhhh=head */
-#define GAYLE_STATUS	0x1e		/* see status-bits */
-#define GAYLE_CONTROL	0x101a
-
-static int gayle_offsets[IDE_NR_PORTS] __initdata = {
-    GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL,
-    GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1
-};
-
-
-    /*
-     *  These are at different offsets from the base
-     */
-
-#define GAYLE_IRQ_4000	0xdd3020	/* MSB = 1, Harddisk is source of */
-#define GAYLE_IRQ_1200	0xda9000	/* interrupt */
-
-
-    /*
-     *  Offset of the secondary port for IDE doublers
-     *  Note that GAYLE_CONTROL is NOT available then!
-     */
-
-#define GAYLE_NEXT_PORT	0x1000
-
-#ifndef CONFIG_BLK_DEV_IDEDOUBLER
-#define GAYLE_NUM_HWIFS		1
-#define GAYLE_NUM_PROBE_HWIFS	GAYLE_NUM_HWIFS
-#define GAYLE_HAS_CONTROL_REG	1
-#define GAYLE_IDEREG_SIZE	0x2000
-#else /* CONFIG_BLK_DEV_IDEDOUBLER */
-#define GAYLE_NUM_HWIFS		2
-#define GAYLE_NUM_PROBE_HWIFS	(ide_doubler ? GAYLE_NUM_HWIFS : \
-					       GAYLE_NUM_HWIFS-1)
-#define GAYLE_HAS_CONTROL_REG	(!ide_doubler)
-#define GAYLE_IDEREG_SIZE	(ide_doubler ? 0x1000 : 0x2000)
-int ide_doubler = 0;	/* support IDE doublers? */
-#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
-
-
-    /*
-     *  Check and acknowledge the interrupt status
-     */
-
-static int gayle_ack_intr_a4000(ide_hwif_t *hwif)
-{
-    unsigned char ch;
-
-    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
-    if (!(ch & GAYLE_IRQ_IDE))
-	return 0;
-    return 1;
-}
-
-static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
-{
-    unsigned char ch;
-
-    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
-    if (!(ch & GAYLE_IRQ_IDE))
-	return 0;
-    (void)z_readb(hwif->io_ports[IDE_STATUS_OFFSET]);
-    z_writeb(0x7c, hwif->io_ports[IDE_IRQ_OFFSET]);
-    return 1;
-}
-
-    /*
-     *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
-     */
-
-void __init gayle_init(void)
-{
-    int a4000, i;
-
-    if (!MACH_IS_AMIGA)
-	return;
-
-    if (!(a4000 = AMIGAHW_PRESENT(A4000_IDE)) && !AMIGAHW_PRESENT(A1200_IDE))
-	return;
-
-    for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
-	ide_ioreg_t base, ctrlport, irqport;
-	ide_ack_intr_t *ack_intr;
-	hw_regs_t hw;
-	int index;
-	unsigned long phys_base, res_start, res_n;
-
-	if (a4000) {
-	    phys_base = GAYLE_BASE_4000;
-	    irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_4000);
-	    ack_intr = gayle_ack_intr_a4000;
-	} else {
-	    phys_base = GAYLE_BASE_1200;
-	    irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_1200);
-	    ack_intr = gayle_ack_intr_a1200;
-	}
-	phys_base += i*GAYLE_NEXT_PORT;
-
-	res_start = ((unsigned long)phys_base) & ~(GAYLE_NEXT_PORT-1);
-	res_n = GAYLE_IDEREG_SIZE;
-
-	if (!request_mem_region(res_start, res_n, "IDE"))
-	    continue;
-
-	base = (ide_ioreg_t)ZTWO_VADDR(phys_base);
-	ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0;
-
-	ide_setup_ports(&hw, base, gayle_offsets,
-			ctrlport, irqport, ack_intr, IRQ_AMIGA_PORTS);
-
-	index = ide_register_hw(&hw, NULL);
-	if (index != -1) {
-	    switch (i) {
-		case 0:
-		    printk("ide%d: Gayle IDE interface (A%d style)\n", index,
-			   a4000 ? 4000 : 1200);
-		    break;
-#ifdef CONFIG_BLK_DEV_IDEDOUBLER
-		case 1:
-		    printk("ide%d: IDE doubler\n", index);
-		    break;
-#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
-	    }
-	} else
-	    release_mem_region(res_start, res_n);
-
-#if 1 /* TESTING */
-	if (i == 1) {
-	    volatile u_short *addr = (u_short *)base;
-	    u_short data;
-	    printk("+++ Probing for IDE doubler... ");
-	    *addr = 0xffff;
-	    data = *addr;
-	    printk("probe returned 0x%02x (PLEASE REPORT THIS!!)\n", data);
-	}
-#endif /* TESTING */
-    }
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/hd.c linux-2.4.21/drivers/ide/hd.c
--- linux-2.4.20/drivers/ide/hd.c	2001-10-15 20:27:42.000000000 +0000
+++ linux-2.4.21/drivers/ide/hd.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,918 +0,0 @@
-/*
- *  linux/drivers/ide/hd.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-/*
- * This is the low-level hd interrupt support. It traverses the
- * request-list, using interrupts to jump between functions. As
- * all the functions are called within interrupts, we may not
- * sleep. Special care is recommended.
- * 
- *  modified by Drew Eckhardt to check nr of hd's from the CMOS.
- *
- *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
- *  in the early extended-partition checks and added DM partitions
- *
- *  IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
- *  and general streamlining by Mark Lord.
- *
- *  Removed 99% of above. Use Mark's ide driver for those options.
- *  This is now a lightweight ST-506 driver. (Paul Gortmaker)
- *
- *  Modified 1995 Russell King for ARM processor.
- *
- *  Bugfix: max_sectors must be <= 255 or the wheels tend to come
- *  off in a hurry once you queue things up - Paul G. 02/2001
- */
-  
-/* Uncomment the following if you want verbose error reports. */
-/* #define VERBOSE_ERRORS */
-  
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/fs.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/kernel.h>
-#include <linux/hdreg.h>
-#include <linux/genhd.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/mc146818rtc.h> /* CMOS defines */
-#include <linux/init.h>
-#include <linux/blkpg.h>
-
-#define REALLY_SLOW_IO
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#define MAJOR_NR HD_MAJOR
-#include <linux/blk.h>
-
-#ifdef __arm__
-#undef  HD_IRQ
-#endif
-#include <asm/irq.h>
-#ifdef __arm__
-#define HD_IRQ IRQ_HARDDISK
-#endif
-
-static int revalidate_hddisk(kdev_t, int);
-
-#define	HD_DELAY	0
-
-#define MAX_ERRORS     16	/* Max read/write errors/sector */
-#define RESET_FREQ      8	/* Reset controller every 8th retry */
-#define RECAL_FREQ      4	/* Recalibrate every 4th retry */
-#define MAX_HD		2
-
-#define STAT_OK		(READY_STAT|SEEK_STAT)
-#define OK_STATUS(s)	(((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK)
-
-static void recal_intr(void);
-static void bad_rw_intr(void);
-
-static char recalibrate[MAX_HD];
-static char special_op[MAX_HD];
-static int access_count[MAX_HD];
-static char busy[MAX_HD];
-static DECLARE_WAIT_QUEUE_HEAD(busy_wait);
-
-static int reset;
-static int hd_error;
-
-#define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0)
-
-/*
- *  This struct defines the HD's and their types.
- */
-struct hd_i_struct {
-	unsigned int head,sect,cyl,wpcom,lzone,ctl;
-};
-	
-#ifdef HD_TYPE
-static struct hd_i_struct hd_info[] = { HD_TYPE };
-static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
-#else
-static struct hd_i_struct hd_info[MAX_HD];
-static int NR_HD;
-#endif
-
-static struct hd_struct hd[MAX_HD<<6];
-static int hd_sizes[MAX_HD<<6];
-static int hd_blocksizes[MAX_HD<<6];
-static int hd_hardsectsizes[MAX_HD<<6];
-static int hd_maxsect[MAX_HD<<6];
-
-static struct timer_list device_timer;
-
-#define SET_TIMER 							\
-	do {								\
-		mod_timer(&device_timer, jiffies + TIMEOUT_VALUE);	\
-	} while (0)
-
-#define CLEAR_TIMER del_timer(&device_timer);
-
-#undef SET_INTR
-
-#define SET_INTR(x) \
-if ((DEVICE_INTR = (x)) != NULL) \
-	SET_TIMER; \
-else \
-	CLEAR_TIMER;
-
-
-#if (HD_DELAY > 0)
-unsigned long last_req;
-
-unsigned long read_timer(void)
-{
-	unsigned long t, flags;
-	int i;
-
-	save_flags(flags);
-	cli();
-	t = jiffies * 11932;
-    	outb_p(0, 0x43);
-	i = inb_p(0x40);
-	i |= inb(0x40) << 8;
-	restore_flags(flags);
-	return(t - i);
-}
-#endif
-
-void __init hd_setup(char *str, int *ints)
-{
-	int hdind = 0;
-
-	if (ints[0] != 3)
-		return;
-	if (hd_info[0].head != 0)
-		hdind=1;
-	hd_info[hdind].head = ints[2];
-	hd_info[hdind].sect = ints[3];
-	hd_info[hdind].cyl = ints[1];
-	hd_info[hdind].wpcom = 0;
-	hd_info[hdind].lzone = ints[1];
-	hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
-	NR_HD = hdind+1;
-}
-
-static void dump_status (const char *msg, unsigned int stat)
-{
-	unsigned long flags;
-	char devc;
-
-	devc = !QUEUE_EMPTY ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
-	save_flags (flags);
-	sti();
-#ifdef VERBOSE_ERRORS
-	printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff);
-	if (stat & BUSY_STAT)	printk("Busy ");
-	if (stat & READY_STAT)	printk("DriveReady ");
-	if (stat & WRERR_STAT)	printk("WriteFault ");
-	if (stat & SEEK_STAT)	printk("SeekComplete ");
-	if (stat & DRQ_STAT)	printk("DataRequest ");
-	if (stat & ECC_STAT)	printk("CorrectedError ");
-	if (stat & INDEX_STAT)	printk("Index ");
-	if (stat & ERR_STAT)	printk("Error ");
-	printk("}\n");
-	if ((stat & ERR_STAT) == 0) {
-		hd_error = 0;
-	} else {
-		hd_error = inb(HD_ERROR);
-		printk("hd%c: %s: error=0x%02x { ", devc, msg, hd_error & 0xff);
-		if (hd_error & BBD_ERR)		printk("BadSector ");
-		if (hd_error & ECC_ERR)		printk("UncorrectableError ");
-		if (hd_error & ID_ERR)		printk("SectorIdNotFound ");
-		if (hd_error & ABRT_ERR)	printk("DriveStatusError ");
-		if (hd_error & TRK0_ERR)	printk("TrackZeroNotFound ");
-		if (hd_error & MARK_ERR)	printk("AddrMarkNotFound ");
-		printk("}");
-		if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
-			printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL),
-				inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
-			if (!QUEUE_EMPTY)
-				printk(", sector=%ld", CURRENT->sector);
-		}
-		printk("\n");
-	}
-#else
-	printk("hd%c: %s: status=0x%02x.\n", devc, msg, stat & 0xff);
-	if ((stat & ERR_STAT) == 0) {
-		hd_error = 0;
-	} else {
-		hd_error = inb(HD_ERROR);
-		printk("hd%c: %s: error=0x%02x.\n", devc, msg, hd_error & 0xff);
-	}
-#endif	/* verbose errors */
-	restore_flags (flags);
-}
-
-void check_status(void)
-{
-	int i = inb_p(HD_STATUS);
-
-	if (!OK_STATUS(i)) {
-		dump_status("check_status", i);
-		bad_rw_intr();
-	}
-}
-
-static int controller_busy(void)
-{
-	int retries = 100000;
-	unsigned char status;
-
-	do {
-		status = inb_p(HD_STATUS);
-	} while ((status & BUSY_STAT) && --retries);
-	return status;
-}
-
-static int status_ok(void)
-{
-	unsigned char status = inb_p(HD_STATUS);
-
-	if (status & BUSY_STAT)
-		return 1;	/* Ancient, but does it make sense??? */
-	if (status & WRERR_STAT)
-		return 0;
-	if (!(status & READY_STAT))
-		return 0;
-	if (!(status & SEEK_STAT))
-		return 0;
-	return 1;
-}
-
-static int controller_ready(unsigned int drive, unsigned int head)
-{
-	int retry = 100;
-
-	do {
-		if (controller_busy() & BUSY_STAT)
-			return 0;
-		outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
-		if (status_ok())
-			return 1;
-	} while (--retry);
-	return 0;
-}
-
-static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
-		unsigned int head,unsigned int cyl,unsigned int cmd,
-		void (*intr_addr)(void))
-{
-	unsigned short port;
-
-#if (HD_DELAY > 0)
-	while (read_timer() - last_req < HD_DELAY)
-		/* nothing */;
-#endif
-	if (reset)
-		return;
-	if (!controller_ready(drive, head)) {
-		reset = 1;
-		return;
-	}
-	SET_INTR(intr_addr);
-	outb_p(hd_info[drive].ctl,HD_CMD);
-	port=HD_DATA;
-	outb_p(hd_info[drive].wpcom>>2,++port);
-	outb_p(nsect,++port);
-	outb_p(sect,++port);
-	outb_p(cyl,++port);
-	outb_p(cyl>>8,++port);
-	outb_p(0xA0|(drive<<4)|head,++port);
-	outb_p(cmd,++port);
-}
-
-static void hd_request (void);
-
-static int drive_busy(void)
-{
-	unsigned int i;
-	unsigned char c;
-
-	for (i = 0; i < 500000 ; i++) {
-		c = inb_p(HD_STATUS);
-		if ((c & (BUSY_STAT | READY_STAT | SEEK_STAT)) == STAT_OK)
-			return 0;
-	}
-	dump_status("reset timed out", c);
-	return 1;
-}
-
-static void reset_controller(void)
-{
-	int	i;
-
-	outb_p(4,HD_CMD);
-	for(i = 0; i < 1000; i++) barrier();
-	outb_p(hd_info[0].ctl & 0x0f,HD_CMD);
-	for(i = 0; i < 1000; i++) barrier();
-	if (drive_busy())
-		printk("hd: controller still busy\n");
-	else if ((hd_error = inb(HD_ERROR)) != 1)
-		printk("hd: controller reset failed: %02x\n",hd_error);
-}
-
-static void reset_hd(void)
-{
-	static int i;
-
-repeat:
-	if (reset) {
-		reset = 0;
-		i = -1;
-		reset_controller();
-	} else {
-		check_status();
-		if (reset)
-			goto repeat;
-	}
-	if (++i < NR_HD) {
-		special_op[i] = recalibrate[i] = 1;
-		hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
-			hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
-		if (reset)
-			goto repeat;
-	} else
-		hd_request();
-}
-
-/*
- * Ok, don't know what to do with the unexpected interrupts: on some machines
- * doing a reset and a retry seems to result in an eternal loop. Right now I
- * ignore it, and just set the timeout.
- *
- * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
- * drive enters "idle", "standby", or "sleep" mode, so if the status looks
- * "good", we just ignore the interrupt completely.
- */
-void unexpected_hd_interrupt(void)
-{
-	unsigned int stat = inb_p(HD_STATUS);
-
-	if (stat & (BUSY_STAT|DRQ_STAT|ECC_STAT|ERR_STAT)) {
-		dump_status ("unexpected interrupt", stat);
-		SET_TIMER;
-	}
-}
-
-/*
- * bad_rw_intr() now tries to be a bit smarter and does things
- * according to the error returned by the controller.
- * -Mika Liljeberg (liljeber@cs.Helsinki.FI)
- */
-static void bad_rw_intr(void)
-{
-	int dev;
-
-	if (QUEUE_EMPTY)
-		return;
-	dev = DEVICE_NR(CURRENT->rq_dev);
-	if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
-		end_request(0);
-		special_op[dev] = recalibrate[dev] = 1;
-	} else if (CURRENT->errors % RESET_FREQ == 0)
-		reset = 1;
-	else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
-		special_op[dev] = recalibrate[dev] = 1;
-	/* Otherwise just retry */
-}
-
-static inline int wait_DRQ(void)
-{
-	int retries = 100000, stat;
-
-	while (--retries > 0)
-		if ((stat = inb_p(HD_STATUS)) & DRQ_STAT)
-			return 0;
-	dump_status("wait_DRQ", stat);
-	return -1;
-}
-
-static void read_intr(void)
-{
-	int i, retries = 100000;
-
-	do {
-		i = (unsigned) inb_p(HD_STATUS);
-		if (i & BUSY_STAT)
-			continue;
-		if (!OK_STATUS(i))
-			break;
-		if (i & DRQ_STAT)
-			goto ok_to_read;
-	} while (--retries > 0);
-	dump_status("read_intr", i);
-	bad_rw_intr();
-	hd_request();
-	return;
-ok_to_read:
-	insw(HD_DATA,CURRENT->buffer,256);
-	CURRENT->sector++;
-	CURRENT->buffer += 512;
-	CURRENT->errors = 0;
-	i = --CURRENT->nr_sectors;
-	--CURRENT->current_nr_sectors;
-#ifdef DEBUG
-	printk("hd%c: read: sector %ld, remaining = %ld, buffer=0x%08lx\n",
-		dev+'a', CURRENT->sector, CURRENT->nr_sectors,
-		(unsigned long) CURRENT->buffer+512));
-#endif
-	if (CURRENT->current_nr_sectors <= 0)
-		end_request(1);
-	if (i > 0) {
-		SET_INTR(&read_intr);
-		return;
-	}
-	(void) inb_p(HD_STATUS);
-#if (HD_DELAY > 0)
-	last_req = read_timer();
-#endif
-	if (!QUEUE_EMPTY)
-		hd_request();
-	return;
-}
-
-static void write_intr(void)
-{
-	int i;
-	int retries = 100000;
-
-	do {
-		i = (unsigned) inb_p(HD_STATUS);
-		if (i & BUSY_STAT)
-			continue;
-		if (!OK_STATUS(i))
-			break;
-		if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
-			goto ok_to_write;
-	} while (--retries > 0);
-	dump_status("write_intr", i);
-	bad_rw_intr();
-	hd_request();
-	return;
-ok_to_write:
-	CURRENT->sector++;
-	i = --CURRENT->nr_sectors;
-	--CURRENT->current_nr_sectors;
-	CURRENT->buffer += 512;
-	if (!i || (CURRENT->bh && !SUBSECTOR(i)))
-		end_request(1);
-	if (i > 0) {
-		SET_INTR(&write_intr);
-		outsw(HD_DATA,CURRENT->buffer,256);
-		sti();
-	} else {
-#if (HD_DELAY > 0)
-		last_req = read_timer();
-#endif
-		hd_request();
-	}
-	return;
-}
-
-static void recal_intr(void)
-{
-	check_status();
-#if (HD_DELAY > 0)
-	last_req = read_timer();
-#endif
-	hd_request();
-}
-
-/*
- * This is another of the error-routines I don't know what to do with. The
- * best idea seems to just set reset, and start all over again.
- */
-static void hd_times_out(unsigned long dummy)
-{
-	unsigned int dev;
-
-	DEVICE_INTR = NULL;
-	if (QUEUE_EMPTY)
-		return;
-	disable_irq(HD_IRQ);
-	sti();
-	reset = 1;
-	dev = DEVICE_NR(CURRENT->rq_dev);
-	printk("hd%c: timeout\n", dev+'a');
-	if (++CURRENT->errors >= MAX_ERRORS) {
-#ifdef DEBUG
-		printk("hd%c: too many errors\n", dev+'a');
-#endif
-		end_request(0);
-	}
-	cli();
-	hd_request();
-	enable_irq(HD_IRQ);
-}
-
-int do_special_op (unsigned int dev)
-{
-	if (recalibrate[dev]) {
-		recalibrate[dev] = 0;
-		hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
-		return reset;
-	}
-	if (hd_info[dev].head > 16) {
-		printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
-		end_request(0);
-	}
-	special_op[dev] = 0;
-	return 1;
-}
-
-/*
- * The driver enables interrupts as much as possible.  In order to do this,
- * (a) the device-interrupt is disabled before entering hd_request(),
- * and (b) the timeout-interrupt is disabled before the sti().
- *
- * Interrupts are still masked (by default) whenever we are exchanging
- * data/cmds with a drive, because some drives seem to have very poor
- * tolerance for latency during I/O. The IDE driver has support to unmask
- * interrupts for non-broken hardware, so use that driver if required.
- */
-static void hd_request(void)
-{
-	unsigned int dev, block, nsect, sec, track, head, cyl;
-
-	if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE) return;
-	if (DEVICE_INTR)
-		return;
-repeat:
-	del_timer(&device_timer);
-	sti();
-	INIT_REQUEST;
-	if (reset) {
-		cli();
-		reset_hd();
-		return;
-	}
-	dev = MINOR(CURRENT->rq_dev);
-	block = CURRENT->sector;
-	nsect = CURRENT->nr_sectors;
-	if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects || ((block+nsect) > hd[dev].nr_sects)) {
-#ifdef DEBUG
-		if (dev >= (NR_HD<<6))
-			printk("hd: bad minor number: device=%s\n",
-			       kdevname(CURRENT->rq_dev));
-		else
-			printk("hd%c: bad access: block=%d, count=%d\n",
-				(MINOR(CURRENT->rq_dev)>>6)+'a', block, nsect);
-#endif
-		end_request(0);
-		goto repeat;
-	}
-	block += hd[dev].start_sect;
-	dev >>= 6;
-	if (special_op[dev]) {
-		if (do_special_op(dev))
-			goto repeat;
-		return;
-	}
-	sec   = block % hd_info[dev].sect + 1;
-	track = block / hd_info[dev].sect;
-	head  = track % hd_info[dev].head;
-	cyl   = track / hd_info[dev].head;
-#ifdef DEBUG
-	printk("hd%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx\n",
-		dev+'a', (CURRENT->cmd == READ)?"read":"writ",
-		cyl, head, sec, nsect, (unsigned long) CURRENT->buffer);
-#endif
-	if (CURRENT->cmd == READ) {
-		hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
-		if (reset)
-			goto repeat;
-		return;
-	}
-	if (CURRENT->cmd == WRITE) {
-		hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
-		if (reset)
-			goto repeat;
-		if (wait_DRQ()) {
-			bad_rw_intr();
-			goto repeat;
-		}
-		outsw(HD_DATA,CURRENT->buffer,256);
-		return;
-	}
-	panic("unknown hd-command");
-}
-
-static void do_hd_request (request_queue_t * q)
-{
-	disable_irq(HD_IRQ);
-	hd_request();
-	enable_irq(HD_IRQ);
-}
-
-static int hd_ioctl(struct inode * inode, struct file * file,
-	unsigned int cmd, unsigned long arg)
-{
-	struct hd_geometry *loc = (struct hd_geometry *) arg;
-	int dev;
-
-	if ((!inode) || !(inode->i_rdev))
-		return -EINVAL;
-	dev = DEVICE_NR(inode->i_rdev);
-	if (dev >= NR_HD)
-		return -EINVAL;
-	switch (cmd) {
-		case HDIO_GETGEO:
-		{
-			struct hd_geometry g; 
-			if (!loc)  return -EINVAL;
-			g.heads = hd_info[dev].head;
-			g.sectors = hd_info[dev].sect;
-			g.cylinders = hd_info[dev].cyl;
-			g.start = hd[MINOR(inode->i_rdev)].start_sect;
-			return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; 
-		}
-
-         	case BLKGETSIZE:   /* Return device size */
-			return put_user(hd[MINOR(inode->i_rdev)].nr_sects, 
-					(unsigned long *) arg);
-         	case BLKGETSIZE64:
-			return put_user((u64)hd[MINOR(inode->i_rdev)].nr_sects << 9, 
-					(u64 *) arg);
-
-		case BLKRRPART: /* Re-read partition tables */
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-			return revalidate_hddisk(inode->i_rdev, 1);
-
-		case BLKROSET:
-		case BLKROGET:
-		case BLKRASET:
-		case BLKRAGET:
-		case BLKFLSBUF:
-		case BLKPG:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
-
-		default:
-			return -EINVAL;
-	}
-}
-
-static int hd_open(struct inode * inode, struct file * filp)
-{
-	int target;
-	target =  DEVICE_NR(inode->i_rdev);
-
-	if (target >= NR_HD)
-		return -ENODEV;
-	while (busy[target])
-		sleep_on(&busy_wait);
-	access_count[target]++;
-	return 0;
-}
-
-/*
- * Releasing a block device means we sync() it, so that it can safely
- * be forgotten about...
- */
-static int hd_release(struct inode * inode, struct file * file)
-{
-        int target =  DEVICE_NR(inode->i_rdev);
-	access_count[target]--;
-	return 0;
-}
-
-extern struct block_device_operations hd_fops;
-
-static struct gendisk hd_gendisk = {
-	major:		MAJOR_NR,
-	major_name:	"hd",
-	minor_shift:	6,
-	max_p:		1 << 6,
-	part:		hd,
-	sizes:		hd_sizes,
-	fops:		&hd_fops,
-};
-	
-static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	void (*handler)(void) = DEVICE_INTR;
-
-	DEVICE_INTR = NULL;
-	del_timer(&device_timer);
-	if (!handler)
-		handler = unexpected_hd_interrupt;
-	handler();
-	sti();
-}
-
-static struct block_device_operations hd_fops = {
-	open:		hd_open,
-	release:	hd_release,
-	ioctl:		hd_ioctl,
-};
-
-/*
- * This is the hard disk IRQ description. The SA_INTERRUPT in sa_flags
- * means we run the IRQ-handler with interrupts disabled:  this is bad for
- * interrupt latency, but anything else has led to problems on some
- * machines.
- *
- * We enable interrupts in some of the routines after making sure it's
- * safe.
- */
-static void __init hd_geninit(void)
-{
-	int drive;
-
-	for(drive=0; drive < (MAX_HD << 6); drive++) {
-		hd_blocksizes[drive] = 1024;
-		hd_hardsectsizes[drive] = 512;
-		hd_maxsect[drive]=255;
-	}
-	blksize_size[MAJOR_NR] = hd_blocksizes;
-	hardsect_size[MAJOR_NR] = hd_hardsectsizes;
-	max_sectors[MAJOR_NR] = hd_maxsect;
-
-#ifdef __i386__
-	if (!NR_HD) {
-		extern struct drive_info drive_info;
-		unsigned char *BIOS = (unsigned char *) &drive_info;
-		unsigned long flags;
-		int cmos_disks;
-
-		for (drive=0 ; drive<2 ; drive++) {
-			hd_info[drive].cyl = *(unsigned short *) BIOS;
-			hd_info[drive].head = *(2+BIOS);
-			hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
-			hd_info[drive].ctl = *(8+BIOS);
-			hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
-			hd_info[drive].sect = *(14+BIOS);
-#ifdef does_not_work_for_everybody_with_scsi_but_helps_ibm_vp
-			if (hd_info[drive].cyl && NR_HD == drive)
-				NR_HD++;
-#endif
-			BIOS += 16;
-		}
-
-	/*
-		We query CMOS about hard disks : it could be that 
-		we have a SCSI/ESDI/etc controller that is BIOS
-		compatible with ST-506, and thus showing up in our
-		BIOS table, but not register compatible, and therefore
-		not present in CMOS.
-
-		Furthermore, we will assume that our ST-506 drives
-		<if any> are the primary drives in the system, and 
-		the ones reflected as drive 1 or 2.
-
-		The first drive is stored in the high nibble of CMOS
-		byte 0x12, the second in the low nibble.  This will be
-		either a 4 bit drive type or 0xf indicating use byte 0x19 
-		for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
-
-		Needless to say, a non-zero value means we have 
-		an AT controller hard disk for that drive.
-
-		Currently the rtc_lock is a bit academic since this
-		driver is non-modular, but someday... ?         Paul G.
-	*/
-
-		spin_lock_irqsave(&rtc_lock, flags);
-		cmos_disks = CMOS_READ(0x12);
-		spin_unlock_irqrestore(&rtc_lock, flags);
-
-		if (cmos_disks & 0xf0) {
-			if (cmos_disks & 0x0f)
-				NR_HD = 2;
-			else
-				NR_HD = 1;
-		}
-	}
-#endif /* __i386__ */
-#ifdef __arm__
-	if (!NR_HD) {
-		/* We don't know anything about the drive.  This means
-		 * that you *MUST* specify the drive parameters to the
-		 * kernel yourself.
-		 */
-		printk("hd: no drives specified - use hd=cyl,head,sectors"
-			" on kernel command line\n");
-	}
-#endif
-
-	for (drive=0 ; drive < NR_HD ; drive++) {
-		hd[drive<<6].nr_sects = hd_info[drive].head *
-			hd_info[drive].sect * hd_info[drive].cyl;
-		printk ("hd%c: %ldMB, CHS=%d/%d/%d\n", drive+'a',
-			hd[drive<<6].nr_sects / 2048, hd_info[drive].cyl,
-			hd_info[drive].head, hd_info[drive].sect);
-	}
-	if (!NR_HD)
-		return;
-
-	if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd", NULL)) {
-		printk("hd: unable to get IRQ%d for the hard disk driver\n",
-			HD_IRQ);
-		NR_HD = 0;
-		return;
-	}
-	request_region(HD_DATA, 8, "hd");
-	request_region(HD_CMD, 1, "hd(cmd)");
-
-	hd_gendisk.nr_real = NR_HD;
-
-	for(drive=0; drive < NR_HD; drive++)
-		register_disk(&hd_gendisk, MKDEV(MAJOR_NR,drive<<6), 1<<6,
-			&hd_fops, hd_info[drive].head * hd_info[drive].sect *
-			hd_info[drive].cyl);
-}
-
-int __init hd_init(void)
-{
-	if (devfs_register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
-		printk("hd: unable to get major %d for hard disk\n",MAJOR_NR);
-		return -1;
-	}
-	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
-	read_ahead[MAJOR_NR] = 8;		/* 8 sector (4kB) read-ahead */
-	add_gendisk(&hd_gendisk);
-	init_timer(&device_timer);
-	device_timer.function = hd_times_out;
-	hd_geninit();
-	return 0;
-}
-
-#define DEVICE_BUSY busy[target]
-#define USAGE access_count[target]
-#define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl)
-/* We assume that the BIOS parameters do not change, so the disk capacity
-   will not change */
-#undef MAYBE_REINIT
-#define GENDISK_STRUCT hd_gendisk
-
-/*
- * This routine is called to flush all partitions and partition tables
- * for a changed disk, and then re-read the new partition table.
- * If we are revalidating a disk because of a media change, then we
- * enter with usage == 0.  If we are using an ioctl, we automatically have
- * usage == 1 (we need an open channel to use an ioctl :-), so this
- * is our limit.
- */
-static int revalidate_hddisk(kdev_t dev, int maxusage)
-{
-	int target;
-	struct gendisk * gdev;
-	int max_p;
-	int start;
-	int i;
-	long flags;
-
-	target = DEVICE_NR(dev);
-	gdev = &GENDISK_STRUCT;
-
-	save_flags(flags);
-	cli();
-	if (DEVICE_BUSY || USAGE > maxusage) {
-		restore_flags(flags);
-		return -EBUSY;
-	}
-	DEVICE_BUSY = 1;
-	restore_flags(flags);
-
-	max_p = gdev->max_p;
-	start = target << gdev->minor_shift;
-
-	for (i=max_p - 1; i >=0 ; i--) {
-		int minor = start + i;
-		invalidate_device(MKDEV(MAJOR_NR, minor), 1);
-		gdev->part[minor].start_sect = 0;
-		gdev->part[minor].nr_sects = 0;
-	}
-
-#ifdef MAYBE_REINIT
-	MAYBE_REINIT;
-#endif
-
-	grok_partitions(gdev, target, 1<<6, CAPACITY);
-
-	DEVICE_BUSY = 0;
-	wake_up(&busy_wait);
-	return 0;
-}
-
-static int parse_hd_setup (char *line) {
-	int ints[6];
-
-	(void) get_options(line, ARRAY_SIZE(ints), ints);
-	hd_setup(NULL, ints);
-
-	return 1;
-}
-__setup("hd=", parse_hd_setup);
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/hpt34x.c linux-2.4.21/drivers/ide/hpt34x.c
--- linux-2.4.20/drivers/ide/hpt34x.c	2001-05-20 00:43:06.000000000 +0000
+++ linux-2.4.21/drivers/ide/hpt34x.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,437 +0,0 @@
-/*
- * linux/drivers/ide/hpt34x.c		Version 0.31	June. 9, 2000
- *
- * Copyright (C) 1998-2000	Andre Hedrick <andre@linux-ide.org>
- * May be copied or modified under the terms of the GNU General Public License
- *
- *
- * 00:12.0 Unknown mass storage controller:
- * Triones Technologies, Inc.
- * Unknown device 0003 (rev 01)
- *
- * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010)
- * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030)
- * hde: DMA 2  (0x0000 0x0002) (0x0000 0x0010)
- * hdf: DMA 2  (0x0002 0x0012) (0x0010 0x0030)
- * hdg: DMA 1  (0x0012 0x0052) (0x0030 0x0070)
- * hdh: DMA 1  (0x0052 0x0252) (0x0070 0x00f0)
- *
- * ide-pci.c reference
- *
- * Since there are two cards that report almost identically,
- * the only discernable difference is the values reported in pcicmd.
- * Booting-BIOS card or HPT363 :: pcicmd == 0x07
- * Non-bootable card or HPT343 :: pcicmd == 0x05
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include "ide_modes.h"
-
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-
-#define HPT343_DEBUG_DRIVE_INFO		0
-
-#undef DISPLAY_HPT34X_TIMINGS
-
-#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int hpt34x_get_info(char *, char **, off_t, int);
-extern int (*hpt34x_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-
-static int hpt34x_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-	u8  c0 = 0, c1 = 0;
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p, "\n                                HPT34X Chipset.\n");
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %sabled                         %sabled\n",
-			(c0&0x80) ? "dis" : " en",
-			(c1&0x80) ? "dis" : " en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	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 " );
-
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "DMA\n");
-	p += sprintf(p, "PIO\n");
-
-	return p-buffer;	/* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte hpt34x_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-static void hpt34x_clear_chipset (ide_drive_t *drive)
-{
-	unsigned int reg1	= 0, tmp1 = 0;
-	unsigned int reg2	= 0, tmp2 = 0;
-
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
-	tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
-	tmp2 = (reg2 & ~(0x11 << drive->dn));
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
-}
-
-static int hpt34x_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	int			err;
-	byte			hi_speed, lo_speed;
-	unsigned int reg1	= 0, tmp1 = 0;
-	unsigned int reg2	= 0, tmp2 = 0;
-
-	SPLIT_BYTE(speed, hi_speed, lo_speed);
-
-	if (hi_speed & 7) {
-		hi_speed = (hi_speed & 4) ? 0x01 : 0x10;
-	} else {
-		lo_speed <<= 5;
-		lo_speed >>= 5;
-	}
-
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
-	tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
-	tmp2 = ((hi_speed << drive->dn) | reg2);
-	err = ide_config_drive_speed(drive, speed);
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-#if HPT343_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
-		" (0x%02x 0x%02x) 0x%04x\n",
-		drive->name, ide_xfer_verbose(speed),
-		drive->dn, reg1, tmp1, reg2, tmp2,
-		hi_speed, lo_speed, err);
-#endif /* HPT343_DEBUG_DRIVE_INFO */
-
-	drive->current_speed = speed;
-	return(err);
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-	unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
-	unsigned short xfer_pio = drive->id->eide_pio_modes;
-
-	byte	timing, speed, pio;
-
-	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-	if (xfer_pio> 4)
-		xfer_pio = 0;
-
-	if (drive->id->eide_pio_iordy > 0) {
-		for (xfer_pio = 5;
-			xfer_pio>0 &&
-			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
-			xfer_pio--);
-	} else {
-		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
-			   (drive->id->eide_pio_modes & 2) ? 0x04 :
-			   (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
-	}
-
-	timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
-	switch(timing) {
-		case 4: speed = XFER_PIO_4;break;
-		case 3: speed = XFER_PIO_3;break;
-		case 2: speed = XFER_PIO_2;break;
-		case 1: speed = XFER_PIO_1;break;
-		default:
-			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
-			break;
-		}
-	(void) hpt34x_tune_chipset(drive, speed);
-}
-
-static void hpt34x_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-
-	switch(pio) {
-		case 4:		speed = XFER_PIO_4;break;
-		case 3:		speed = XFER_PIO_3;break;
-		case 2:		speed = XFER_PIO_2;break;
-		case 1:		speed = XFER_PIO_1;break;
-		default:	speed = XFER_PIO_0;break;
-	}
-	hpt34x_clear_chipset(drive);
-	(void) hpt34x_tune_chipset(drive, speed);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * This allows the configuration of ide_pci chipset registers
- * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.  Initally for designed for
- * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc.
- */
-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	struct hd_driveid *id	= drive->id;
-	byte speed		= 0x00;
-
-	if (drive->media != ide_disk)
-		return ((int) ide_dma_off_quietly);
-
-	hpt34x_clear_chipset(drive);
-
-	if ((id->dma_ultra & 0x0010) && ultra) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0008) && ultra) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0004) && ultra) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && ultra) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && ultra) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_mword & 0x0001) {
-		speed = XFER_MW_DMA_0;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-	} else if (id->dma_1word & 0x0002) {
-		speed = XFER_SW_DMA_1;
-	} else if (id->dma_1word & 0x0001) {
-		speed = XFER_SW_DMA_0;
-        } else {
-		return ((int) ide_dma_off_quietly);
-	}
-
-	(void) hpt34x_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 3) ? ide_dma_off :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x0007) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive, 1);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive, 0);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive, 0);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		config_chipset_for_pio(drive);
-	}
-
-#ifndef CONFIG_HPT34X_AUTODMA
-	if (dma_func == ide_dma_on)
-		dma_func = ide_dma_off;
-#endif /* CONFIG_HPT34X_AUTODMA */
-
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * hpt34x_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- *
- * This is specific to the HPT343 UDMA bios-less chipset
- * and HPT345 UDMA bios chipset (stamped HPT363)
- * by HighPoint|Triones Technologies, Inc.
- */
-
-int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned long dma_base = hwif->dma_base;
-	unsigned int count, reading = 0;
-	byte dma_stat;
-
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_read:
-			reading = 1 << 3;
-		case ide_dma_write:
-			if (!(count = ide_build_dmatable(drive, func)))
-				return 1;	/* try PIO instead of DMA */
-			outl(hwif->dmatable_dma, dma_base + 4); /* PRD table */
-			reading |= 0x01;
-			outb(reading, dma_base);		/* specify r/w */
-			outb(inb(dma_base+2)|6, dma_base+2);	/* clear INTR & ERROR flags */
-			drive->waiting_for_dma = 1;
-			if (drive->media != ide_disk)
-				return 0;
-			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);	/* issue cmd to drive */
-			OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-			return 0;
-		case ide_dma_end:	/* returns 1 on error, 0 otherwise */
-			drive->waiting_for_dma = 0;
-			outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-			dma_stat = inb(dma_base+2);		/* get DMA status */
-			outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
-			ide_destroy_dmatable(drive);		/* purge DMA mappings */
-			return (dma_stat & 7) != 4;		/* verify good DMA status */
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * If the BIOS does not set the IO base addaress to XX00, 343 will fail.
- */
-#define	HPT34X_PCI_INIT_REG		0x80
-
-unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name)
-{
-	int i = 0;
-	unsigned long hpt34xIoBase = pci_resource_start(dev, 4);
-	unsigned short cmd;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00);
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-
-	if (cmd & PCI_COMMAND_MEMORY) {
-		if (pci_resource_start(dev, PCI_ROM_RESOURCE)) {
-			pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-			printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->resource[PCI_ROM_RESOURCE].start);
-		}
-		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
-	} else {
-		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
-	}
-
-	pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
-	dev->resource[0].start = (hpt34xIoBase + 0x20);
-	dev->resource[1].start = (hpt34xIoBase + 0x34);
-	dev->resource[2].start = (hpt34xIoBase + 0x28);
-	dev->resource[3].start = (hpt34xIoBase + 0x3c);
-	for(i=0; i<4; i++)
-		dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
-	/*
-	 * Since 20-23 can be assigned and are R/W, we correct them.
-	 */
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->resource[0].start);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->resource[1].start);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->resource[2].start);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->resource[3].start);
-	pci_write_config_word(dev, PCI_COMMAND, cmd);
-
-	__restore_flags(flags);	/* local CPU only */
-
-#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!hpt34x_proc) {
-		hpt34x_proc = 1;
-		bmide_dev = dev;
-		hpt34x_display_info = &hpt34x_get_info;
-	}
-#endif /* DISPLAY_HPT34X_TIMINGS && CONFIG_PROC_FS */
-
-	return dev->irq;
-}
-
-void __init ide_init_hpt34x (ide_hwif_t *hwif)
-{
-	hwif->tuneproc = &hpt34x_tune_drive;
-	hwif->speedproc = &hpt34x_tune_chipset;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		unsigned short pcicmd = 0;
-
-		pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
-		if (!noautodma)
-			hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
-		else
-			hwif->autodma = 0;
-
-		hwif->dmaproc = &hpt34x_dmaproc;
-	} else {
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-	}
-#else /* !CONFIG_BLK_DEV_IDEDMA */
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/hpt366.c linux-2.4.21/drivers/ide/hpt366.c
--- linux-2.4.20/drivers/ide/hpt366.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/hpt366.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1233 +0,0 @@
-/*
- * linux/drivers/ide/hpt366.c		Version 0.22	20 Sep 2001
- *
- * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
- * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
- * May be copied or modified under the terms of the GNU General Public License
- *
- * Thanks to HighPoint Technologies for their assistance, and hardware.
- * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his
- * donation of an ABit BP6 mainboard, processor, and memory acellerated
- * development and support.
- *
- * Note that final HPT370 support was done by force extraction of GPL.
- *
- * - add function for getting/setting power status of drive
- * - the HPT370's state machine can get confused. reset it before each dma 
- *   xfer to prevent that from happening.
- * - reset state engine whenever we get an error.
- * - check for busmaster state at end of dma. 
- * - use new highpoint timings.
- * - detect bus speed using highpoint register.
- * - use pll if we don't have a clock table. added a 66MHz table that's
- *   just 2x the 33MHz table.
- * - removed turnaround. NOTE: we never want to switch between pll and
- *   pci clocks as the chip can glitch in those cases. the highpoint
- *   approved workaround slows everything down too much to be useful. in
- *   addition, we would have to serialize access to each chip.
- * 	Adrian Sun <a.sun@sun.com>
- *
- * add drive timings for 66MHz PCI bus,
- * fix ATA Cable signal detection, fix incorrect /proc info
- * add /proc display for per-drive PIO/DMA/UDMA mode and
- * per-channel ATA-33/66 Cable detect.
- * 	Duncan Laurie <void@sun.com>
- *
- * fixup /proc output for multiple controllers
- *	Tim Hockin <thockin@sun.com>
- *
- * On hpt366: 
- * Reset the hpt366 on error, reset on dma
- * Fix disabling Fast Interrupt hpt366.
- * 	Mike Waychison <crlf@sun.com>
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_HPT366_TIMINGS
-
-/* various tuning parameters */
-#define HPT_RESET_STATE_ENGINE
-/*#define HPT_DELAY_INTERRUPT*/
-/*#define HPT_SERIALIZE_IO*/
-
-#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-#endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
-
-const char *quirk_drives[] = {
-	"QUANTUM FIREBALLlct08 08",
-	"QUANTUM FIREBALLP KA6.4",
-	"QUANTUM FIREBALLP LM20.4",
-	"QUANTUM FIREBALLP LM20.5",
-        NULL
-};
-
-const char *bad_ata100_5[] = {
-	"IBM-DTLA-307075",
-	"IBM-DTLA-307060",
-	"IBM-DTLA-307045",
-	"IBM-DTLA-307030",
-	"IBM-DTLA-307020",
-	"IBM-DTLA-307015",
-	"IBM-DTLA-305040",
-	"IBM-DTLA-305030",
-	"IBM-DTLA-305020",
-	"IC35L010AVER07-0",
-	"IC35L020AVER07-0",
-	"IC35L030AVER07-0",
-	"IC35L040AVER07-0",
-	"IC35L060AVER07-0",
-	"WDC AC310200R",
-	NULL
-};
-
-const char *bad_ata66_4[] = {
-	"IBM-DTLA-307075",
-	"IBM-DTLA-307060",
-	"IBM-DTLA-307045",
-	"IBM-DTLA-307030",
-	"IBM-DTLA-307020",
-	"IBM-DTLA-307015",
-	"IBM-DTLA-305040",
-	"IBM-DTLA-305030",
-	"IBM-DTLA-305020",
-	"IC35L010AVER07-0",
-	"IC35L020AVER07-0",
-	"IC35L030AVER07-0",
-	"IC35L040AVER07-0",
-	"IC35L060AVER07-0",
-	"WDC AC310200R",
-	NULL
-};
-
-const char *bad_ata66_3[] = {
-	"WDC AC310200R",
-	NULL
-};
-
-const char *bad_ata33[] = {
-	"Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
-	"Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
-	"Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
-	"Maxtor 90510D4",
-	"Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
-	"Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
-	"Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
-	NULL
-};
-
-struct chipset_bus_clock_list_entry {
-	byte		xfer_speed;
-	unsigned int	chipset_settings;
-};
-
-/* key for bus clock timings
- * bit
- * 0:3    data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
- *        DMA. cycles = value + 1
- * 4:8    data_low_time. active time of DIOW_/DIOR_ for PIO and MW
- *        DMA. cycles = value + 1
- * 9:12   cmd_high_time. inactive time of DIOW_/DIOR_ during task file
- *        register access.
- * 13:17  cmd_low_time. active time of DIOW_/DIOR_ during task file
- *        register access.
- * 18:21  udma_cycle_time. clock freq and clock cycles for UDMA xfer.
- *        during task file register access.
- * 22:24  pre_high_time. time to initialize 1st cycle for PIO and MW DMA
- *        xfer.
- * 25:27  cmd_pre_high_time. time to initialize 1st PIO cycle for task
- *        register access.
- * 28     UDMA enable
- * 29     DMA enable
- * 30     PIO_MST enable. if set, the chip is in bus master mode during
- *        PIO.
- * 31     FIFO enable.
- */
-struct chipset_bus_clock_list_entry forty_base [] = {
-
-	{	XFER_UDMA_4,    0x900fd943	},
-	{	XFER_UDMA_3,	0x900ad943	},
-	{	XFER_UDMA_2,	0x900bd943	},
-	{	XFER_UDMA_1,	0x9008d943	},
-	{	XFER_UDMA_0,	0x9008d943	},
-
-	{	XFER_MW_DMA_2,	0xa008d943	},
-	{	XFER_MW_DMA_1,	0xa010d955	},
-	{	XFER_MW_DMA_0,	0xa010d9fc	},
-
-	{	XFER_PIO_4,	0xc008d963	},
-	{	XFER_PIO_3,	0xc010d974	},
-	{	XFER_PIO_2,	0xc010d997	},
-	{	XFER_PIO_1,	0xc010d9c7	},
-	{	XFER_PIO_0,	0xc018d9d9	},
-	{	0,		0x0120d9d9	}
-};
-
-struct chipset_bus_clock_list_entry thirty_three_base [] = {
-
-	{	XFER_UDMA_4,	0x90c9a731	},
-	{	XFER_UDMA_3,	0x90cfa731	},
-	{	XFER_UDMA_2,	0x90caa731	},
-	{	XFER_UDMA_1,	0x90cba731	},
-	{	XFER_UDMA_0,	0x90c8a731	},
-
-	{	XFER_MW_DMA_2,	0xa0c8a731	},
-	{	XFER_MW_DMA_1,	0xa0c8a732	},	/* 0xa0c8a733 */
-	{	XFER_MW_DMA_0,	0xa0c8a797	},
-
-	{	XFER_PIO_4,	0xc0c8a731	},
-	{	XFER_PIO_3,	0xc0c8a742	},
-	{	XFER_PIO_2,	0xc0d0a753	},
-	{	XFER_PIO_1,	0xc0d0a7a3	},	/* 0xc0d0a793 */
-	{	XFER_PIO_0,	0xc0d0a7aa	},	/* 0xc0d0a7a7 */
-	{	0,		0x0120a7a7	}
-};
-
-struct chipset_bus_clock_list_entry twenty_five_base [] = {
-
-	{	XFER_UDMA_4,	0x90c98521	},
-	{	XFER_UDMA_3,	0x90cf8521	},
-	{	XFER_UDMA_2,	0x90cf8521	},
-	{	XFER_UDMA_1,	0x90cb8521	},
-	{	XFER_UDMA_0,	0x90cb8521	},
-
-	{	XFER_MW_DMA_2,	0xa0ca8521	},
-	{	XFER_MW_DMA_1,	0xa0ca8532	},
-	{	XFER_MW_DMA_0,	0xa0ca8575	},
-
-	{	XFER_PIO_4,	0xc0ca8521	},
-	{	XFER_PIO_3,	0xc0ca8532	},
-	{	XFER_PIO_2,	0xc0ca8542	},
-	{	XFER_PIO_1,	0xc0d08572	},
-	{	XFER_PIO_0,	0xc0d08585	},
-	{	0,		0x01208585	}
-};
-
-#if 1
-/* these are the current (4 sep 2001) timings from highpoint */
-struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
-        {       XFER_UDMA_5,    0x12446231      },
-        {       XFER_UDMA_4,    0x12446231      },
-        {       XFER_UDMA_3,    0x126c6231      },
-        {       XFER_UDMA_2,    0x12486231      },
-        {       XFER_UDMA_1,    0x124c6233      },
-        {       XFER_UDMA_0,    0x12506297      },
-
-        {       XFER_MW_DMA_2,  0x22406c31      },
-        {       XFER_MW_DMA_1,  0x22406c33      },
-        {       XFER_MW_DMA_0,  0x22406c97      },
-
-        {       XFER_PIO_4,     0x06414e31      },
-        {       XFER_PIO_3,     0x06414e42      },
-        {       XFER_PIO_2,     0x06414e53      },
-        {       XFER_PIO_1,     0x06814e93      },
-        {       XFER_PIO_0,     0x06814ea7      },
-        {       0,              0x06814ea7      }
-};
-
-/* 2x 33MHz timings */
-struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
-	{       XFER_UDMA_5,    0x1488e673       },
-	{       XFER_UDMA_4,    0x1488e673       },
-	{       XFER_UDMA_3,    0x1498e673       },
-	{       XFER_UDMA_2,    0x1490e673       },
-	{       XFER_UDMA_1,    0x1498e677       },
-	{       XFER_UDMA_0,    0x14a0e73f       },
-
-	{       XFER_MW_DMA_2,  0x2480fa73       },
-	{       XFER_MW_DMA_1,  0x2480fa77       }, 
-	{       XFER_MW_DMA_0,  0x2480fb3f       },
-
-	{       XFER_PIO_4,     0x0c82be73       },
-	{       XFER_PIO_3,     0x0c82be95       },
-	{       XFER_PIO_2,     0x0c82beb7       },
-	{       XFER_PIO_1,     0x0d02bf37       },
-	{       XFER_PIO_0,     0x0d02bf5f       },
-	{       0,              0x0d02bf5f       }
-};
-#else
-/* from highpoint documentation. these are old values */
-struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
-	{	XFER_UDMA_5,	0x16454e31	},
-	{	XFER_UDMA_4,	0x16454e31	},
-	{	XFER_UDMA_3,	0x166d4e31	},
-	{	XFER_UDMA_2,	0x16494e31	},
-	{	XFER_UDMA_1,	0x164d4e31	},
-	{	XFER_UDMA_0,	0x16514e31	},
-
-	{	XFER_MW_DMA_2,	0x26514e21	},
-	{	XFER_MW_DMA_1,	0x26514e33	},
-	{	XFER_MW_DMA_0,	0x26514e97	},
-
-	{	XFER_PIO_4,	0x06514e21	},
-	{	XFER_PIO_3,	0x06514e22	},
-	{	XFER_PIO_2,	0x06514e33	},
-	{	XFER_PIO_1,	0x06914e43	},
-	{	XFER_PIO_0,	0x06914e57	},
-	{	0,		0x06514e57	}
-};
-
-struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
-	{       XFER_UDMA_5,    0x14846231      },
-	{       XFER_UDMA_4,    0x14886231      },
-	{       XFER_UDMA_3,    0x148c6231      },
-	{       XFER_UDMA_2,    0x148c6231      },
-	{       XFER_UDMA_1,    0x14906231      },
-	{       XFER_UDMA_0,    0x14986231      },
-	
-	{       XFER_MW_DMA_2,  0x26514e21      },
-	{       XFER_MW_DMA_1,  0x26514e33      },
-	{       XFER_MW_DMA_0,  0x26514e97      },
-	
-	{       XFER_PIO_4,     0x06514e21      },
-	{       XFER_PIO_3,     0x06514e22      },
-	{       XFER_PIO_2,     0x06514e33      },
-	{       XFER_PIO_1,     0x06914e43      },
-	{       XFER_PIO_0,     0x06914e57      },
-	{       0,              0x06514e57      }
-};
-#endif
-
-struct chipset_bus_clock_list_entry fifty_base_hpt370[] = {
-	{       XFER_UDMA_5,    0x12848242      },
-	{       XFER_UDMA_4,    0x12ac8242      },
-	{       XFER_UDMA_3,    0x128c8242      },
-	{       XFER_UDMA_2,    0x120c8242      },
-	{       XFER_UDMA_1,    0x12148254      },
-	{       XFER_UDMA_0,    0x121882ea      },
-
-	{       XFER_MW_DMA_2,  0x22808242      },
-	{       XFER_MW_DMA_1,  0x22808254      },
-	{       XFER_MW_DMA_0,  0x228082ea      },
-
-	{       XFER_PIO_4,     0x0a81f442      },
-	{       XFER_PIO_3,     0x0a81f443      },
-	{       XFER_PIO_2,     0x0a81f454      },
-	{       XFER_PIO_1,     0x0ac1f465      },
-	{       XFER_PIO_0,     0x0ac1f48a      },
-	{       0,              0x0ac1f48a      }
-};
-
-#define HPT366_DEBUG_DRIVE_INFO		0
-#define HPT370_ALLOW_ATA100_5		1
-#define HPT366_ALLOW_ATA66_4		1
-#define HPT366_ALLOW_ATA66_3		1
-#define HPT366_MAX_DEVS			8
-
-#define F_LOW_PCI_33      0x23
-#define F_LOW_PCI_40      0x29
-#define F_LOW_PCI_50      0x2d
-#define F_LOW_PCI_66      0x42
-
-static struct pci_dev *hpt_devs[HPT366_MAX_DEVS];
-static int n_hpt_devs;
-
-static unsigned int pci_rev_check_hpt3xx(struct pci_dev *dev);
-static unsigned int pci_rev2_check_hpt3xx(struct pci_dev *dev);
-byte hpt366_proc = 0;
-byte hpt363_shared_irq;
-byte hpt363_shared_pin;
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
-static int hpt366_get_info(char *, char **, off_t, int);
-extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-
-static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p	= buffer;
-	char *chipset_nums[] = {"366", "366", "368", "370", "370A"};
-	int i;
-
-	p += sprintf(p, "\n                             "
-		"HighPoint HPT366/368/370\n");
-	for (i = 0; i < n_hpt_devs; i++) {
-		struct pci_dev *dev = hpt_devs[i];
-		unsigned long iobase = dev->resource[4].start;
-		u32 class_rev;
-		u8 c0, c1;
-
-		pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-		class_rev &= 0xff;
-
-		p += sprintf(p, "\nController: %d\n", i);
-		p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]);
-		p += sprintf(p, "--------------- Primary Channel "
-				"--------------- Secondary Channel "
-				"--------------\n");
-
-		/* get the bus master status registers */
-		c0 = inb_p(iobase + 0x2);
-		c1 = inb_p(iobase + 0xa);
-		p += sprintf(p, "Enabled:        %s"
-				"                             %s\n",
-			(c0 & 0x80) ? "no" : "yes",
-			(c1 & 0x80) ? "no" : "yes");
-
-		if (pci_rev_check_hpt3xx(dev)) {
-			u8 cbl;
-			cbl = inb_p(iobase + 0x7b);
-			outb_p(cbl | 1, iobase + 0x7b);
-			outb_p(cbl & ~1, iobase + 0x7b);
-			cbl = inb_p(iobase + 0x7a);
-			p += sprintf(p, "Cable:          ATA-%d"
-					"                          ATA-%d\n",
-				(cbl & 0x02) ? 33 : 66,
-				(cbl & 0x01) ? 33 : 66);
-			p += sprintf(p, "\n");
-		}
-
-		p += sprintf(p, "--------------- drive0 --------- drive1 "
-				"------- drive0 ---------- drive1 -------\n");
-		p += sprintf(p, "DMA capable:    %s              %s" 
-				"            %s               %s\n",
-			(c0 & 0x20) ? "yes" : "no ", 
-			(c0 & 0x40) ? "yes" : "no ",
-			(c1 & 0x20) ? "yes" : "no ", 
-			(c1 & 0x40) ? "yes" : "no ");
-
-		{
-			u8 c2, c3;
-			/* older revs don't have these registers mapped 
-			 * into io space */
-			pci_read_config_byte(dev, 0x43, &c0);
-			pci_read_config_byte(dev, 0x47, &c1);
-			pci_read_config_byte(dev, 0x4b, &c2);
-			pci_read_config_byte(dev, 0x4f, &c3);
-
-			p += sprintf(p, "Mode:           %s             %s"
-					"           %s              %s\n",
-				(c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " : 
-					(c0 & 0x80) ? "PIO " : "off ",
-				(c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
-					(c1 & 0x80) ? "PIO " : "off ",
-				(c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " :
-					(c2 & 0x80) ? "PIO " : "off ",
-				(c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " :
-					(c3 & 0x80) ? "PIO " : "off ");
-		}
-	}
-	p += sprintf(p, "\n");
-	
-	return p-buffer;/* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-static unsigned int pci_rev_check_hpt3xx (struct pci_dev *dev)
-{
-	unsigned int class_rev;
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-	return ((int) (class_rev > 0x02) ? 1 : 0);
-}
-
-static unsigned int pci_rev2_check_hpt3xx (struct pci_dev *dev)
-{
-	unsigned int class_rev;
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-	return ((int) (class_rev > 0x01) ? 1 : 0);
-}
-
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (quirk_drives == list) {
-		while (*list) {
-			if (strstr(id->model, *list++)) {
-				return 1;
-			}
-		}
-	} else {
-		while (*list) {
-			if (!strcmp(*list++,id->model)) {
-				return 1;
-			}
-		}
-	}
-	return 0;
-}
-
-static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
-{
-	for ( ; chipset_table->xfer_speed ; chipset_table++)
-		if (chipset_table->xfer_speed == speed) {
-			return chipset_table->chipset_settings;
-		}
-	return chipset_table->chipset_settings;
-}
-
-static void hpt366_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	byte regtime		= (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
-	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
-			/*
-			 * since the channel is always 0 it does not matter.
-			 */
-
-	unsigned int reg1	= 0;
-	unsigned int reg2	= 0;
-	byte drive_fast		= 0;
-
-	/*
-	 * Disable the "fast interrupt" prediction. 
-	 */
-	pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
-	if (drive_fast & 0x02)
-		pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x20);
-
-	pci_read_config_dword(HWIF(drive)->pci_dev, regtime, &reg1);
-	/* detect bus speed by looking at control reg timing: */
-	switch((reg1 >> 8) & 7) {
-		case 5:
-			reg2 = pci_bus_clock_list(speed, forty_base);
-			break;
-		case 9:
-			reg2 = pci_bus_clock_list(speed, twenty_five_base);
-			break;
-		default:
-		case 7:
-			reg2 = pci_bus_clock_list(speed, thirty_three_base);
-			break;
-	}
-#if 0
-	/* this is a nice idea ... */
-	list_conf = pci_bus_clock_list(speed,
-				       (struct chipset_bus_clock_list_entry *)
-				       dev->sysdata);
-#endif
-	/*
-	 * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
-	 */
-	if (speed >= XFER_MW_DMA_0) {
-		reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
-	} else {
-		reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000);
-	}	
-	reg2 &= ~0x80000000;
-
-	pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
-}
-
-static void hpt370_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
-	unsigned int list_conf	= 0;
-	unsigned int drive_conf = 0;
-	unsigned int conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
-	byte drive_pci		= 0x40 + (drive->dn * 4);
-	byte new_fast, drive_fast		= 0;
-	struct pci_dev *dev 	= HWIF(drive)->pci_dev;
-
-	/*
-	 * Disable the "fast interrupt" prediction.
-	 * don't holdoff on interrupts. (== 0x01 despite what the docs say) 
-	 */
-	pci_read_config_byte(dev, regfast, &drive_fast);
-	new_fast = drive_fast;
-	if (new_fast & 0x02)
-		new_fast &= ~0x02;
-
-#ifdef HPT_DELAY_INTERRUPT
-	if (new_fast & 0x01)
-		new_fast &= ~0x01;
-#else
-	if ((new_fast & 0x01) == 0)
-		new_fast |= 0x01;
-#endif
-	if (new_fast != drive_fast)
-		pci_write_config_byte(HWIF(drive)->pci_dev, regfast, new_fast);
-
-	list_conf = pci_bus_clock_list(speed, 
-				       (struct chipset_bus_clock_list_entry *)
-				       dev->sysdata);
-
-	pci_read_config_dword(dev, drive_pci, &drive_conf);
-	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
-	
-	if (speed < XFER_MW_DMA_0) {
-		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
-	}
-
-	pci_write_config_dword(dev, drive_pci, list_conf);
-}
-
-static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
-		return -1;
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
-		hpt370_tune_chipset(drive, speed);
-        } else {
-                hpt366_tune_chipset(drive, speed);
-        }
-	drive->current_speed = speed;
-	return ((int) ide_config_drive_speed(drive, speed));
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-	unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
-	unsigned short xfer_pio = drive->id->eide_pio_modes;
-	byte	timing, speed, pio;
-
-	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-	if (xfer_pio> 4)
-		xfer_pio = 0;
-
-	if (drive->id->eide_pio_iordy > 0) {
-		for (xfer_pio = 5;
-			xfer_pio>0 &&
-			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
-			xfer_pio--);
-	} else {
-		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
-			   (drive->id->eide_pio_modes & 2) ? 0x04 :
-			   (drive->id->eide_pio_modes & 1) ? 0x03 :
-			   (drive->id->tPIO & 2) ? 0x02 :
-			   (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
-	}
-
-	timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
-	switch(timing) {
-		case 4: speed = XFER_PIO_4;break;
-		case 3: speed = XFER_PIO_3;break;
-		case 2: speed = XFER_PIO_2;break;
-		case 1: speed = XFER_PIO_1;break;
-		default:
-			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
-			break;
-	}
-	(void) hpt3xx_tune_chipset(drive, speed);
-}
-
-static void hpt3xx_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-	switch(pio) {
-		case 4:		speed = XFER_PIO_4;break;
-		case 3:		speed = XFER_PIO_3;break;
-		case 2:		speed = XFER_PIO_2;break;
-		case 1:		speed = XFER_PIO_1;break;
-		default:	speed = XFER_PIO_0;break;
-	}
-	(void) hpt3xx_tune_chipset(drive, speed);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * This allows the configuration of ide_pci chipset registers
- * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.  Initally for designed for
- * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
- *
- * check_in_drive_lists(drive, bad_ata66_4)
- * check_in_drive_lists(drive, bad_ata66_3)
- * check_in_drive_lists(drive, bad_ata33)
- *
- */
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	byte speed		= 0x00;
-	byte ultra66		= eighty_ninty_three(drive);
-	int  rval;
-
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
-		return ((int) ide_dma_off_quietly);
-
-	if ((id->dma_ultra & 0x0020) &&
-	    (!check_in_drive_lists(drive, bad_ata100_5)) &&
-	    (HPT370_ALLOW_ATA100_5) &&
-	    (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) &&
-	    (ultra66)) {
-		speed = XFER_UDMA_5;
-	} else if ((id->dma_ultra & 0x0010) &&
-		   (!check_in_drive_lists(drive, bad_ata66_4)) &&
-		   (HPT366_ALLOW_ATA66_4) &&
-		   (ultra66)) {
-		speed = XFER_UDMA_4;
-	} else if ((id->dma_ultra & 0x0008) &&
-		   (!check_in_drive_lists(drive, bad_ata66_3)) &&
-		   (HPT366_ALLOW_ATA66_3) &&
-		   (ultra66)) {
-		speed = XFER_UDMA_3;
-	} else if (id->dma_ultra && (!check_in_drive_lists(drive, bad_ata33))) {
-		if (id->dma_ultra & 0x0004) {
-			speed = XFER_UDMA_2;
-		} else if (id->dma_ultra & 0x0002) {
-			speed = XFER_UDMA_1;
-		} else if (id->dma_ultra & 0x0001) {
-			speed = XFER_UDMA_0;
-		}
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_mword & 0x0001) {
-		speed = XFER_MW_DMA_0;
-	} else {
-		return ((int) ide_dma_off_quietly);
-	}
-
-	(void) hpt3xx_tune_chipset(drive, speed);
-
-	rval = (int)(	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-	return rval;
-}
-
-int hpt3xx_quirkproc (ide_drive_t *drive)
-{
-	return ((int) check_in_drive_lists(drive, quirk_drives));
-}
-
-void hpt3xx_intrproc (ide_drive_t *drive)
-{
-	if (drive->quirk_list) {
-		/* drives in the quirk_list may not like intr setups/cleanups */
-	} else {
-		OUT_BYTE((drive)->ctl|2, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]);
-	}
-}
-
-void hpt3xx_maskproc (ide_drive_t *drive, int mask)
-{
-	if (drive->quirk_list) {
-		if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
-			byte reg5a = 0;
-			pci_read_config_byte(HWIF(drive)->pci_dev, 0x5a, &reg5a);
-			if (((reg5a & 0x10) >> 4) != mask)
-				pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
-		} else {
-			if (mask) {
-				disable_irq(HWIF(drive)->irq);
-			} else {
-				enable_irq(HWIF(drive)->irq);
-			}
-		}
-	} else {
-		if (IDE_CONTROL_REG)
-			OUT_BYTE(mask ? (drive->ctl | 2) : (drive->ctl & ~2), IDE_CONTROL_REG);
-	}
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x002F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if (id->dma_mword & 0x0007) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-
-		config_chipset_for_pio(drive);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * hpt366_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- *
- * This is specific to the HPT366 UDMA bios chipset
- * by HighPoint|Triones Technologies, Inc.
- */
-int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	byte reg50h = 0, reg52h = 0, reg5ah = 0, dma_stat = 0;
-	unsigned long dma_base = HWIF(drive)->dma_base;
-
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = inb(dma_base+2);
-			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-		case ide_dma_lostirq:
-			pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, &reg50h);
-			pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, &reg52h);
-			pci_read_config_byte(HWIF(drive)->pci_dev, 0x5a, &reg5ah);
-			printk("%s: (%s)  reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
-				drive->name,
-				ide_dmafunc_verbose(func),
-				reg50h, reg52h, reg5ah);
-			if (reg5ah & 0x10)
-				pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, reg5ah & ~0x10);
-			/* fall through to a reset */
-#if 0
-		case ide_dma_begin:
-		case ide_dma_end:
-			/* reset the chips state over and over.. */
-			pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x13);
-#endif
-			break;
-		case ide_dma_timeout:
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-
-int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned long dma_base = hwif->dma_base;
-	byte regstate = hwif->channel ? 0x54 : 0x50;
-	byte reginfo = hwif->channel ? 0x56 : 0x52;
-	byte dma_stat;
-
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = inb(dma_base+2);
-			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-
-		case ide_dma_end:
-			dma_stat = inb(dma_base + 2);
-			if (dma_stat & 0x01) {
-				udelay(20); /* wait a little */
-				dma_stat = inb(dma_base + 2);
-			}
-			if ((dma_stat & 0x01) == 0) 
-				break;
-
-			func = ide_dma_timeout;
-			/* fallthrough */
-
-		case ide_dma_timeout:
-		case ide_dma_lostirq:
-			pci_read_config_byte(hwif->pci_dev, reginfo, 
-					     &dma_stat); 
-			printk("%s: %d bytes in FIFO\n", drive->name, 
-			       dma_stat);
-			pci_write_config_byte(hwif->pci_dev, regstate, 0x37);
-			udelay(10);
-			dma_stat = inb(dma_base);
-			outb(dma_stat & ~0x1, dma_base); /* stop dma */
-			dma_stat = inb(dma_base + 2); 
-			outb(dma_stat | 0x6, dma_base+2); /* clear errors */
-			/* fallthrough */
-
-#ifdef HPT_RESET_STATE_ENGINE
-	        case ide_dma_begin:
-#endif
-			pci_write_config_byte(hwif->pci_dev, regstate, 0x37);
-			udelay(10);
-			break;
-
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * Since SUN Cobalt is attempting to do this operation, I should disclose
- * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
- * HOTSWAP ATA Infrastructure.
- */
-void hpt3xx_reset (ide_drive_t *drive)
-{
-#if 0
-	unsigned long high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
-	byte reset		= (HWIF(drive)->channel) ? 0x80 : 0x40;
-	byte reg59h		= 0;
-
-	pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, &reg59h);
-	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset);
-	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h);
-#endif
-}
-
-static int hpt3xx_tristate (ide_drive_t * drive, int state)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte reset		= (hwif->channel) ? 0x80 : 0x40;
-	byte state_reg		= (hwif->channel) ? 0x57 : 0x53;
-	byte reg59h		= 0;
-	byte regXXh		= 0;
-
-	if (!hwif)
-		return -EINVAL;
-
-//	hwif->bus_state = state;
-
-	pci_read_config_byte(dev, 0x59, &reg59h);
-	pci_read_config_byte(dev, state_reg, &regXXh);
-
-	if (state) {
-		(void) ide_do_reset(drive);
-		pci_write_config_byte(dev, state_reg, regXXh|0x80);
-		pci_write_config_byte(dev, 0x59, reg59h|reset);
-	} else {
-		pci_write_config_byte(dev, 0x59, reg59h & ~(reset));
-		pci_write_config_byte(dev, state_reg, regXXh & ~(0x80));
-		(void) ide_do_reset(drive);
-	}
-	return 0;
-}
-
-/* 
- * set/get power state for a drive.
- * turning the power off does the following things:
- *   1) soft-reset the drive
- *   2) tri-states the ide bus
- *
- * when we turn things back on, we need to re-initialize things.
- */
-#define TRISTATE_BIT  0x8000
-static int hpt370_busproc(ide_drive_t * drive, int state)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	byte tristate, resetmask, bus_reg;
-	u16 tri_reg;
-
-	if (!hwif)
-		return -EINVAL;
-
-	hwif->bus_state = state;
-
-	if (hwif->channel) { 
-		/* secondary channel */
-		tristate = 0x56;
-		resetmask = 0x80; 
-	} else { 
-		/* primary channel */
-		tristate = 0x52;
-		resetmask = 0x40;
-	}
-
-	/* grab status */
-	pci_read_config_word(hwif->pci_dev, tristate, &tri_reg);
-	pci_read_config_byte(hwif->pci_dev, 0x59, &bus_reg);
-
-	/* set the state. we don't set it if we don't need to do so.
-	 * make sure that the drive knows that it has failed if it's off */
-	switch (state) {
-	case BUSSTATE_ON:
-		hwif->drives[0].failures = 0;
-		hwif->drives[1].failures = 0;
-		if ((bus_reg & resetmask) == 0)
-			return 0;
-		tri_reg &= ~TRISTATE_BIT;
-		bus_reg &= ~resetmask;
-		break;
-	case BUSSTATE_OFF:
-		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
-		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
-		if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask))
-			return 0;
-		tri_reg &= ~TRISTATE_BIT;
-		bus_reg |= resetmask;
-		break;
-	case BUSSTATE_TRISTATE:
-		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
-		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
-		if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask))
-			return 0;
-		tri_reg |= TRISTATE_BIT;
-		bus_reg |= resetmask;
-		break;
-	}
-	pci_write_config_byte(hwif->pci_dev, 0x59, bus_reg);
-	pci_write_config_word(hwif->pci_dev, tristate, tri_reg);
-
-	return 0;
-}
-
-static void __init init_hpt370(struct pci_dev *dev)
-{
-	int adjust, i;
-	u16 freq;
-	u32 pll;
-	byte reg5bh;
-
-	/*
-	 * default to pci clock. make sure MA15/16 are set to output
-	 * to prevent drives having problems with 40-pin cables.
-	 */
-	pci_write_config_byte(dev, 0x5b, 0x23);
-
-	/*
-	 * set up the PLL. we need to adjust it so that it's stable. 
-	 * freq = Tpll * 192 / Tpci
-	 */
-	pci_read_config_word(dev, 0x78, &freq);
-	freq &= 0x1FF;
-	if (freq < 0x9c) {
-		pll = F_LOW_PCI_33;
-		dev->sysdata = (void *) thirty_three_base_hpt370;
-		printk("HPT370: using 33MHz PCI clock\n");
-	} else if (freq < 0xb0) {
-		pll = F_LOW_PCI_40;
-	} else if (freq < 0xc8) {
-		pll = F_LOW_PCI_50;
-		dev->sysdata = (void *) fifty_base_hpt370;
-		printk("HPT370: using 50MHz PCI clock\n");
-	} else {
-		pll = F_LOW_PCI_66;
-		dev->sysdata = (void *) sixty_six_base_hpt370;
-		printk("HPT370: using 66MHz PCI clock\n");
-	}
-	
-	/*
-	 * only try the pll if we don't have a table for the clock
-	 * speed that we're running at. NOTE: the internal PLL will
-	 * result in slow reads when using a 33MHz PCI clock. we also
-	 * don't like to use the PLL because it will cause glitches
-	 * on PRST/SRST when the HPT state engine gets reset.
-	 */
-	if (dev->sysdata) 
-		goto init_hpt370_done;
-	
-	/*
-	 * adjust PLL based upon PCI clock, enable it, and wait for
-	 * stabilization.
-	 */
-	adjust = 0;
-	freq = (pll < F_LOW_PCI_50) ? 2 : 4;
-	while (adjust++ < 6) {
-		pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
-				       pll | 0x100);
-
-		/* wait for clock stabilization */
-		for (i = 0; i < 0x50000; i++) {
-			pci_read_config_byte(dev, 0x5b, &reg5bh);
-			if (reg5bh & 0x80) {
-				/* spin looking for the clock to destabilize */
-				for (i = 0; i < 0x1000; ++i) {
-					pci_read_config_byte(dev, 0x5b, 
-							     &reg5bh);
-					if ((reg5bh & 0x80) == 0)
-						goto pll_recal;
-				}
-				pci_read_config_dword(dev, 0x5c, &pll);
-				pci_write_config_dword(dev, 0x5c, 
-						       pll & ~0x100);
-				pci_write_config_byte(dev, 0x5b, 0x21);
-				dev->sysdata = (void *) fifty_base_hpt370;
-				printk("HPT370: using 50MHz internal PLL\n");
-				goto init_hpt370_done;
-			}
-		}
-pll_recal:
-		if (adjust & 1)
-			pll -= (adjust >> 1);
-		else
-			pll += (adjust >> 1);
-	} 
-
-init_hpt370_done:
-	/* reset state engine */
-	pci_write_config_byte(dev, 0x50, 0x37); 
-	pci_write_config_byte(dev, 0x54, 0x37); 
-	udelay(100);
-}
-
-unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
-{
-	byte test = 0;
-
-	if (dev->resource[PCI_ROM_RESOURCE].start)
-		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-
-	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
-	if (test != (L1_CACHE_BYTES / 4))
-		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
-
-	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
-	if (test != 0x78)
-		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
-
-	pci_read_config_byte(dev, PCI_MIN_GNT, &test);
-	if (test != 0x08)
-		pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
-
-	pci_read_config_byte(dev, PCI_MAX_LAT, &test);
-	if (test != 0x08)
-		pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
-
-	if (pci_rev_check_hpt3xx(dev)) {
-		init_hpt370(dev);
-		hpt_devs[n_hpt_devs++] = dev;
-	} else {
-		hpt_devs[n_hpt_devs++] = dev;
-	}
-	
-#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!hpt366_proc) {
-		hpt366_proc = 1;
-		hpt366_display_info = &hpt366_get_info;
-	}
-#endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */
-
-	return dev->irq;
-}
-
-unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
-{
-	byte ata66	= 0;
-	byte regmask	= (hwif->channel) ? 0x01 : 0x02;
-
-	pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
-#ifdef DEBUG
-	printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
-		ata66, (ata66 & regmask) ? "33" : "66",
-		PCI_FUNC(hwif->pci_dev->devfn));
-#endif /* DEBUG */
-	return ((ata66 & regmask) ? 0 : 1);
-}
-
-void __init ide_init_hpt366 (ide_hwif_t *hwif)
-{
-	int hpt_rev;
-
-	hwif->tuneproc	= &hpt3xx_tune_drive;
-	hwif->speedproc	= &hpt3xx_tune_chipset;
-	hwif->quirkproc	= &hpt3xx_quirkproc;
-	hwif->intrproc	= &hpt3xx_intrproc;
-	hwif->maskproc	= &hpt3xx_maskproc;
-
-#ifdef HPT_SERIALIZE_IO
-	/* serialize access to this device */
-	if (hwif->mate)
-		hwif->serialized = hwif->mate->serialized = 1;
-#endif
-
-	hpt_rev = pci_rev_check_hpt3xx(hwif->pci_dev);
-	if (hpt_rev) {
-		/* set up ioctl for power status. note: power affects both
-		 * drives on each channel */
-		hwif->busproc   = &hpt370_busproc;
-	}
-
-	if (pci_rev2_check_hpt3xx(hwif->pci_dev)) {
-		/* do nothing now but will split device types */
-		hwif->resetproc = &hpt3xx_reset;
-/*
- * don't do until we can parse out the cobalt box argh ...
- *		hwif->busproc   = &hpt3xx_tristate;
- */
-	}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		if (hpt_rev) {
-			byte reg5ah = 0;
-			pci_read_config_byte(hwif->pci_dev, 0x5a, &reg5ah);
-			if (reg5ah & 0x10)	/* interrupt force enable */
-				pci_write_config_byte(hwif->pci_dev, 0x5a, reg5ah & ~0x10);
-			hwif->dmaproc = &hpt370_dmaproc;
-		} else {
-			hwif->dmaproc = &hpt366_dmaproc;
-		}
-		if (!noautodma)
-			hwif->autodma = 1;
-		else
-			hwif->autodma = 0;
-	} else {
-		hwif->autodma = 0;
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-	}
-#else /* !CONFIG_BLK_DEV_IDEDMA */
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-void __init ide_dmacapable_hpt366 (ide_hwif_t *hwif, unsigned long dmabase)
-{
-	byte masterdma = 0, slavedma = 0;
-	byte dma_new = 0, dma_old = inb(dmabase+2);
-	byte primary	= hwif->channel ? 0x4b : 0x43;
-	byte secondary	= hwif->channel ? 0x4f : 0x47;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	dma_new = dma_old;
-	pci_read_config_byte(hwif->pci_dev, primary, &masterdma);
-	pci_read_config_byte(hwif->pci_dev, secondary, &slavedma);
-
-	if (masterdma & 0x30)	dma_new |= 0x20;
-	if (slavedma & 0x30)	dma_new |= 0x40;
-	if (dma_new != dma_old) outb(dma_new, dmabase+2);
-
-	__restore_flags(flags);	/* local CPU only */
-
-	ide_setup_dma(hwif, dmabase, 8);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/hptraid.c linux-2.4.21/drivers/ide/hptraid.c
--- linux-2.4.20/drivers/ide/hptraid.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/hptraid.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,436 +0,0 @@
-/*
-   hptraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
-
-   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, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-   
-   Authors: 	Arjan van de Ven <arjanv@redhat.com>
-
-   Based on work
-   	Copyleft  (C) 2001 by Wilfried Weissmann <wweissmann@gmx.at>
-	Copyright (C) 1994-96 Marc ZYNGIER <zyngier@ufr-info-p7.ibp.fr>
-   Based on work done by Søren Schmidt for FreeBSD
-
-   
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/kernel.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/ioctl.h>
-
-#include <linux/ide.h>
-#include <asm/uaccess.h>
-
-#include "ataraid.h"
-
-static int hptraid_open(struct inode * inode, struct file * filp);
-static int hptraid_release(struct inode * inode, struct file * filp);
-static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int hptraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
-
-
-
-struct hptdisk {
-	kdev_t	device;
-	unsigned long sectors;
-	struct block_device *bdev;
-};
-
-struct hptraid {
-	unsigned int stride;
-	unsigned int disks;
-	unsigned long sectors;
-	struct geom geom;
-	
-	struct hptdisk disk[8];
-	
-	unsigned long cutoff[8];
-	unsigned int cutoff_disks[8];	
-};
-
-static struct raid_device_operations hptraid_ops = {
-	open:                   hptraid_open,
-	release:                hptraid_release,
-	ioctl:			hptraid_ioctl,
-	make_request:		hptraid_make_request
-};
-
-static struct hptraid raid[16];
-
-static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	unsigned int minor;
-	unsigned char val;
-	unsigned long sectors;
-	
-	if (!inode || !inode->i_rdev) 	
-		return -EINVAL;
-
-	minor = MINOR(inode->i_rdev)>>SHIFT;
-	
-	switch (cmd) {
-         	case BLKGETSIZE:   /* Return device size */
-			if (!arg)  return -EINVAL;
-			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
-			if (MINOR(inode->i_rdev)&15)
-				return put_user(sectors, (unsigned long *) arg);
-			return put_user(raid[minor].sectors , (unsigned long *) arg);
-			break;
-			
-
-		case HDIO_GETGEO:
-		{
-			struct hd_geometry *loc = (struct hd_geometry *) arg;
-			unsigned short bios_cyl;
-			
-			if (!loc) return -EINVAL;
-			val = 255;
-			if (put_user(val, (byte *) &loc->heads)) return -EFAULT;
-			val=63;
-			if (put_user(val, (byte *) &loc->sectors)) return -EFAULT;
-			bios_cyl = raid[minor].sectors/63/255;
-			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
-				(unsigned long *) &loc->start)) return -EFAULT;
-			return 0;
-		}
-
-		case HDIO_GETGEO_BIG:
-		{
-			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
-			unsigned int bios_cyl;
-			if (!loc) return -EINVAL;
-			val = 255;
-			if (put_user(val, (byte *) &loc->heads)) return -EFAULT;
-			val = 63;
-			if (put_user(val, (byte *) &loc->sectors)) return -EFAULT;
-			bios_cyl = raid[minor].sectors/63/255;
-			if (put_user(bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
-				(unsigned long *) &loc->start)) return -EFAULT;
-			return 0;
-		}
-			
-		default:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
-	};
-
-	return 0;
-}
-
-
-static int hptraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	unsigned long rsect;
-	unsigned long rsect_left,rsect_accum = 0;
-	unsigned long block;
-	unsigned int disk=0,real_disk=0;
-	int i;
-	int device;
-	struct hptraid *thisraid;
-
-	rsect = bh->b_rsector;
-
-	/* Ok. We need to modify this sector number to a new disk + new sector number. 
-	 * If there are disks of different sizes, this gets tricky. 
-	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
-	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
-	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
-	 * and the last 1Gb is disk 3 only.
-	 *
-	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
-	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
-	 * point, we have to divide by one less.
-	 */
-	
-	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
-	thisraid = &raid[device];
-	if (thisraid->stride==0)
-		thisraid->stride=1;
-
-	/* Partitions need adding of the start sector of the partition to the requested sector */
-	
-	rsect += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
-
-	/* Woops we need to split the request to avoid crossing a stride barrier */
-	if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
-		return -1;
-	}
-			
-	rsect_left = rsect;
-	
-	for (i=0;i<8;i++) {
-		if (thisraid->cutoff_disks[i]==0)
-			break;
-		if (rsect > thisraid->cutoff[i]) {
-			/* we're in the wrong area so far */
-			rsect_left -= thisraid->cutoff[i];
-			rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
-		} else {
-			block = rsect_left / thisraid->stride;
-			disk = block % thisraid->cutoff_disks[i];
-			block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
-			rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
-			break;
-		}
-	}
-	
-	for (i=0;i<8;i++) {
-		if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
-			real_disk = i;
-			break;
-		}
-		if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
-			disk--;
-		}
-		
-	}
-	disk = real_disk;
-	
-	/* All but the first disk have a 10 sector offset */
-	if (i>0)
-		rsect+=10;
-		
-	
-	/*
-	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
-	 * is the only IO operation happening on this bh.
-	 */
-	 
-	bh->b_rdev = thisraid->disk[disk].device;
-	bh->b_rsector = rsect;
-
-	/*
-	 * Let the main block layer submit the IO and resolve recursion:
-	 */
-	return 1;
-}
-
-
-#include "hptraid.h"
-
-static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
-{
-	int ret = -EINVAL;
-	struct buffer_head *bh = NULL;
-	kdev_t dev = MKDEV(major,minor);
-	
-	if (blksize_size[major]==NULL)	 /* device doesn't exist */
-		return -EINVAL;
-	
-
-	/* Superblock is at 4096+412 bytes */
-	set_blocksize (dev, 4096);
-	bh = bread (dev, 1, 4096);
-
-	
-	if (bh) {
-		memcpy (buffer, bh->b_data, bufsize);
-	} else {
-		printk(KERN_ERR "hptraid: Error reading superblock.\n");
-		goto abort;
-	}
-	ret = 0;
-abort:
-	if (bh)
-		brelse (bh);
-	return ret;
-}
-
-static unsigned long maxsectors (int major,int minor)
-{
-	unsigned long lba = 0;
-	kdev_t dev;
-	ide_drive_t *ideinfo;
-	
-	dev = MKDEV(major,minor);
-	ideinfo = get_info_ptr (dev);
-	if (ideinfo==NULL)
-		return 0;
-	
-	
-	/* first sector of the last cluster */
-	if (ideinfo->head==0) 
-		return 0;
-	if (ideinfo->sect==0)
-		return 0;
-	lba = (ideinfo->capacity);
-
-	return lba;
-}
-
-static void __init probedisk(int major, int minor,int device)
-{
-	int i;
-        struct highpoint_raid_conf *prom;
-	static unsigned char block[4096];
-	struct block_device *bdev;
-	
-	if (maxsectors(major,minor)==0)
-		return;
-	
-        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
-        	return;
-                                                                                                                 
-        prom = (struct highpoint_raid_conf*)&block[512];
-                
-        if (prom->magic!=  0x5a7816f0)
-        	return;
-        if (prom->type) {
-        	printk(KERN_INFO "hptraid: only RAID0 is supported currently\n");
-        	return;
-        }
-
-	i = prom->disk_number;
-	if (i<0)
-		return;
-	if (i>8) 
-		return;
-
-	bdev = bdget(MKDEV(major,minor));
-	if (bdev && blkdev_get(bdev,FMODE_READ|FMODE_WRITE,0,BDEV_RAW) == 0) {
-        	int j=0;
-        	struct gendisk *gd;
-		raid[device].disk[i].bdev = bdev;
-        	/* This is supposed to prevent others from stealing our underlying disks */
-		/* now blank the /proc/partitions table for the wrong partition table,
-		   so that scripts don't accidentally mount it and crash the kernel */
-		 /* XXX: the 0 is an utter hack  --hch */
-		gd=get_gendisk(MKDEV(major, 0));
-		if (gd!=NULL) {
-			for (j=1+(minor<<gd->minor_shift);j<((minor+1)<<gd->minor_shift);j++) 
-				gd->part[j].nr_sects=0;					
-		}
-        }
-	raid[device].disk[i].device = MKDEV(major,minor);
-	raid[device].disk[i].sectors = maxsectors(major,minor);
-	raid[device].stride = (1<<prom->raid0_shift);
-	raid[device].disks = prom->raid_disks;
-	raid[device].sectors = prom->total_secs;
-			
-}
-
-static void __init fill_cutoff(int device)
-{
-	int i,j;
-	unsigned long smallest;
-	unsigned long bar;
-	int count;
-	
-	bar = 0;
-	for (i=0;i<8;i++) {
-		smallest = ~0;
-		for (j=0;j<8;j++) 
-			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
-				smallest = raid[device].disk[j].sectors;
-		count = 0;
-		for (j=0;j<8;j++) 
-			if (raid[device].disk[j].sectors >= smallest)
-				count++;
-		
-		smallest = smallest * count;		
-		bar = smallest;
-		raid[device].cutoff[i] = smallest;
-		raid[device].cutoff_disks[i] = count;
-		
-	}
-}
-
-
-static __init int hptraid_init_one(int device)
-{
-	int i,count;
-
-	probedisk(IDE0_MAJOR,  0, device);
-	probedisk(IDE0_MAJOR, 64, device);
-	probedisk(IDE1_MAJOR,  0, device);
-	probedisk(IDE1_MAJOR, 64, device);
-	probedisk(IDE2_MAJOR,  0, device);
-	probedisk(IDE2_MAJOR, 64, device);
-	probedisk(IDE3_MAJOR,  0, device);
-	probedisk(IDE3_MAJOR, 64, device);
-	probedisk(IDE4_MAJOR,  0, device);
-	probedisk(IDE4_MAJOR, 64, device);
-	probedisk(IDE5_MAJOR,  0, device);
-	probedisk(IDE5_MAJOR, 64, device);
-
-	fill_cutoff(device);
-	
-	/* Initialize the gendisk structure */
-	
-	ataraid_register_disk(device,raid[device].sectors);
-
-	count=0;
-	printk(KERN_INFO "Highpoint HPT370 Softwareraid driver for linux version 0.01\n");
-		
-	for (i=0;i<8;i++) {
-		if (raid[device].disk[i].device!=0) {
-			printk(KERN_INFO "Drive %i is %li Mb \n",
-				i,raid[device].disk[i].sectors/2048);
-			count++;
-		}
-	}
-	if (count) {
-		printk(KERN_INFO "Raid array consists of %i drives. \n",count);
-		return 0;
-	} else {
-		printk(KERN_INFO "No raid array found\n");
-		return -ENODEV;
-	}
-	
-}
-
-static __init int hptraid_init(void)
-{
-	int retval,device;
-	
-	device=ataraid_get_device(&hptraid_ops);
-	if (device<0)
-		return -ENODEV;
-	retval = hptraid_init_one(device);
-	if (retval)
-		ataraid_release_device(device);
-	return retval;
-}
-
-static void __exit hptraid_exit (void)
-{
-	int i,device;
-	for (device = 0; device<16; device++) {
-		for (i=0;i<8;i++)  {
-			struct block_device *bdev = raid[device].disk[i].bdev;
-			raid[device].disk[i].bdev = NULL;
-			if (bdev)
-				blkdev_put(bdev, BDEV_RAW);
-		}       
-		if (raid[device].sectors)
-			ataraid_release_device(device);
-	}
-}
-
-static int hptraid_open(struct inode * inode, struct file * filp) 
-{
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-static int hptraid_release(struct inode * inode, struct file * filp)
-{	
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-module_init(hptraid_init);
-module_exit(hptraid_exit);
-MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/hptraid.h linux-2.4.21/drivers/ide/hptraid.h
--- linux-2.4.20/drivers/ide/hptraid.h	2001-10-11 16:43:29.000000000 +0000
+++ linux-2.4.21/drivers/ide/hptraid.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,77 +0,0 @@
-/*-
- * Copyright (c) 2000,2001 Søren Schmidt <sos@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer,
- *    without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-                            
-struct highpoint_raid_conf
-{
-       int8_t  filler1[32];
-       u_int32_t       magic;
-#define HPT_MAGIC_OK   0x5a7816f0
-#define HPT_MAGIC_BAD  0x5a7816fd  
-
-       u_int32_t       magic_0;
-       u_int32_t       magic_1;
-       u_int32_t       order;  
-#define HPT_O_MIRROR   0x01  
-#define HPT_O_STRIPE   0x02
-#define HPT_O_OK       0x04
-
-       u_int8_t        raid_disks;
-       u_int8_t        raid0_shift; 
-       u_int8_t        type;
-#define HPT_T_RAID_0   0x00 
-#define HPT_T_RAID_1   0x01
-#define HPT_T_RAID_01_RAID_0   0x02
-#define HPT_T_SPAN             0x03
-#define HPT_T_RAID_3           0x04   
-#define HPT_T_RAID_5           0x05
-#define HPT_T_SINGLEDISK       0x06
-#define HPT_T_RAID_01_RAID_1   0x07
-
-       u_int8_t        disk_number;
-       u_int32_t       total_secs; 
-       u_int32_t       disk_mode;  
-       u_int32_t       boot_mode;
-       u_int8_t        boot_disk; 
-       u_int8_t        boot_protect;
-       u_int8_t        error_log_entries;
-       u_int8_t        error_log_index;  
-       struct
-       {
-               u_int32_t       timestamp;
-               u_int8_t        reason;   
-#define HPT_R_REMOVED          0xfe      
-#define HPT_R_BROKEN           0xff      
-
-               u_int8_t        disk;
-               u_int8_t        status;
-               u_int8_t        sectors;
-               u_int32_t       lba;
-       } errorlog[32];
-       u_int8_t        filler[60];
-};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ht6560b.c linux-2.4.21/drivers/ide/ht6560b.c
--- linux-2.4.20/drivers/ide/ht6560b.c	2000-04-14 05:54:26.000000000 +0000
+++ linux-2.4.21/drivers/ide/ht6560b.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,343 +0,0 @@
-/*
- *  linux/drivers/ide/ht6560b.c		Version 0.07	Feb  1, 2000
- *
- *  Copyright (C) 1995-2000  Linus Torvalds & author (see below)
- */
-
-/*
- *
- *  Version 0.01        Initial version hacked out of ide.c
- *
- *  Version 0.02        Added support for PIO modes, auto-tune
- *
- *  Version 0.03        Some cleanups
- *
- *  Version 0.05        PIO mode cycle timings auto-tune using bus-speed
- *
- *  Version 0.06        Prefetch mode now defaults no OFF. To set
- *                      prefetch mode OFF/ON use "hdparm -p8/-p9".
- *                      Unmask irq is disabled when prefetch mode
- *                      is enabled.
- *
- *  Version 0.07        Trying to fix CD-ROM detection problem.
- *                      "Prefetch" mode bit OFF for ide disks and
- *                      ON for anything else.
- *
- *
- *  HT-6560B EIDE-controller support
- *  To activate controller support use kernel parameter "ide0=ht6560b".
- *  Use hdparm utility to enable PIO mode support.
- *
- *  Author:    Mikko Ala-Fossi            <maf@iki.fi>
- *             Jan Evert van Grootheest   <janevert@iae.nl>
- *
- *  Try:  http://www.maf.iki.fi/~maf/ht6560b/
- */
-
-#define HT6560B_VERSION "v0.07"
-
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/* #define DEBUG */  /* remove comments for DEBUG messages */
-
-/*
- * The special i/o-port that HT-6560B uses to configuration:
- *    bit0 (0x01): "1" selects secondary interface
- *    bit2 (0x04): "1" enables FIFO function
- *    bit5 (0x20): "1" enables prefetched data read function  (???)
- *
- * The special i/o-port that HT-6560A uses to configuration:
- *    bit0 (0x01): "1" selects secondary interface
- *    bit1 (0x02): "1" enables prefetched data read function
- *    bit2 (0x04): "0" enables multi-master system	      (?)
- *    bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time	      (?)
- */
-#define HT_CONFIG_PORT	  0x3e6
-#define HT_CONFIG(drivea) (byte)(((drivea)->drive_data & 0xff00) >> 8)
-/*
- * FIFO + PREFETCH (both a/b-model)
- */
-#define HT_CONFIG_DEFAULT 0x1c /* no prefetch */
-/* #define HT_CONFIG_DEFAULT 0x3c */ /* with prefetch */
-#define HT_SECONDARY_IF	  0x01
-#define HT_PREFETCH_MODE  0x20
-
-/*
- * ht6560b Timing values:
- *
- * I reviewed some assembler source listings of htide drivers and found
- * out how they setup those cycle time interfacing values, as they at Holtek
- * call them. IDESETUP.COM that is supplied with the drivers figures out
- * optimal values and fetches those values to drivers. I found out that
- * they use IDE_SELECT_REG to fetch timings to the ide board right after
- * interface switching. After that it was quite easy to add code to
- * ht6560b.c.
- *
- * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine
- * for hda and hdc. But hdb needed higher values to work, so I guess
- * that sometimes it is necessary to give higher value than IDESETUP
- * gives.   [see cmd640.c for an extreme example of this. -ml]
- *
- * Perhaps I should explain something about these timing values:
- * The higher nibble of value is the Recovery Time  (rt) and the lower nibble
- * of the value is the Active Time  (at). Minimum value 2 is the fastest and
- * the maximum value 15 is the slowest. Default values should be 15 for both.
- * So 0x24 means 2 for rt and 4 for at. Each of the drives should have
- * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or
- * similar. If value is too small there will be all sorts of failures.
- *
- * Timing byte consists of
- *	High nibble:  Recovery Cycle Time  (rt)
- *	     The valid values range from 2 to 15. The default is 15.
- *
- *	Low nibble:   Active Cycle Time	   (at)
- *	     The valid values range from 2 to 15. The default is 15.
- *
- * You can obtain optimized timing values by running Holtek IDESETUP.COM
- * for DOS. DOS drivers get their timing values from command line, where
- * the first value is the Recovery Time and the second value is the
- * Active Time for each drive. Smaller value gives higher speed.
- * In case of failures you should probably fall back to a higher value.
- */
-#define HT_TIMING(drivea) (byte)((drivea)->drive_data & 0x00ff)
-#define HT_TIMING_DEFAULT 0xff
-
-/*
- * This routine handles interface switching for the peculiar hardware design
- * on the F.G.I./Holtek HT-6560B VLB IDE interface.
- * The HT-6560B can only enable one IDE port at a time, and requires a
- * silly sequence (below) whenever we switch between primary and secondary.
- */
-
-/*
- * This routine is invoked from ide.c to prepare for access to a given drive.
- */
-static void ht6560b_selectproc (ide_drive_t *drive)
-{
-	unsigned long flags;
-	static byte current_select = 0;
-	static byte current_timing = 0;
-	byte select, timing;
-	
-	__save_flags (flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	
-	select = HT_CONFIG(drive);
-	timing = HT_TIMING(drive);
-	
-	if (select != current_select || timing != current_timing) {
-		current_select = select;
-		current_timing = timing;
-		if (drive->media != ide_disk || !drive->present)
-			select |= HT_PREFETCH_MODE;
-		(void) inb(HT_CONFIG_PORT);
-		(void) inb(HT_CONFIG_PORT);
-		(void) inb(HT_CONFIG_PORT);
-		(void) inb(HT_CONFIG_PORT);
-		outb(select, HT_CONFIG_PORT);
-		/*
-		 * Set timing for this drive:
-		 */
-		outb(timing, IDE_SELECT_REG);
-		(void) inb(IDE_STATUS_REG);
-#ifdef DEBUG
-		printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, select, timing);
-#endif
-	}
-	__restore_flags (flags);	/* local CPU only */
-}
-
-/*
- * Autodetection and initialization of ht6560b
- */
-static int __init try_to_init_ht6560b(void)
-{
-	byte orig_value;
-	int i;
-	
-	/* Autodetect ht6560b */
-	if ((orig_value=inb(HT_CONFIG_PORT)) == 0xff)
-		return 0;
-	
-	for (i=3;i>0;i--) {
-		outb(0x00, HT_CONFIG_PORT);
-		if (!( (~inb(HT_CONFIG_PORT)) & 0x3f )) {
-			outb(orig_value, HT_CONFIG_PORT);
-			return 0;
-		}
-	}
-	outb(0x00, HT_CONFIG_PORT);
-	if ((~inb(HT_CONFIG_PORT))& 0x3f) {
-		outb(orig_value, HT_CONFIG_PORT);
-		return 0;
-	}
-	/*
-	 * Ht6560b autodetected
-	 */
-	outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT);
-	outb(HT_TIMING_DEFAULT, 0x1f6);  /* IDE_SELECT_REG */
-	(void) inb(0x1f7);               /* IDE_STATUS_REG */
-	
-	printk("\nht6560b " HT6560B_VERSION
-	       ": chipset detected and initialized"
-#ifdef DEBUG
-	       " with debug enabled"
-#endif
-		);
-	return 1;
-}
-
-static byte ht_pio2timings(ide_drive_t *drive, byte pio)
-{
-	int active_time, recovery_time;
-	int active_cycles, recovery_cycles;
-	ide_pio_data_t d;
-	int bus_speed = system_bus_clock();
-	
-        if (pio) {
-		pio = ide_get_best_pio_mode(drive, pio, 5, &d);
-		
-		/*
-		 *  Just like opti621.c we try to calculate the
-		 *  actual cycle time for recovery and activity
-		 *  according system bus speed.
-		 */
-		active_time = ide_pio_timings[pio].active_time;
-		recovery_time = d.cycle_time 
-			- active_time
-			- ide_pio_timings[pio].setup_time;
-		/*
-		 *  Cycle times should be Vesa bus cycles
-		 */
-		active_cycles   = (active_time   * bus_speed + 999) / 1000;
-		recovery_cycles = (recovery_time * bus_speed + 999) / 1000;
-		/*
-		 *  Upper and lower limits
-		 */
-		if (active_cycles   < 2)  active_cycles   = 2;
-		if (recovery_cycles < 2)  recovery_cycles = 2;
-		if (active_cycles   > 15) active_cycles   = 15;
-		if (recovery_cycles > 15) recovery_cycles = 0;  /* 0==16 */
-		
-#ifdef DEBUG
-		printk("ht6560b: drive %s setting pio=%d recovery=%d (%dns) active=%d (%dns)\n", drive->name, pio, recovery_cycles, recovery_time, active_cycles, active_time);
-#endif
-		
-		return (byte)((recovery_cycles << 4) | active_cycles);
-	} else {
-		
-#ifdef DEBUG
-		printk("ht6560b: drive %s setting pio=0\n", drive->name);
-#endif
-		
-		return HT_TIMING_DEFAULT;    /* default setting */
-	}
-}
-
-/*
- *  Enable/Disable so called prefetch mode
- */
-static void ht_set_prefetch(ide_drive_t *drive, byte state)
-{
-	unsigned long flags;
-	int t = HT_PREFETCH_MODE << 8;
-	
-	save_flags (flags);	/* all CPUs */
-	cli();		        /* all CPUs */
-	
-	/*
-	 *  Prefetch mode and unmask irq seems to conflict
-	 */
-	if (state) {
-		drive->drive_data |= t;   /* enable prefetch mode */
-		drive->no_unmask = 1;
-		drive->unmask = 0;
-	} else {
-		drive->drive_data &= ~t;  /* disable prefetch mode */
-		drive->no_unmask = 0;
-	}
-	
-	restore_flags (flags);	/* all CPUs */
-	
-#ifdef DEBUG
-	printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis"));
-#endif
-}
-
-static void tune_ht6560b (ide_drive_t *drive, byte pio)
-{
-	unsigned long flags;
-	byte timing;
-	
-	switch (pio) {
-	case 8:         /* set prefetch off */
-	case 9:         /* set prefetch on */
-		ht_set_prefetch(drive, pio & 1);
-		return;
-	}
-	
-	timing = ht_pio2timings(drive, pio);
-	
-	save_flags (flags);	/* all CPUs */
-	cli();		        /* all CPUs */
-	
-	drive->drive_data &= 0xff00;
-	drive->drive_data |= timing;
-	
-	restore_flags (flags);	/* all CPUs */
-	
-#ifdef DEBUG
-	printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing);
-#endif
-}
-
-void __init init_ht6560b (void)
-{
-	int t;
-	
-	if (check_region(HT_CONFIG_PORT,1)) {
-		printk(KERN_ERR "ht6560b: PORT %#x ALREADY IN USE\n", HT_CONFIG_PORT);
-	} else {
-		if (try_to_init_ht6560b()) {
-			request_region(HT_CONFIG_PORT, 1, ide_hwifs[0].name);
-			ide_hwifs[0].chipset = ide_ht6560b;
-			ide_hwifs[1].chipset = ide_ht6560b;
-			ide_hwifs[0].selectproc = &ht6560b_selectproc;
-			ide_hwifs[1].selectproc = &ht6560b_selectproc;
-			ide_hwifs[0].tuneproc = &tune_ht6560b;
-			ide_hwifs[1].tuneproc = &tune_ht6560b;
-			ide_hwifs[0].serialized = 1;  /* is this needed? */
-			ide_hwifs[1].serialized = 1;  /* is this needed? */
-			ide_hwifs[0].mate = &ide_hwifs[1];
-			ide_hwifs[1].mate = &ide_hwifs[0];
-			ide_hwifs[1].channel = 1;
-			
-			/*
-			 * Setting default configurations for drives
-			 */
-			t = (HT_CONFIG_DEFAULT << 8);
-			t |= HT_TIMING_DEFAULT;
-			ide_hwifs[0].drives[0].drive_data = t;
-			ide_hwifs[0].drives[1].drive_data = t;
-			t |= (HT_SECONDARY_IF << 8);
-			ide_hwifs[1].drives[0].drive_data = t;
-			ide_hwifs[1].drives[1].drive_data = t;
-		} else
-			printk(KERN_ERR "ht6560b: not found\n");
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/icside.c linux-2.4.21/drivers/ide/icside.c
--- linux-2.4.20/drivers/ide/icside.c	2001-10-25 20:53:47.000000000 +0000
+++ linux-2.4.21/drivers/ide/icside.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,766 +0,0 @@
-/*
- * linux/drivers/ide/icside.c
- *
- * Copyright (c) 1996,1997 Russell King.
- *
- * Changelog:
- *  08-Jun-1996	RMK	Created
- *  12-Sep-1997	RMK	Added interrupt enable/disable
- *  17-Apr-1999	RMK	Added support for V6 EASI
- *  22-May-1999	RMK	Added support for V6 DMA
- */
-
-#include <linux/config.h>
-#include <linux/string.h>
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/errno.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-
-#include <asm/dma.h>
-#include <asm/ecard.h>
-#include <asm/io.h>
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/*
- * Maximum number of interfaces per card
- */
-#define MAX_IFS	2
-
-#define ICS_IDENT_OFFSET		0x8a0
-
-#define ICS_ARCIN_V5_INTRSTAT		0x000
-#define ICS_ARCIN_V5_INTROFFSET		0x001
-#define ICS_ARCIN_V5_IDEOFFSET		0xa00
-#define ICS_ARCIN_V5_IDEALTOFFSET	0xae0
-#define ICS_ARCIN_V5_IDESTEPPING	4
-
-#define ICS_ARCIN_V6_IDEOFFSET_1	0x800
-#define ICS_ARCIN_V6_INTROFFSET_1	0x880
-#define ICS_ARCIN_V6_INTRSTAT_1		0x8a4
-#define ICS_ARCIN_V6_IDEALTOFFSET_1	0x8e0
-#define ICS_ARCIN_V6_IDEOFFSET_2	0xc00
-#define ICS_ARCIN_V6_INTROFFSET_2	0xc80
-#define ICS_ARCIN_V6_INTRSTAT_2		0xca4
-#define ICS_ARCIN_V6_IDEALTOFFSET_2	0xce0
-#define ICS_ARCIN_V6_IDESTEPPING	4
-
-struct cardinfo {
-	unsigned int dataoffset;
-	unsigned int ctrloffset;
-	unsigned int stepping;
-};
-
-static struct cardinfo icside_cardinfo_v5 = {
-	ICS_ARCIN_V5_IDEOFFSET,
-	ICS_ARCIN_V5_IDEALTOFFSET,
-	ICS_ARCIN_V5_IDESTEPPING
-};
-
-static struct cardinfo icside_cardinfo_v6_1 = {
-	ICS_ARCIN_V6_IDEOFFSET_1,
-	ICS_ARCIN_V6_IDEALTOFFSET_1,
-	ICS_ARCIN_V6_IDESTEPPING
-};
-
-static struct cardinfo icside_cardinfo_v6_2 = {
-	ICS_ARCIN_V6_IDEOFFSET_2,
-	ICS_ARCIN_V6_IDEALTOFFSET_2,
-	ICS_ARCIN_V6_IDESTEPPING
-};
-
-static const card_ids icside_cids[] = {
-	{ MANU_ICS,  PROD_ICS_IDE  },
-	{ MANU_ICS2, PROD_ICS2_IDE },
-	{ 0xffff, 0xffff }
-};
-
-typedef enum {
-	ics_if_unknown,
-	ics_if_arcin_v5,
-	ics_if_arcin_v6
-} iftype_t;
-
-/* ---------------- Version 5 PCB Support Functions --------------------- */
-/* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
- * Purpose  : enable interrupts from card
- */
-static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
-{
-	unsigned int memc_port = (unsigned int)ec->irq_data;
-	outb (0, memc_port + ICS_ARCIN_V5_INTROFFSET);
-}
-
-/* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
- * Purpose  : disable interrupts from card
- */
-static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
-{
-	unsigned int memc_port = (unsigned int)ec->irq_data;
-	inb (memc_port + ICS_ARCIN_V5_INTROFFSET);
-}
-
-static const expansioncard_ops_t icside_ops_arcin_v5 = {
-	icside_irqenable_arcin_v5,
-	icside_irqdisable_arcin_v5,
-	NULL,
-	NULL,
-	NULL,
-	NULL
-};
-
-
-/* ---------------- Version 6 PCB Support Functions --------------------- */
-/* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
- * Purpose  : enable interrupts from card
- */
-static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
-{
-	unsigned int ide_base_port = (unsigned int)ec->irq_data;
-
-	outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
-	outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
-}
-
-/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
- * Purpose  : disable interrupts from card
- */
-static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
-{
-	unsigned int ide_base_port = (unsigned int)ec->irq_data;
-
-	inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
-	inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
-}
-
-/* Prototype: icside_irqprobe(struct expansion_card *ec)
- * Purpose  : detect an active interrupt from card
- */
-static int icside_irqpending_arcin_v6(struct expansion_card *ec)
-{
-	unsigned int ide_base_port = (unsigned int)ec->irq_data;
-
-	return inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
-	       inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
-}
-
-static const expansioncard_ops_t icside_ops_arcin_v6 = {
-	icside_irqenable_arcin_v6,
-	icside_irqdisable_arcin_v6,
-	icside_irqpending_arcin_v6,
-	NULL,
-	NULL,
-	NULL
-};
-
-/* Prototype: icside_identifyif (struct expansion_card *ec)
- * Purpose  : identify IDE interface type
- * Notes    : checks the description string
- */
-static iftype_t __init icside_identifyif (struct expansion_card *ec)
-{
-	unsigned int addr;
-	iftype_t iftype;
-	int id = 0;
-
-	iftype = ics_if_unknown;
-
-	addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET;
-
-	id = inb (addr) & 1;
-	id |= (inb (addr + 1) & 1) << 1;
-	id |= (inb (addr + 2) & 1) << 2;
-	id |= (inb (addr + 3) & 1) << 3;
-
-	switch (id) {
-	case 0: /* A3IN */
-		printk("icside: A3IN unsupported\n");
-		break;
-
-	case 1: /* A3USER */
-		printk("icside: A3USER unsupported\n");
-		break;
-
-	case 3:	/* ARCIN V6 */
-		printk(KERN_DEBUG "icside: detected ARCIN V6 in slot %d\n", ec->slot_no);
-		iftype = ics_if_arcin_v6;
-		break;
-
-	case 15:/* ARCIN V5 (no id) */
-		printk(KERN_DEBUG "icside: detected ARCIN V5 in slot %d\n", ec->slot_no);
-		iftype = ics_if_arcin_v5;
-		break;
-
-	default:/* we don't know - complain very loudly */
-		printk("icside: ***********************************\n");
-		printk("icside: *** UNKNOWN ICS INTERFACE id=%d ***\n", id);
-		printk("icside: ***********************************\n");
-		printk("icside: please report this to linux@arm.linux.org.uk\n");
-		printk("icside: defaulting to ARCIN V5\n");
-		iftype = ics_if_arcin_v5;
-		break;
-	}
-
-	return iftype;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
-/*
- * SG-DMA support.
- *
- * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers.
- * There is only one DMA controller per card, which means that only
- * one drive can be accessed at one time.  NOTE! We do not enforce that
- * here, but we rely on the main IDE driver spotting that both
- * interfaces use the same IRQ, which should guarantee this.
- */
-#define NR_ENTRIES 256
-#define TABLE_SIZE (NR_ENTRIES * 8)
-
-static int ide_build_sglist(ide_hwif_t *hwif, struct request *rq)
-{
-	struct buffer_head *bh;
-	struct scatterlist *sg = hwif->sg_table;
-	int nents = 0;
-
-	if (rq->cmd == READ)
-		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-	else
-		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
-	bh = rq->bh;
-	do {
-		unsigned char *virt_addr = bh->b_data;
-		unsigned int size = bh->b_size;
-
-		while ((bh = bh->b_reqnext) != NULL) {
-			if ((virt_addr + size) != (unsigned char *)bh->b_data)
-				break;
-			size += bh->b_size;
-		}
-		memset(&sg[nents], 0, sizeof(*sg));
-		sg[nents].address = virt_addr;
-		sg[nents].length = size;
-		nents++;
-	} while (bh != NULL);
-
-	return pci_map_sg(NULL, sg, nents, hwif->sg_dma_direction);
-}
-
-static int
-icside_build_dmatable(ide_drive_t *drive, int reading)
-{
-	return HWIF(drive)->sg_nents = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
-}
-
-/* Teardown mappings after DMA has completed.  */
-static void icside_destroy_dmatable(ide_drive_t *drive)
-{
-	struct scatterlist *sg = HWIF(drive)->sg_table;
-	int nents = HWIF(drive)->sg_nents;
-
-	pci_unmap_sg(NULL, sg, nents, HWIF(drive)->sg_dma_direction);
-}
-
-static int
-icside_config_if(ide_drive_t *drive, int xfer_mode)
-{
-	int func = ide_dma_off;
-
-	switch (xfer_mode) {
-	case XFER_MW_DMA_2:
-		/*
-		 * The cycle time is limited to 250ns by the r/w
-		 * pulse width (90ns), however we should still
-		 * have a maximum burst transfer rate of 8MB/s.
-		 */
-		drive->drive_data = 250;
-		break;
-
-	case XFER_MW_DMA_1:
-		drive->drive_data = 250;
-		break;
-
-	case XFER_MW_DMA_0:
-		drive->drive_data = 480;
-		break;
-
-	default:
-		drive->drive_data = 0;
-		break;
-	}
-
-	if (!drive->init_speed)
-		drive->init_speed = (byte) xfer_mode;
-
-	if (drive->drive_data &&
-	    ide_config_drive_speed(drive, (byte) xfer_mode) == 0)
-		func = ide_dma_on;
-	else
-		drive->drive_data = 480;
-
-	printk("%s: %s selected (peak %dMB/s)\n", drive->name,
-		ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
-
-	drive->current_speed = (byte) xfer_mode;
-
-	return func;
-}
-
-static int
-icside_set_speed(ide_drive_t *drive, byte speed)
-{
-	return icside_config_if(drive, speed);
-}
-
-/*
- * dma_intr() is the handler for disk read/write DMA interrupts
- */
-static ide_startstop_t icside_dmaintr(ide_drive_t *drive)
-{
-	int i;
-	byte stat, dma_stat;
-
-	dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
-	stat = GET_STAT();			/* get drive status */
-	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
-		if (!dma_stat) {
-			struct request *rq = HWGROUP(drive)->rq;
-			rq = HWGROUP(drive)->rq;
-			for (i = rq->nr_sectors; i > 0;) {
-				i -= rq->current_nr_sectors;
-				ide_end_request(1, HWGROUP(drive));
-			}
-			return ide_stopped;
-		}
-		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
-		       drive->name, dma_stat);
-	}
-	return ide_error(drive, "dma_intr", stat);
-}
-
-/*
- * The following is a sick duplication from ide-dma.c ;(
- *
- * This should be defined in one place only.
- */
-struct drive_list_entry {
-	char * id_model;
-	char * id_firmware;
-};
-
-static struct drive_list_entry drive_whitelist [] = {
-	{ "Micropolis 2112A",			"ALL"		},
-	{ "CONNER CTMA 4000",			"ALL"		},
-	{ "CONNER CTT8000-A",			"ALL"		},
-	{ "ST34342A",				"ALL"		},
-	{ NULL,					0		}
-};
-
-static struct drive_list_entry drive_blacklist [] = {
-	{ "WDC AC11000H",			"ALL"		},
-	{ "WDC AC22100H",			"ALL"		},
-	{ "WDC AC32500H",			"ALL"		},
-	{ "WDC AC33100H",			"ALL"		},
-	{ "WDC AC31600H",			"ALL"		},
-	{ "WDC AC32100H",			"24.09P07"	},
-	{ "WDC AC23200L",			"21.10N21"	},
-	{ "Compaq CRD-8241B",			"ALL"		},
-	{ "CRD-8400B",				"ALL"		},
-	{ "CRD-8480B",				"ALL"		},
-	{ "CRD-8480C",				"ALL"		},
-	{ "CRD-8482B",				"ALL"		},
- 	{ "CRD-84",				"ALL"		},
-	{ "SanDisk SDP3B",			"ALL"		},
-	{ "SanDisk SDP3B-64",			"ALL"		},
-	{ "SANYO CD-ROM CRD",			"ALL"		},
-	{ "HITACHI CDR-8",			"ALL"		},
-	{ "HITACHI CDR-8335",			"ALL"		},
-	{ "HITACHI CDR-8435",			"ALL"		},
-	{ "Toshiba CD-ROM XM-6202B",		"ALL"		},
-	{ "CD-532E-A",				"ALL"		},
-	{ "E-IDE CD-ROM CR-840",		"ALL"		},
-	{ "CD-ROM Drive/F5A",			"ALL"		},
-	{ "RICOH CD-R/RW MP7083A",		"ALL"		},
-	{ "WPI CDD-820",			"ALL"		},
-	{ "SAMSUNG CD-ROM SC-148C",		"ALL"		},
-	{ "SAMSUNG CD-ROM SC-148F",		"ALL"		},
-	{ "SAMSUNG CD-ROM SC",			"ALL"		},
-	{ "SanDisk SDP3B-64",			"ALL"		},
-	{ "SAMSUNG CD-ROM SN-124",		"ALL"		},
-	{ "PLEXTOR CD-R PX-W8432T",		"ALL"		},
-	{ "ATAPI CD-ROM DRIVE 40X MAXIMUM",	"ALL"		},
-	{ "_NEC DV5800A",			"ALL"		},
-	{ NULL,					0		}
-};
-
-static int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
-{
-	for ( ; drive_table->id_model ; drive_table++)
-		if ((!strcmp(drive_table->id_model, id->model)) &&
-		    ((!strstr(drive_table->id_firmware, id->fw_rev)) ||
-		     (!strcmp(drive_table->id_firmware, "ALL"))))
-			return 1;
-	return 0;
-}
-
-/*
- *  For both Blacklisted and Whitelisted drives.
- *  This is setup to be called as an extern for future support
- *  to other special driver code.
- */
-static int check_drive_lists(ide_drive_t *drive, int good_bad)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (good_bad) {
-		return in_drive_list(id, drive_whitelist);
-	} else {
-		int blacklist = in_drive_list(id, drive_blacklist);
-		if (blacklist)
-			printk("%s: Disabling DMA for %s\n", drive->name, id->model);
-		return(blacklist);
-	}
-	return 0;
-}
-
-static int
-icside_dma_check(ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_hwif_t *hwif = HWIF(drive);
-	int autodma = hwif->autodma;
-	int xfer_mode = XFER_PIO_2;
-	int func = ide_dma_off_quietly;
-
-	if (!id || !(id->capability & 1) || !autodma)
-		goto out;
-
-	/*
-	 * Consult the list of known "bad" drives
-	 */
-	if (check_drive_lists(drive, 0)) {
-		func = ide_dma_off;
-		goto out;
-	}
-
-	/*
-	 * Enable DMA on any drive that has multiword DMA
-	 */
-	if (id->field_valid & 2) {
-		if (id->dma_mword & 4) {
-			xfer_mode = XFER_MW_DMA_2;
-			func = ide_dma_on;
-		} else if (id->dma_mword & 2) {
-			xfer_mode = XFER_MW_DMA_1;
-			func = ide_dma_on;
-		} else if (id->dma_mword & 1) {
-			xfer_mode = XFER_MW_DMA_0;
-			func = ide_dma_on;
-		}
-		goto out;
-	}
-
-	/*
-	 * Consult the list of known "good" drives
-	 */
-	if (check_drive_lists(drive, 1)) {
-		if (id->eide_dma_time > 150)
-			goto out;
-		xfer_mode = XFER_MW_DMA_1;
-		func = ide_dma_on;
-	}
-
-out:
-	func = icside_config_if(drive, xfer_mode);
-
-	return hwif->dmaproc(func, drive);
-}
-
-static int
-icside_dma_verbose(ide_drive_t *drive)
-{
-	printk(", DMA");
-	return 1;
-}
-
-static int
-icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	int count, reading = 0;
-
-	switch (func) {
-	case ide_dma_off:
-		printk("%s: DMA disabled\n", drive->name);
-		/*FALLTHROUGH*/
-
-	case ide_dma_off_quietly:
-	case ide_dma_on:
-		drive->using_dma = (func == ide_dma_on);
-		return 0;
-
-	case ide_dma_check:
-		return icside_dma_check(drive);
-
-	case ide_dma_read:
-		reading = 1;
-	case ide_dma_write:
-		count = icside_build_dmatable(drive, reading);
-		if (!count)
-			return 1;
-		disable_dma(hwif->hw.dma);
-
-		/* Route the DMA signals to
-		 * to the correct interface.
-		 */
-		outb(hwif->select_data, hwif->config_data);
-
-		/* Select the correct timing
-		 * for this drive
-		 */
-		set_dma_speed(hwif->hw.dma, drive->drive_data);
-
-		set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count);
-		set_dma_mode(hwif->hw.dma, reading ? DMA_MODE_READ
-			     : DMA_MODE_WRITE);
-
-		drive->waiting_for_dma = 1;
-		if (drive->media != ide_disk)
-			return 0;
-
-		ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
-		OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA,
-			 IDE_COMMAND_REG);
-
-	case ide_dma_begin:
-		enable_dma(hwif->hw.dma);
-		return 0;
-
-	case ide_dma_end:
-		drive->waiting_for_dma = 0;
-		disable_dma(hwif->hw.dma);
-		icside_destroy_dmatable(drive);
-		return get_dma_residue(hwif->hw.dma) != 0;
-
-	case ide_dma_test_irq:
-		return inb((unsigned long)hwif->hw.priv) & 1;
-
-	case ide_dma_bad_drive:
-	case ide_dma_good_drive:
-		return check_drive_lists(drive, (func == ide_dma_good_drive));
-
-	case ide_dma_verbose:
-		return icside_dma_verbose(drive);
-
-	case ide_dma_timeout:
-	default:
-		printk("icside_dmaproc: unsupported %s func: %d\n",
-			ide_dmafunc_verbose(func), func);
-	}
-	return 1;
-}
-
-static int
-icside_setup_dma(ide_hwif_t *hwif, int autodma)
-{
-	printk("    %s: SG-DMA", hwif->name);
-
-	hwif->sg_table = kmalloc(sizeof(struct scatterlist) * NR_ENTRIES,
-				 GFP_KERNEL);
-	if (!hwif->sg_table)
-		goto failed;
-
-	hwif->dmatable_cpu = NULL;
-	hwif->dmatable_dma = 0;
-	hwif->speedproc = icside_set_speed;
-	hwif->dmaproc = icside_dmaproc;
-	hwif->autodma = autodma;
-
-	printk(" capable%s\n", autodma ?
-		", auto-enable" : "");
-
-	return 1;
-
-failed:
-	printk(" -- ERROR, unable to allocate DMA table\n");
-	return 0;
-}
-#endif
-
-static ide_hwif_t *
-icside_find_hwif(unsigned long dataport)
-{
-	ide_hwif_t *hwif;
-	int index;
-
-	for (index = 0; index < MAX_HWIFS; ++index) {
-		hwif = &ide_hwifs[index];
-		if (hwif->io_ports[IDE_DATA_OFFSET] == (ide_ioreg_t)dataport)
-			goto found;
-	}
-
-	for (index = 0; index < MAX_HWIFS; ++index) {
-		hwif = &ide_hwifs[index];
-		if (!hwif->io_ports[IDE_DATA_OFFSET])
-			goto found;
-	}
-
-	return NULL;
-found:
-	return hwif;
-}
-
-static ide_hwif_t *
-icside_setup(unsigned long base, struct cardinfo *info, int irq)
-{
-	unsigned long port = base + info->dataoffset;
-	ide_hwif_t *hwif;
-
-	hwif = icside_find_hwif(base);
-	if (hwif) {
-		int i;
-
-		memset(&hwif->hw, 0, sizeof(hw_regs_t));
-
-		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-			hwif->hw.io_ports[i] = (ide_ioreg_t)port;
-			hwif->io_ports[i] = (ide_ioreg_t)port;
-			port += 1 << info->stepping;
-		}
-		hwif->hw.io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
-		hwif->io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
-		hwif->hw.irq  = irq;
-		hwif->irq     = irq;
-		hwif->hw.dma  = NO_DMA;
-		hwif->noprobe = 0;
-		hwif->chipset = ide_acorn;
-	}
-
-	return hwif;
-}
-
-static int __init icside_register_v5(struct expansion_card *ec, int autodma)
-{
-	unsigned long slot_port;
-	ide_hwif_t *hwif;
-
-	slot_port = ecard_address(ec, ECARD_MEMC, 0);
-
-	ec->irqaddr  = (unsigned char *)ioaddr(slot_port + ICS_ARCIN_V5_INTRSTAT);
-	ec->irqmask  = 1;
-	ec->irq_data = (void *)slot_port;
-	ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v5;
-
-	/*
-	 * Be on the safe side - disable interrupts
-	 */
-	inb(slot_port + ICS_ARCIN_V5_INTROFFSET);
-
-	hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec->irq);
-
-	return hwif ? 0 : -1;
-}
-
-static int __init icside_register_v6(struct expansion_card *ec, int autodma)
-{
-	unsigned long slot_port, port;
-	ide_hwif_t *hwif, *mate;
-	int sel = 0;
-
-	slot_port = ecard_address(ec, ECARD_IOC, ECARD_FAST);
-	port      = ecard_address(ec, ECARD_EASI, ECARD_FAST);
-
-	if (port == 0)
-		port = slot_port;
-	else
-		sel = 1 << 5;
-
-	outb(sel, slot_port);
-
-	ec->irq_data = (void *)port;
-	ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v6;
-
-	/*
-	 * Be on the safe side - disable interrupts
-	 */
-	inb(port + ICS_ARCIN_V6_INTROFFSET_1);
-	inb(port + ICS_ARCIN_V6_INTROFFSET_2);
-
-	hwif = icside_setup(port, &icside_cardinfo_v6_1, ec->irq);
-	mate = icside_setup(port, &icside_cardinfo_v6_2, ec->irq);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
-	if (ec->dma != NO_DMA) {
-		if (request_dma(ec->dma, hwif->name))
-			goto no_dma;
-
-		if (hwif) {
-			hwif->config_data = slot_port;
-			hwif->select_data = sel;
-			hwif->hw.dma  = ec->dma;
-			hwif->hw.priv = (void *)
-					(port + ICS_ARCIN_V6_INTRSTAT_1);
-			hwif->channel = 0;
-			icside_setup_dma(hwif, autodma);
-		}
-		if (mate) {
-			mate->config_data = slot_port;
-			mate->select_data = sel | 1;
-			mate->hw.dma  = ec->dma;
-			mate->hw.priv = (void *)
-					(port + ICS_ARCIN_V6_INTRSTAT_2);
-			mate->channel = 1;
-			icside_setup_dma(mate, autodma);
-		}
-	}
-no_dma:
-#endif
-	return hwif || mate ? 0 : -1;
-}
-
-int __init icside_init(void)
-{
-	int autodma = 0;
-
-#ifdef CONFIG_IDEDMA_ICS_AUTO
-	autodma = 1;
-#endif
-
-	ecard_startfind ();
-
-	do {
-		struct expansion_card *ec;
-		int result;
-
-		ec = ecard_find(0, icside_cids);
-		if (ec == NULL)
-			break;
-
-		ecard_claim(ec);
-
-		switch (icside_identifyif(ec)) {
-		case ics_if_arcin_v5:
-			result = icside_register_v5(ec, autodma);
-			break;
-
-		case ics_if_arcin_v6:
-			result = icside_register_v6(ec, autodma);
-			break;
-
-		default:
-			result = -1;
-			break;
-		}
-
-		if (result)
-			ecard_release(ec);
-	} while (1);
-
-	return 0;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-adma.c linux-2.4.21/drivers/ide/ide-adma.c
--- linux-2.4.20/drivers/ide/ide-adma.c	2001-08-13 22:44:03.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-adma.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,9 +0,0 @@
-/*
- *  linux/drivers/ide/ide-adma.c         Version 0.00	June 24, 2001
- *
- *  Copyright (c) 2001		Andre Hedrick <andre@linux-ide.org>
- *
- *  Asynchronous DMA -- TBA, this is a holding file.
- *
- */
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-cd.c linux-2.4.21/drivers/ide/ide-cd.c
--- linux-2.4.20/drivers/ide/ide-cd.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-cd.c	2002-12-18 18:58:08.000000000 +0000
@@ -540,7 +540,124 @@
 }
 
 
-static void cdrom_end_request (int uptodate, ide_drive_t *drive)
+/*
+ * This is our end_request replacement function.
+ */
+static int ide_cdrom_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		add_blkdev_randomness(MAJOR(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return ret;
+}
+
+/*
+ * Error reporting, in human readable form (luxurious, but a memory hog).
+ */
+byte ide_cdrom_dump_status (ide_drive_t *drive, const char *msg, byte stat)
+{
+	unsigned long flags;
+
+	atapi_status_t status;
+	atapi_error_t error;
+
+	status.all = stat;
+	local_irq_set(flags);
+	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
+#if FANCY_STATUS_DUMPS
+	printk(" { ");
+	if (status.b.bsy)
+		printk("Busy ");
+	else {
+		if (status.b.drdy)	printk("DriveReady ");
+		if (status.b.df)	printk("DeviceFault ");
+		if (status.b.dsc)	printk("SeekComplete ");
+		if (status.b.drq)	printk("DataRequest ");
+		if (status.b.corr)	printk("CorrectedError ");
+		if (status.b.idx)	printk("Index ");
+		if (status.b.check)	printk("Error ");
+	}
+	printk("}");
+#endif	/* FANCY_STATUS_DUMPS */
+	printk("\n");
+	if ((status.all & (status.b.bsy|status.b.check)) == status.b.check) {
+		error.all = HWIF(drive)->INB(IDE_ERROR_REG);
+		printk("%s: %s: error=0x%02x", drive->name, msg, error.all);
+#if FANCY_STATUS_DUMPS
+		if (error.b.ili)	printk("IllegalLengthIndication ");
+		if (error.b.eom)	printk("EndOfMedia ");
+		if (error.b.abrt)	printk("Aborted Command ");
+		if (error.b.mcr)	printk("MediaChangeRequested ");
+		if (error.b.sense_key)	printk("LastFailedSense 0x%02x ",
+						error.b.sense_key);
+#endif	/* FANCY_STATUS_DUMPS */
+		printk("\n");
+	}
+	local_irq_restore(flags);
+	return error.all;
+}
+
+/*
+ * ide_error() takes action based on the error returned by the drive.
+ */
+ide_startstop_t ide_cdrom_error (ide_drive_t *drive, const char *msg, byte stat)
+{
+	struct request *rq;
+	byte err;
+
+	err = ide_cdrom_dump_status(drive, msg, stat);
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+	/* retry only "normal" I/O: */
+	if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) {
+		rq->errors = 1;
+		ide_end_drive_cmd(drive, stat, err);
+		return ide_stopped;
+	}
+
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
+		/* other bits are useless when BUSY */
+		rq->errors |= ERROR_RESET;
+	} else {
+		/* add decoding error stuff */
+	}
+	if (HWIF(drive)->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
+		/* force an abort */
+		HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
+	if (rq->errors >= ERROR_MAX) {
+		DRIVER(drive)->end_request(drive, 0);
+	} else {
+		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+			++rq->errors;
+			return ide_do_reset(drive);
+		}
+		++rq->errors;
+	}
+	return ide_stopped;
+}
+
+static void cdrom_end_request (ide_drive_t *drive, int uptodate)
 {
 	struct request *rq = HWGROUP(drive)->rq;
 
@@ -550,11 +667,10 @@
 			(struct packet_command *) pc->sense,
 			(struct request_sense *) (pc->buffer - pc->c[4]));
 	}
-	if (rq->cmd == READ || rq->cmd == WRITE)
-		if (!rq->current_nr_sectors)
-			uptodate = 1;
+	if (blk_fs_request(rq) && !rq->current_nr_sectors)
+		uptodate = 1;
 
-	ide_end_request (uptodate, HWGROUP(drive));
+	ide_cdrom_end_request(drive, uptodate);
 }
 
 
@@ -568,14 +684,13 @@
 	struct packet_command *pc;
 	
 	/* Check for errors. */
-	stat = GET_STAT();
-	*stat_ret = stat;
+	*stat_ret = stat = HWIF(drive)->INB(IDE_STATUS_REG);
 
 	if (OK_STAT (stat, good_stat, BAD_R_STAT))
 		return 0;
 
 	/* Get the IDE error register. */
-	err = GET_ERR();
+	err = HWIF(drive)->INB(IDE_ERROR_REG);
 	sense_key = err >> 4;
 
 	if (rq == NULL) {
@@ -591,8 +706,8 @@
 
 		pc = (struct packet_command *) rq->buffer;
 		pc->stat = 1;
-		cdrom_end_request (1, drive);
-		*startstop = ide_error (drive, "request sense failure", stat);
+		cdrom_end_request(drive, 1);
+		*startstop = DRIVER(drive)->error(drive, "request sense failure", stat);
 		return 1;
 
 	} else if (rq->cmd == PACKET_COMMAND) {
@@ -628,11 +743,11 @@
 		}
 
 		pc->stat = 1;
-		cdrom_end_request (1, drive);
+		cdrom_end_request(drive, 1);
 
 		if ((stat & ERR_STAT) != 0)
 			cdrom_queue_request_sense(drive, wait, pc->sense, pc);
-	} else {
+	} else if (blk_fs_request(rq)) {
 		/* Handle errors from READ and WRITE requests. */
 
 		if (sense_key == NOT_READY) {
@@ -641,7 +756,7 @@
 
 			/* Fail the request. */
 			printk ("%s: tray open\n", drive->name);
-			cdrom_end_request (0, drive);
+			cdrom_end_request(drive, 0);
 		} else if (sense_key == UNIT_ATTENTION) {
 			/* Media change. */
 			cdrom_saw_media_change (drive);
@@ -650,21 +765,26 @@
 			   But be sure to give up if we've retried
 			   too many times. */
 			if (++rq->errors > ERROR_MAX)
-				cdrom_end_request (0, drive);
+				cdrom_end_request(drive, 0);
 		} else if (sense_key == ILLEGAL_REQUEST ||
 			   sense_key == DATA_PROTECT) {
 			/* No point in retrying after an illegal
 			   request or data protect error.*/
 			ide_dump_status (drive, "command error", stat);
-			cdrom_end_request (0, drive);
+			cdrom_end_request(drive, 0);
 		} else if ((err & ~ABRT_ERR) != 0) {
 			/* Go to the default handler
 			   for other errors. */
-			*startstop = ide_error (drive, "cdrom_decode_status", stat);
+			*startstop = DRIVER(drive)->error(drive, "cdrom_decode_status", stat);
 			return 1;
+		} else if (sense_key == MEDIUM_ERROR) {
+			/* No point in re-trying a zillion times on a bad 
+			 * sector...  If we got here the error is not correctable */
+			ide_dump_status (drive, "media error (bad sector)", stat);
+			cdrom_end_request(drive, 0);
 		} else if ((++rq->errors > ERROR_MAX)) {
 			/* We've racked up too many retries.  Abort. */
-			cdrom_end_request (0, drive);
+			cdrom_end_request(drive, 0);
 		}
 
 		/* If we got a CHECK_CONDITION status,
@@ -723,33 +843,34 @@
 
 	if (info->dma) {
 		if (info->cmd == READ) {
-			info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
+			info->dma = !HWIF(drive)->ide_dma_read(drive);
 		} else if (info->cmd == WRITE) {
-			info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive);
+			info->dma = !HWIF(drive)->ide_dma_write(drive);
 		} else {
 			printk("ide-cd: DMA set, but not allowed\n");
 		}
 	}
 
 	/* Set up the controller registers. */
-	OUT_BYTE (info->dma, IDE_FEATURE_REG);
-	OUT_BYTE (0, IDE_NSECTOR_REG);
-	OUT_BYTE (0, IDE_SECTOR_REG);
+	HWIF(drive)->OUTB(info->dma, IDE_FEATURE_REG);
+	HWIF(drive)->OUTB(0, IDE_IREASON_REG);
+	HWIF(drive)->OUTB(0, IDE_SECTOR_REG);
 
-	OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);
-	OUT_BYTE (xferlen >> 8  , IDE_HCYL_REG);
+	HWIF(drive)->OUTB(xferlen & 0xff, IDE_BCOUNTL_REG);
+	HWIF(drive)->OUTB(xferlen >> 8  , IDE_BCOUNTH_REG);
 	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
+		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
  
-	if (info->dma)
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
-
 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
 		ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		/* packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return ide_started;
 	} else {
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		/* packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return (*handler) (drive);
 	}
 }
@@ -770,27 +891,37 @@
 	unsigned char *cmd_buf	= pc->c;
 	int cmd_len		= sizeof(pc->c);
 	unsigned int timeout	= pc->timeout;
+	struct cdrom_info *info = drive->driver_data;
 	ide_startstop_t startstop;
 
-	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+	if (CDROM_CONFIG_FLAGS(drive)->drq_interrupt) {
 		/* Here we should have been called after receiving an interrupt
 		   from the device.  DRQ should how be set. */
 		int stat_dum;
 
 		/* Check for errors. */
-		if (cdrom_decode_status (&startstop, drive, DRQ_STAT, &stat_dum))
+		if (cdrom_decode_status(&startstop, drive, DRQ_STAT, &stat_dum))
 			return startstop;
 	} else {
 		/* Otherwise, we must wait for DRQ to get set. */
-		if (ide_wait_stat (&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY))
+		if (ide_wait_stat(&startstop, drive, DRQ_STAT,
+				BUSY_STAT, WAIT_READY))
 			return startstop;
 	}
 
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+
 	/* Arm the interrupt handler. */
-	ide_set_handler (drive, handler, timeout, cdrom_timer_expiry);
+	ide_set_handler(drive, handler, timeout, cdrom_timer_expiry);
 
 	/* Send the command to the device. */
-	atapi_output_bytes (drive, cmd_buf, cmd_len);
+	HWIF(drive)->atapi_output_bytes(drive, cmd_buf, cmd_len);
+
+	/* Start the DMA if need be */
+	if (info->dma)
+		(void) HWIF(drive)->ide_dma_begin(drive);
+
 	return ide_started;
 }
 
@@ -828,7 +959,7 @@
 	/* Read the data into the buffer. */
 	dest = info->buffer + info->nsectors_buffered * SECTOR_SIZE;
 	while (sectors_to_buffer > 0) {
-		atapi_input_bytes (drive, dest, SECTOR_SIZE);
+		HWIF(drive)->atapi_input_bytes(drive, dest, SECTOR_SIZE);
 		--sectors_to_buffer;
 		--sectors_to_transfer;
 		++info->nsectors_buffered;
@@ -838,7 +969,7 @@
 	/* Throw away any remaining data. */
 	while (sectors_to_transfer > 0) {
 		char dum[SECTOR_SIZE];
-		atapi_input_bytes (drive, dum, sizeof (dum));
+		HWIF(drive)->atapi_input_bytes(drive, dum, sizeof (dum));
 		--sectors_to_transfer;
 	}
 }
@@ -864,14 +995,14 @@
 		   and quit this request. */
 		while (len > 0) {
 			int dum = 0;
-			atapi_output_bytes (drive, &dum, sizeof (dum));
+			HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof (dum));
 			len -= sizeof (dum);
 		}
 	} else  if (ireason == 1) {
 		/* Some drives (ASUS) seem to tell us that status
 		 * info is available. just get it and ignore.
 		 */
-		GET_STAT();
+		(void) HWIF(drive)->INB(IDE_STATUS_REG);
 		return 0;
 	} else {
 		/* Drive wants a command packet, or invalid ireason... */
@@ -879,7 +1010,7 @@
 			drive->name, ireason);
 	}
 
-	cdrom_end_request (0, drive);
+	cdrom_end_request(drive, 0);
 	return -1;
 }
 
@@ -891,6 +1022,7 @@
 	int stat;
 	int ireason, len, sectors_to_transfer, nskip;
 	struct cdrom_info *info = drive->driver_data;
+	u8 lowcyl = 0, highcyl = 0;
 	int i, dma = info->dma, dma_error = 0;
 	ide_startstop_t startstop;
 
@@ -899,8 +1031,8 @@
 	/* Check for errors. */
 	if (dma) {
 		info->dma = 0;
-		if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive)))
-			HWIF(drive)->dmaproc(ide_dma_off, drive);
+		if ((dma_error = HWIF(drive)->ide_dma_end(drive)))
+			HWIF(drive)->ide_dma_off(drive);
 	}
 
 	if (cdrom_decode_status (&startstop, drive, 0, &stat))
@@ -910,16 +1042,19 @@
 		if (!dma_error) {
 			for (i = rq->nr_sectors; i > 0;) {
 				i -= rq->current_nr_sectors;
-				ide_end_request(1, HWGROUP(drive));
+				ide_cdrom_end_request(drive, 1);
 			}
 			return ide_stopped;
 		} else
-			return ide_error (drive, "dma error", stat);
+			return DRIVER(drive)->error(drive, "dma error", stat);
 	}
 
 	/* Read the interrupt reason and the transfer length. */
-	ireason = IN_BYTE (IDE_NSECTOR_REG);
-	len = IN_BYTE (IDE_LCYL_REG) + 256 * IN_BYTE (IDE_HCYL_REG);
+	ireason = HWIF(drive)->INB(IDE_IREASON_REG);
+	lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+
+	len = lowcyl + (256 * highcyl);
 
 	/* If DRQ is clear, the command has completed. */
 	if ((stat & DRQ_STAT) == 0) {
@@ -928,9 +1063,9 @@
 		if (rq->current_nr_sectors > 0) {
 			printk ("%s: cdrom_read_intr: data underrun (%ld blocks)\n",
 				drive->name, rq->current_nr_sectors);
-			cdrom_end_request (0, drive);
+			cdrom_end_request(drive, 0);
 		} else
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 		return ide_stopped;
 	}
 
@@ -944,13 +1079,13 @@
 	if ((len % SECTOR_SIZE) != 0) {
 		printk ("%s: cdrom_read_intr: Bad transfer size %d\n",
 			drive->name, len);
-		if (CDROM_CONFIG_FLAGS (drive)->limit_nframes)
+		if (CDROM_CONFIG_FLAGS(drive)->limit_nframes)
 			printk ("  This drive is not supported by this version of the driver\n");
 		else {
 			printk ("  Trying to limit transfer sizes\n");
-			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
+			CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
 		}
-		cdrom_end_request (0, drive);
+		cdrom_end_request(drive, 0);
 		return ide_stopped;
 	}
 
@@ -965,7 +1100,7 @@
 	while (nskip > 0) {
 		/* We need to throw away a sector. */
 		char dum[SECTOR_SIZE];
-		atapi_input_bytes (drive, dum, sizeof (dum));
+		HWIF(drive)->atapi_input_bytes(drive, dum, sizeof (dum));
 
 		--rq->current_nr_sectors;
 		--nskip;
@@ -979,7 +1114,7 @@
 		/* If we've filled the present buffer but there's another
 		   chained buffer after it, move on. */
 		if (rq->current_nr_sectors == 0 && rq->nr_sectors)
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 
 		/* If the buffers are full, cache the rest of the data in our
 		   internal buffer. */
@@ -996,7 +1131,7 @@
 			/* Read this_transfer sectors
 			   into the current buffer. */
 			while (this_transfer > 0) {
-				atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE);
+				HWIF(drive)->atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE);
 				rq->buffer += SECTOR_SIZE;
 				--rq->nr_sectors;
 				--rq->current_nr_sectors;
@@ -1007,8 +1142,10 @@
 		}
 	}
 
-	/* Done moving data!
-	   Wait for another interrupt. */
+	if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
+		BUG();
+
+	/* Done moving data!  Wait for another interrupt. */
 	ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL);
 	return ide_started;
 }
@@ -1031,7 +1168,7 @@
 	       rq->sector >= info->sector_buffered &&
 	       rq->sector < info->sector_buffered + info->nsectors_buffered) {
 		if (rq->current_nr_sectors == 0)
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 
 		memcpy (rq->buffer,
 			info->buffer +
@@ -1046,13 +1183,13 @@
 	/* If we've satisfied the current request,
 	   terminate it successfully. */
 	if (rq->nr_sectors == 0) {
-		cdrom_end_request (1, drive);
+		cdrom_end_request(drive, 1);
 		return -1;
 	}
 
 	/* Move on to the next buffer if needed. */
 	if (rq->current_nr_sectors == 0)
-		cdrom_end_request (1, drive);
+		cdrom_end_request(drive, 1);
 
 	/* If this condition does not hold, then the kluge i use to
 	   represent the number of sectors to skip at the start of a transfer
@@ -1060,9 +1197,9 @@
 	   paranoid and check. */
 	if (rq->current_nr_sectors < (rq->bh->b_size >> SECTOR_BITS) &&
 	    (rq->sector % SECTORS_PER_FRAME) != 0) {
-		printk ("%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
+		printk("%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
 			drive->name, rq->sector);
-		cdrom_end_request (0, drive);
+		cdrom_end_request(drive, 0);
 		return -1;
 	}
 
@@ -1101,7 +1238,7 @@
 			(rq->sector % CD_FRAMESIZE != 0)) {
 			printk ("%s: cdrom_start_read_continuation: buffer botch (%lu)\n",
 				drive->name, rq->current_nr_sectors);
-			cdrom_end_request (0, drive);
+			cdrom_end_request(drive, 0);
 			return ide_stopped;
 		}
 		sector -= nskip;
@@ -1147,7 +1284,7 @@
 		return startstop;
 	CDROM_CONFIG_FLAGS(drive)->seeking = 1;
 
-	if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) {
+	if (retry && time_after(jiffies, info->start_seek + IDECD_SEEK_TIMER)) {
 		if (--retry == 0) {
 			/*
 			 * this condition is far too common, to bother
@@ -1189,7 +1326,7 @@
 	info->dma = 0;
 	info->cmd = 0;
 	info->start_seek = jiffies;
-	return cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation);
+	return cdrom_start_packet_command(drive, 0, cdrom_start_seek_continuation);
 }
 
 static inline int cdrom_merge_requests(struct request *rq, struct request *nxt)
@@ -1263,7 +1400,7 @@
 {
 	struct cdrom_info *info = drive->driver_data;
 	struct request *rq = HWGROUP(drive)->rq;
-	int minor = MINOR (rq->rq_dev);
+	int minor = MINOR(rq->rq_dev);
 
 	/* If the request is relative to a partition, fix it up to refer to the
 	   absolute address.  */
@@ -1313,14 +1450,18 @@
 	struct request *rq = HWGROUP(drive)->rq;
 	struct packet_command *pc = (struct packet_command *)rq->buffer;
 	ide_startstop_t startstop;
+	u8 lowcyl = 0, highcyl = 0;
 
 	/* Check for errors. */
-	if (cdrom_decode_status (&startstop, drive, 0, &stat))
+	if (cdrom_decode_status(&startstop, drive, 0, &stat))
 		return startstop;
 
 	/* Read the interrupt reason and the transfer length. */
-	ireason = IN_BYTE (IDE_NSECTOR_REG);
-	len = IN_BYTE (IDE_LCYL_REG) + 256 * IN_BYTE (IDE_HCYL_REG);
+	ireason = HWIF(drive)->INB(IDE_IREASON_REG);
+	lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+
+	len = lowcyl + (256 * highcyl);
 
 	/* If DRQ is clear, the command has completed.
 	   Complain if we still have data left to transfer. */
@@ -1337,7 +1478,7 @@
 		}
 
 		if (pc->buflen == 0)
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 		else {
 			/* Comment this out, because this always happens 
 			   right after a reset occurs, and it is annoying to 
@@ -1347,7 +1488,7 @@
 				drive->name, pc->buflen);
 			*/
 			pc->stat = 1;
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 		}
 		return ide_stopped;
 	}
@@ -1359,14 +1500,14 @@
 	/* The drive wants to be written to. */
 	if ((ireason & 3) == 0) {
 		/* Transfer the data. */
-		atapi_output_bytes (drive, pc->buffer, thislen);
+		HWIF(drive)->atapi_output_bytes(drive, pc->buffer, thislen);
 
 		/* If we haven't moved enough data to satisfy the drive,
 		   add some padding. */
 		while (len > thislen) {
 			int dum = 0;
-			atapi_output_bytes (drive, &dum, sizeof (dum));
-			len -= sizeof (dum);
+			HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof(dum));
+			len -= sizeof(dum);
 		}
 
 		/* Keep count of how much data we've moved. */
@@ -1378,14 +1519,14 @@
 	else if ((ireason & 3) == 2) {
 
 		/* Transfer the data. */
-		atapi_input_bytes (drive, pc->buffer, thislen);
+		HWIF(drive)->atapi_input_bytes(drive, pc->buffer, thislen);
 
 		/* If we haven't moved enough data to satisfy the drive,
 		   add some padding. */
 		while (len > thislen) {
 			int dum = 0;
-			atapi_input_bytes (drive, &dum, sizeof (dum));
-			len -= sizeof (dum);
+			HWIF(drive)->atapi_input_bytes(drive, &dum, sizeof(dum));
+			len -= sizeof(dum);
 		}
 
 		/* Keep count of how much data we've moved. */
@@ -1398,8 +1539,11 @@
 		pc->stat = 1;
 	}
 
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+
 	/* Now we wait for another interrupt. */
-	ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
+	ide_set_handler(drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
 	return ide_started;
 }
 
@@ -1430,7 +1574,7 @@
 	len = pc->buflen;
 
 	/* Start sending the command to the drive. */
-	return cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation);
+	return cdrom_start_packet_command(drive, len, cdrom_do_pc_continuation);
 }
 
 
@@ -1462,7 +1606,7 @@
 		ide_init_drive_cmd (&req);
 		req.cmd = PACKET_COMMAND;
 		req.buffer = (char *)pc;
-		ide_do_drive_cmd (drive, &req, ide_wait);
+		ide_do_drive_cmd(drive, &req, ide_wait);
 		/* FIXME: we should probably abort/retry or something 
 		 * in case of failure */
 		if (pc->stat != 0) {
@@ -1472,7 +1616,7 @@
 			struct request_sense *reqbuf = pc->sense;
 
 			if (reqbuf->sense_key == UNIT_ATTENTION)
-				cdrom_saw_media_change (drive);
+				cdrom_saw_media_change(drive);
 			else if (reqbuf->sense_key == NOT_READY &&
 				 reqbuf->asc == 4 && reqbuf->ascq != 4) {
 				/* The drive is in the process of loading
@@ -1513,7 +1657,7 @@
 		   and quit this request. */
 		while (len > 0) {
 			int dum = 0;
-			atapi_output_bytes(drive, &dum, sizeof(dum));
+			HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof(dum));
 			len -= sizeof(dum);
 		}
 	} else {
@@ -1522,7 +1666,7 @@
 			drive->name, ireason);
 	}
 
-	cdrom_end_request(0, drive);
+	cdrom_end_request(drive, 0);
 	return 1;
 }
 
@@ -1531,6 +1675,7 @@
 	int stat, ireason, len, sectors_to_transfer, uptodate;
 	struct cdrom_info *info = drive->driver_data;
 	int i, dma_error = 0, dma = info->dma;
+	u8 lowcyl = 0, highcyl = 0;
 	ide_startstop_t startstop;
 
 	struct request *rq = HWGROUP(drive)->rq;
@@ -1538,9 +1683,9 @@
 	/* Check for errors. */
 	if (dma) {
 		info->dma = 0;
-		if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive))) {
+		if ((dma_error = HWIF(drive)->ide_dma_end(drive))) {
 			printk("ide-cd: write dma error\n");
-			HWIF(drive)->dmaproc(ide_dma_off, drive);
+			HWIF(drive)->ide_dma_off(drive);
 		}
 	}
 
@@ -1554,19 +1699,22 @@
 	 */
 	if (dma) {
 		if (dma_error)
-			return ide_error(drive, "dma error", stat);
+			return DRIVER(drive)->error(drive, "dma error", stat);
 
 		rq = HWGROUP(drive)->rq;
 		for (i = rq->nr_sectors; i > 0;) {
 			i -= rq->current_nr_sectors;
-			ide_end_request(1, HWGROUP(drive));
+			ide_cdrom_end_request(drive, 1);
 		}
 		return ide_stopped;
 	}
 
 	/* Read the interrupt reason and the transfer length. */
-	ireason = IN_BYTE(IDE_NSECTOR_REG);
-	len = IN_BYTE(IDE_LCYL_REG) + 256 * IN_BYTE(IDE_HCYL_REG);
+	ireason = HWIF(drive)->INB(IDE_IREASON_REG);
+	lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+
+	len = lowcyl + (256 * highcyl);
 
 	/* If DRQ is clear, the command has completed. */
 	if ((stat & DRQ_STAT) == 0) {
@@ -1579,7 +1727,7 @@
 			drive->name, rq->current_nr_sectors);
 			uptodate = 0;
 		}
-		cdrom_end_request(uptodate, drive);
+		cdrom_end_request(drive, uptodate);
 		return ide_stopped;
 	}
 
@@ -1607,7 +1755,7 @@
 		this_transfer = MIN(sectors_to_transfer,rq->current_nr_sectors);
 
 		while (this_transfer > 0) {
-			atapi_output_bytes(drive, rq->buffer, SECTOR_SIZE);
+			HWIF(drive)->atapi_output_bytes(drive, rq->buffer, SECTOR_SIZE);
 			rq->buffer += SECTOR_SIZE;
 			--rq->nr_sectors;
 			--rq->current_nr_sectors;
@@ -1620,9 +1768,12 @@
 		 * current buffer complete, move on
 		 */
 		if (rq->current_nr_sectors == 0 && rq->nr_sectors)
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 	}
 
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+
 	/* re-arm handler */
 	ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL);
 	return ide_started;
@@ -1662,7 +1813,7 @@
 	 * writes *must* be 2kB frame aligned
 	 */
 	if ((rq->nr_sectors & 3) || (rq->sector & 3)) {
-		cdrom_end_request(0, drive);
+		cdrom_end_request(drive, 0);
 		return ide_stopped;
 	}
 
@@ -1698,11 +1849,10 @@
 		case WRITE:
 		case READ: {
 			if (CDROM_CONFIG_FLAGS(drive)->seeking) {
-				unsigned long elpased = jiffies - info->start_seek;
-				int stat = GET_STAT();
+				int stat = HWIF(drive)->INB(IDE_STATUS_REG);
 
 				if ((stat & SEEK_STAT) != SEEK_STAT) {
-					if (elpased < IDECD_SEEK_TIMEOUT) {
+					if (time_before(jiffies, info->start_seek + IDECD_SEEK_TIMEOUT)) {
 						ide_stall_queue(drive, IDECD_SEEK_TIMER);
 						return ide_stopped;
 					}
@@ -1711,9 +1861,9 @@
 				CDROM_CONFIG_FLAGS(drive)->seeking = 0;
 			}
 			if (IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap)
-				action = cdrom_start_seek (drive, block);
+				action = cdrom_start_seek(drive, block);
 			else {
-				if (rq->cmd == READ)
+				if (rq_data_dir(rq) == READ)
 					action = cdrom_start_read(drive, block);
 				else
 					action = cdrom_start_write(drive, rq);
@@ -1728,13 +1878,13 @@
 		}
 
 		case RESET_DRIVE_COMMAND: {
-			cdrom_end_request(1, drive);
+			cdrom_end_request(drive, 1);
 			return ide_do_reset(drive);
 		}
 
 		default: {
 			printk("ide-cd: bad cmd %d\n", rq->cmd);
-			cdrom_end_request(0, drive);
+			cdrom_end_request(drive, 0);
 			return ide_stopped;
 		}
 	}
@@ -1836,7 +1986,7 @@
 		pc.sense = sense;
 		pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
 		pc.c[4] = lockflag ? 1 : 0;
-		stat = cdrom_queue_packet_command (drive, &pc);
+		stat = cdrom_queue_packet_command(drive, &pc);
 	}
 
 	/* If we got an illegal field error, the drive
@@ -1846,7 +1996,7 @@
 	    (sense->asc == 0x24 || sense->asc == 0x20)) {
 		printk ("%s: door locking not supported\n",
 			drive->name);
-		CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
+		CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
 		stat = 0;
 	}
 	
@@ -1855,7 +2005,7 @@
 		stat = 0;
 
 	if (stat == 0)
-		CDROM_STATE_FLAGS (drive)->door_locked = lockflag;
+		CDROM_STATE_FLAGS(drive)->door_locked = lockflag;
 
 	return stat;
 }
@@ -1880,7 +2030,7 @@
 
 	pc.c[0] = GPCMD_START_STOP_UNIT;
 	pc.c[4] = 0x02 + (ejectflag != 0);
-	return cdrom_queue_packet_command (drive, &pc);
+	return cdrom_queue_packet_command(drive, &pc);
 }
 
 static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
@@ -1929,7 +2079,7 @@
 	if (msf_flag)
 		pc.c[1] = 2;
 
-	return cdrom_queue_packet_command (drive, &pc);
+	return cdrom_queue_packet_command(drive, &pc);
 }
 
 
@@ -1969,9 +2119,9 @@
 	if (stat) return stat;
 
 #if ! STANDARD_ATAPI
-	if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) {
-		toc->hdr.first_track = bcd2bin (toc->hdr.first_track);
-		toc->hdr.last_track  = bcd2bin (toc->hdr.last_track);
+	if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
+		toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
+		toc->hdr.last_track  = bcd2bin(toc->hdr.last_track);
 	}
 #endif  /* not STANDARD_ATAPI */
 
@@ -2009,7 +2159,7 @@
 			return stat;
 		}
 #if ! STANDARD_ATAPI
-		if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) {
+		if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
 			toc->hdr.first_track = bin2bcd(CDROM_LEADOUT);
 			toc->hdr.last_track = bin2bcd(CDROM_LEADOUT);
 		} else
@@ -2026,18 +2176,18 @@
 	toc->hdr.toc_length = ntohs (toc->hdr.toc_length);
 
 #if ! STANDARD_ATAPI
-	if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) {
-		toc->hdr.first_track = bcd2bin (toc->hdr.first_track);
-		toc->hdr.last_track  = bcd2bin (toc->hdr.last_track);
+	if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
+		toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
+		toc->hdr.last_track  = bcd2bin(toc->hdr.last_track);
 	}
 #endif  /* not STANDARD_ATAPI */
 
 	for (i=0; i<=ntracks; i++) {
 #if ! STANDARD_ATAPI
-		if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd) {
-			if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd)
-				toc->ent[i].track = bcd2bin (toc->ent[i].track);
-			msf_from_bcd (&toc->ent[i].addr.msf);
+		if (CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd) {
+			if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd)
+				toc->ent[i].track = bcd2bin(toc->ent[i].track);
+			msf_from_bcd(&toc->ent[i].addr.msf);
 		}
 #endif  /* not STANDARD_ATAPI */
 		toc->ent[i].addr.lba = msf_to_lba (toc->ent[i].addr.msf.minute,
@@ -2059,7 +2209,7 @@
 	}
 
 #if ! STANDARD_ATAPI
-	if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd)
+	if (CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd)
 		msf_from_bcd (&ms_tmp.ent.addr.msf);
 #endif  /* not STANDARD_ATAPI */
 
@@ -2082,7 +2232,7 @@
 	drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME;
 
 	/* Remember that we've read this stuff. */
-	CDROM_STATE_FLAGS (drive)->toc_valid = 1;
+	CDROM_STATE_FLAGS(drive)->toc_valid = 1;
 
 	return 0;
 }
@@ -2308,7 +2458,7 @@
 		struct cdrom_tocentry *tocentry = (struct cdrom_tocentry*) arg;
 		struct atapi_toc_entry *toce;
 
-		stat = cdrom_get_toc_entry (drive, tocentry->cdte_track, &toce);
+		stat = cdrom_get_toc_entry(drive, tocentry->cdte_track, &toce);
 		if (stat) return stat;
 
 		tocentry->cdte_ctrl = toce->control;
@@ -2380,10 +2530,10 @@
 	struct request_sense sense;
 	int stat;
 
-	if ((stat = cdrom_select_speed (drive, speed, &sense)) < 0)
+	if ((stat = cdrom_select_speed(drive, speed, &sense)) < 0)
 		return stat;
 
-        cdi->speed = CDROM_STATE_FLAGS (drive)->current_speed;
+        cdi->speed = CDROM_STATE_FLAGS(drive)->current_speed;
         return 0;
 }
 
@@ -2476,8 +2626,8 @@
 	
 	if (slot_nr == CDSL_CURRENT) {
 		(void) cdrom_check_status(drive, NULL);
-		retval = CDROM_STATE_FLAGS (drive)->media_changed;
-		CDROM_STATE_FLAGS (drive)->media_changed = 0;
+		retval = CDROM_STATE_FLAGS(drive)->media_changed;
+		CDROM_STATE_FLAGS(drive)->media_changed = 0;
 		return retval;
 	} else {
 		return -EINVAL;
@@ -2535,30 +2685,30 @@
 	struct cdrom_device_info *devinfo = &info->devinfo;
 	int minor = (drive->select.b.unit) << PARTN_BITS;
 
-	devinfo->dev = MKDEV (HWIF(drive)->major, minor);
+	devinfo->dev = MKDEV(HWIF(drive)->major, minor);
 	devinfo->ops = &ide_cdrom_dops;
 	devinfo->mask = 0;
-	devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed;
+	devinfo->speed = CDROM_STATE_FLAGS(drive)->current_speed;
 	devinfo->capacity = nslots;
 	devinfo->handle = (void *) drive;
 	strcpy(devinfo->name, drive->name);
 	
 	/* set capability mask to match the probe. */
-	if (!CDROM_CONFIG_FLAGS (drive)->cd_r)
+	if (!CDROM_CONFIG_FLAGS(drive)->cd_r)
 		devinfo->mask |= CDC_CD_R;
-	if (!CDROM_CONFIG_FLAGS (drive)->cd_rw)
+	if (!CDROM_CONFIG_FLAGS(drive)->cd_rw)
 		devinfo->mask |= CDC_CD_RW;
-	if (!CDROM_CONFIG_FLAGS (drive)->dvd)
+	if (!CDROM_CONFIG_FLAGS(drive)->dvd)
 		devinfo->mask |= CDC_DVD;
-	if (!CDROM_CONFIG_FLAGS (drive)->dvd_r)
+	if (!CDROM_CONFIG_FLAGS(drive)->dvd_r)
 		devinfo->mask |= CDC_DVD_R;
-	if (!CDROM_CONFIG_FLAGS (drive)->dvd_ram)
+	if (!CDROM_CONFIG_FLAGS(drive)->dvd_ram)
 		devinfo->mask |= CDC_DVD_RAM;
-	if (!CDROM_CONFIG_FLAGS (drive)->is_changer)
+	if (!CDROM_CONFIG_FLAGS(drive)->is_changer)
 		devinfo->mask |= CDC_SELECT_DISC;
-	if (!CDROM_CONFIG_FLAGS (drive)->audio_play)
+	if (!CDROM_CONFIG_FLAGS(drive)->audio_play)
 		devinfo->mask |= CDC_PLAY_AUDIO;
-	if (!CDROM_CONFIG_FLAGS (drive)->close_tray)
+	if (!CDROM_CONFIG_FLAGS(drive)->close_tray)
 		devinfo->mask |= CDC_CLOSE_TRAY;
 
 	devinfo->de = devfs_register(drive->de, "cd", DEVFS_FL_DEFAULT,
@@ -2612,9 +2762,9 @@
 	struct atapi_capabilities_page cap;
 	int nslots = 1;
 
-	if (CDROM_CONFIG_FLAGS (drive)->nec260) {
-		CDROM_CONFIG_FLAGS (drive)->no_eject = 0;                       
-		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;       
+	if (CDROM_CONFIG_FLAGS(drive)->nec260) {
+		CDROM_CONFIG_FLAGS(drive)->no_eject = 0;                       
+		CDROM_CONFIG_FLAGS(drive)->audio_play = 1;       
 		return nslots;
 	}
 
@@ -2622,38 +2772,38 @@
 		return 0;
 
 	if (cap.lock == 0)
-		CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
+		CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
 	if (cap.eject)
-		CDROM_CONFIG_FLAGS (drive)->no_eject = 0;
+		CDROM_CONFIG_FLAGS(drive)->no_eject = 0;
 	if (cap.cd_r_write)
-		CDROM_CONFIG_FLAGS (drive)->cd_r = 1;
+		CDROM_CONFIG_FLAGS(drive)->cd_r = 1;
 	if (cap.cd_rw_write)
-		CDROM_CONFIG_FLAGS (drive)->cd_rw = 1;
+		CDROM_CONFIG_FLAGS(drive)->cd_rw = 1;
 	if (cap.test_write)
-		CDROM_CONFIG_FLAGS (drive)->test_write = 1;
+		CDROM_CONFIG_FLAGS(drive)->test_write = 1;
 	if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom)
-		CDROM_CONFIG_FLAGS (drive)->dvd = 1;
+		CDROM_CONFIG_FLAGS(drive)->dvd = 1;
 	if (cap.dvd_ram_write)
-		CDROM_CONFIG_FLAGS (drive)->dvd_ram = 1;
+		CDROM_CONFIG_FLAGS(drive)->dvd_ram = 1;
 	if (cap.dvd_r_write)
-		CDROM_CONFIG_FLAGS (drive)->dvd_r = 1;
+		CDROM_CONFIG_FLAGS(drive)->dvd_r = 1;
 	if (cap.audio_play)
-		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
+		CDROM_CONFIG_FLAGS(drive)->audio_play = 1;
 	if (cap.mechtype == mechtype_caddy || cap.mechtype == mechtype_popup)
-		CDROM_CONFIG_FLAGS (drive)->close_tray = 0;
+		CDROM_CONFIG_FLAGS(drive)->close_tray = 0;
 
 	/* Some drives used by Apple don't advertise audio play
 	 * but they do support reading TOC & audio datas
 	 */
-	if (strcmp (drive->id->model, "MATSHITADVD-ROM SR-8187") == 0 ||
-	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8186") == 0 ||
-	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8176") == 0 ||
-	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8174") == 0)
-		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
+	if (strcmp(drive->id->model, "MATSHITADVD-ROM SR-8187") == 0 ||
+	    strcmp(drive->id->model, "MATSHITADVD-ROM SR-8186") == 0 ||
+	    strcmp(drive->id->model, "MATSHITADVD-ROM SR-8176") == 0 ||
+	    strcmp(drive->id->model, "MATSHITADVD-ROM SR-8174") == 0)
+		CDROM_CONFIG_FLAGS(drive)->audio_play = 1;
 
 #if ! STANDARD_ATAPI
 	if (cdi->sanyo_slot > 0) {
-		CDROM_CONFIG_FLAGS (drive)->is_changer = 1;
+		CDROM_CONFIG_FLAGS(drive)->is_changer = 1;
 		nslots = 3;
 	}
 
@@ -2662,21 +2812,22 @@
 	if (cap.mechtype == mechtype_individual_changer ||
 	    cap.mechtype == mechtype_cartridge_changer) {
 		if ((nslots = cdrom_number_of_slots(cdi)) > 1) {
-			CDROM_CONFIG_FLAGS (drive)->is_changer = 1;
-			CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 1;
+			CDROM_CONFIG_FLAGS(drive)->is_changer = 1;
+			CDROM_CONFIG_FLAGS(drive)->supp_disc_present = 1;
 		}
 	}
 
 	/* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */
-	if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) {
-		CDROM_STATE_FLAGS (drive)->current_speed  = 
+	if (drive->id && !drive->id->model[0] &&
+	    !strncmp(drive->id->fw_rev, "241N", 4)) {
+		CDROM_STATE_FLAGS(drive)->current_speed  = 
 			(((unsigned int)cap.curspeed) + (176/2)) / 176;
-		CDROM_CONFIG_FLAGS (drive)->max_speed = 
+		CDROM_CONFIG_FLAGS(drive)->max_speed = 
 			(((unsigned int)cap.maxspeed) + (176/2)) / 176;
 	} else {
-		CDROM_STATE_FLAGS (drive)->current_speed  = 
+		CDROM_STATE_FLAGS(drive)->current_speed  = 
 			(ntohs(cap.curspeed) + (176/2)) / 176;
-		CDROM_CONFIG_FLAGS (drive)->max_speed = 
+		CDROM_CONFIG_FLAGS(drive)->max_speed = 
 			(ntohs(cap.maxspeed) + (176/2)) / 176;
 	}
 
@@ -2687,26 +2838,26 @@
 		printk(" %dX", CDROM_CONFIG_FLAGS(drive)->max_speed);
 	printk(" %s", CDROM_CONFIG_FLAGS(drive)->dvd ? "DVD-ROM" : "CD-ROM");
 
-	if (CDROM_CONFIG_FLAGS (drive)->dvd_r|CDROM_CONFIG_FLAGS (drive)->dvd_ram)
-        	printk (" DVD%s%s", 
-        	(CDROM_CONFIG_FLAGS (drive)->dvd_r)? "-R" : "", 
-        	(CDROM_CONFIG_FLAGS (drive)->dvd_ram)? "-RAM" : "");
-
-        if (CDROM_CONFIG_FLAGS (drive)->cd_r|CDROM_CONFIG_FLAGS (drive)->cd_rw) 
-        	printk (" CD%s%s", 
-        	(CDROM_CONFIG_FLAGS (drive)->cd_r)? "-R" : "", 
-        	(CDROM_CONFIG_FLAGS (drive)->cd_rw)? "/RW" : "");
+	if (CDROM_CONFIG_FLAGS(drive)->dvd_r|CDROM_CONFIG_FLAGS(drive)->dvd_ram)
+        	printk(" DVD%s%s", 
+        	(CDROM_CONFIG_FLAGS(drive)->dvd_r)? "-R" : "", 
+        	(CDROM_CONFIG_FLAGS(drive)->dvd_ram)? "-RAM" : "");
+
+        if (CDROM_CONFIG_FLAGS(drive)->cd_r|CDROM_CONFIG_FLAGS(drive)->cd_rw) 
+        	printk(" CD%s%s", 
+        	(CDROM_CONFIG_FLAGS(drive)->cd_r)? "-R" : "", 
+        	(CDROM_CONFIG_FLAGS(drive)->cd_rw)? "/RW" : "");
 
-        if (CDROM_CONFIG_FLAGS (drive)->is_changer) 
-        	printk (" changer w/%d slots", nslots);
+        if (CDROM_CONFIG_FLAGS(drive)->is_changer) 
+        	printk(" changer w/%d slots", nslots);
         else 	
-        	printk (" drive");
+        	printk(" drive");
 
-	printk (", %dkB Cache", be16_to_cpu(cap.buffer_size));
+	printk(", %dkB Cache", be16_to_cpu(cap.buffer_size));
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (drive->using_dma)
-		(void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+		(void) HWIF(drive)->ide_dma_verbose(drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	printk("\n");
 
@@ -2741,42 +2892,42 @@
 	drive->special.all	= 0;
 	drive->ready_stat	= 0;
 
-	CDROM_STATE_FLAGS (drive)->media_changed = 1;
-	CDROM_STATE_FLAGS (drive)->toc_valid     = 0;
-	CDROM_STATE_FLAGS (drive)->door_locked   = 0;
+	CDROM_STATE_FLAGS(drive)->media_changed = 1;
+	CDROM_STATE_FLAGS(drive)->toc_valid     = 0;
+	CDROM_STATE_FLAGS(drive)->door_locked   = 0;
 
 #if NO_DOOR_LOCKING
-	CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
+	CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
 #else
-	CDROM_CONFIG_FLAGS (drive)->no_doorlock = 0;
+	CDROM_CONFIG_FLAGS(drive)->no_doorlock = 0;
 #endif
 
 	if (drive->id != NULL)
-		CDROM_CONFIG_FLAGS (drive)->drq_interrupt =
+		CDROM_CONFIG_FLAGS(drive)->drq_interrupt =
 			((drive->id->config & 0x0060) == 0x20);
 	else
-		CDROM_CONFIG_FLAGS (drive)->drq_interrupt = 0;
+		CDROM_CONFIG_FLAGS(drive)->drq_interrupt = 0;
 
-	CDROM_CONFIG_FLAGS (drive)->is_changer = 0;
-	CDROM_CONFIG_FLAGS (drive)->cd_r = 0;
-	CDROM_CONFIG_FLAGS (drive)->cd_rw = 0;
-	CDROM_CONFIG_FLAGS (drive)->test_write = 0;
-	CDROM_CONFIG_FLAGS (drive)->dvd = 0;
-	CDROM_CONFIG_FLAGS (drive)->dvd_r = 0;
-	CDROM_CONFIG_FLAGS (drive)->dvd_ram = 0;
-	CDROM_CONFIG_FLAGS (drive)->no_eject = 1;
-	CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 0;
-	CDROM_CONFIG_FLAGS (drive)->audio_play = 0;
-	CDROM_CONFIG_FLAGS (drive)->close_tray = 1;
+	CDROM_CONFIG_FLAGS(drive)->is_changer = 0;
+	CDROM_CONFIG_FLAGS(drive)->cd_r = 0;
+	CDROM_CONFIG_FLAGS(drive)->cd_rw = 0;
+	CDROM_CONFIG_FLAGS(drive)->test_write = 0;
+	CDROM_CONFIG_FLAGS(drive)->dvd = 0;
+	CDROM_CONFIG_FLAGS(drive)->dvd_r = 0;
+	CDROM_CONFIG_FLAGS(drive)->dvd_ram = 0;
+	CDROM_CONFIG_FLAGS(drive)->no_eject = 1;
+	CDROM_CONFIG_FLAGS(drive)->supp_disc_present = 0;
+	CDROM_CONFIG_FLAGS(drive)->audio_play = 0;
+	CDROM_CONFIG_FLAGS(drive)->close_tray = 1;
 	
 	/* limit transfer size per interrupt. */
-	CDROM_CONFIG_FLAGS (drive)->limit_nframes = 0;
+	CDROM_CONFIG_FLAGS(drive)->limit_nframes = 0;
 	if (drive->id != NULL) {
 		/* a testament to the nice quality of Samsung drives... */
 		if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2430"))
-			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
+			CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
 		else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2432"))
-			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
+			CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
 		/* the 3231 model does not support the SET_CD_SPEED command */
 		else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-3231"))
 			cdi->mask |= CDC_SELECT_SPEED;
@@ -2787,11 +2938,11 @@
            ATAPI Rev 2.2+ standard support for CD changers is used */
 	cdi->sanyo_slot = 0;
 
-	CDROM_CONFIG_FLAGS (drive)->nec260 = 0;
-	CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd = 0;
-	CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd = 0;
-	CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 0;
-	CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 0;
+	CDROM_CONFIG_FLAGS(drive)->nec260 = 0;
+	CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 0;
+	CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 0;
+	CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 0;
+	CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 0;
 
 	if (drive->id != NULL) {
 		if (strcmp (drive->id->model, "V003S0DS") == 0 &&
@@ -2799,36 +2950,36 @@
 		    drive->id->fw_rev[6] <= '2') {
 			/* Vertos 300.
 			   Some versions of this drive like to talk BCD. */
-			CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
 		}
 
 		else if (strcmp (drive->id->model, "V006E0DS") == 0 &&
 		    drive->id->fw_rev[4] == '1' &&
 		    drive->id->fw_rev[6] <= '2') {
 			/* Vertos 600 ESD. */
-			CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 1;
 		}
 
-		else if (strcmp (drive->id->model,
+		else if (strcmp(drive->id->model,
 				 "NEC CD-ROM DRIVE:260") == 0 &&
-			 strncmp (drive->id->fw_rev, "1.01", 4) == 0) { /* FIXME */
+			 strncmp(drive->id->fw_rev, "1.01", 4) == 0) { /* FIXME */
 			/* Old NEC260 (not R).
 			   This drive was released before the 1.2 version
 			   of the spec. */
-			CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->nec260         = 1;
+			CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->nec260         = 1;
 		}
 
-		else if (strcmp (drive->id->model, "WEARNES CDD-120") == 0 &&
-			 strncmp (drive->id->fw_rev, "A1.1", 4) == 0) { /* FIXME */
+		else if (strcmp(drive->id->model, "WEARNES CDD-120") == 0 &&
+			 strncmp(drive->id->fw_rev, "A1.1", 4) == 0) { /* FIXME */
 			/* Wearnes */
-			CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
 		}
 
                 /* Sanyo 3 CD changer uses a non-standard command
@@ -2857,7 +3008,16 @@
 	if (CDROM_CONFIG_FLAGS(drive)->dvd_ram)
 		set_device_ro(MKDEV(HWIF(drive)->major, minor), 0);
 
-	if (ide_cdrom_register (drive, nslots)) {
+#if 0
+	drive->dsc_overlap = (HWIF(drive)->no_dsc) ? 0 : 1;
+	if (HWIF(drive)->no_dsc) {
+		printk(KERN_INFO "ide-cd: %s: disabling DSC overlap\n",
+			drive->name);
+		drive->dsc_overlap = 0;
+	}
+#endif
+
+	if (ide_cdrom_register(drive, nslots)) {
 		printk ("%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name);
 		info->devinfo.handle = NULL;
 		return 1;
@@ -2872,7 +3032,7 @@
 		     struct inode *inode, struct file *file,
 		     unsigned int cmd, unsigned long arg)
 {
-	return cdrom_ioctl (inode, file, cmd, arg);
+	return cdrom_ioctl(inode, file, cmd, arg);
 }
 
 static
@@ -2902,7 +3062,7 @@
 static
 int ide_cdrom_check_media_change (ide_drive_t *drive)
 {
-	return cdrom_media_changed(MKDEV (HWIF (drive)->major,
+	return cdrom_media_changed(MKDEV (HWIF(drive)->major,
 			(drive->select.b.unit) << PARTN_BITS));
 }
 
@@ -2950,35 +3110,47 @@
 	struct cdrom_info *info = drive->driver_data;
 	struct cdrom_device_info *devinfo = &info->devinfo;
 
-	if (ide_unregister_subdriver (drive))
+	if (ide_unregister_subdriver(drive)) {
+		printk("%s: %s: failed to ide_unregister_subdriver\n",
+			__FUNCTION__, drive->name);
 		return 1;
+	}
 	if (info->buffer != NULL)
 		kfree(info->buffer);
 	if (info->toc != NULL)
 		kfree(info->toc);
 	if (info->changer_info != NULL)
 		kfree(info->changer_info);
-	if (devinfo->handle == drive && unregister_cdrom (devinfo))
-		printk ("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name);
+	if (devinfo->handle == drive && unregister_cdrom(devinfo))
+		printk("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name);
 	kfree(info);
 	drive->driver_data = NULL;
 	return 0;
 }
 
-int ide_cdrom_reinit (ide_drive_t *drive);
+int ide_cdrom_init(void);
+int ide_cdrom_attach (ide_drive_t *drive);
 
 static ide_driver_t ide_cdrom_driver = {
 	name:			"ide-cdrom",
 	version:		IDECD_VERSION,
 	media:			ide_cdrom,
 	busy:			0,
+#ifdef CONFIG_IDEDMA_ONLYDISK
+	supports_dma:		0,
+#else
 	supports_dma:		1,
+#endif
 	supports_dsc_overlap:	1,
 	cleanup:		ide_cdrom_cleanup,
 	standby:		NULL,
+	suspend:		NULL,
+	resume:			NULL,
 	flushcache:		NULL,
 	do_request:		ide_do_rw_cdrom,
-	end_request:		NULL,
+	end_request:		ide_cdrom_end_request,
+	sense:			ide_cdrom_dump_status,
+	error:			ide_cdrom_error,
 	ioctl:			ide_cdrom_ioctl,
 	open:			ide_cdrom_open,
 	release:		ide_cdrom_release,
@@ -2988,12 +3160,12 @@
 	capacity:		ide_cdrom_capacity,
 	special:		NULL,
 	proc:			NULL,
-	reinit:			ide_cdrom_reinit,
+	init:			ide_cdrom_init,
+	attach:			ide_cdrom_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 };
 
-int ide_cdrom_init(void);
 static ide_module_t ide_cdrom_module = {
 	IDE_DRIVER_MODULE,
 	ide_cdrom_init,
@@ -3007,35 +3179,46 @@
 MODULE_PARM(ignore, "s");
 MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
 
-int ide_cdrom_reinit (ide_drive_t *drive)
+int ide_cdrom_attach (ide_drive_t *drive)
 {
 	struct cdrom_info *info;
 	int failed = 0;
 
+	if (drive->scsi) {
+		printk("ide-cd: passing drive %s to ide-scsi emulation.\n",
+			drive->name);
+		return 1;
+	}
+
 	MOD_INC_USE_COUNT;
 	info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL);
 	if (info == NULL) {
-		printk ("%s: Can't allocate a cdrom structure\n", drive->name);
+		printk("%s: Can't allocate a cdrom structure\n", drive->name);
+		MOD_DEC_USE_COUNT;
 		return 1;
 	}
-	if (ide_register_subdriver (drive, &ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) {
-		printk ("%s: Failed to register the driver with ide.c\n", drive->name);
-		kfree (info);
+	if (ide_register_subdriver(drive,
+			&ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) {
+		printk(KERN_ERR "ide-cd: %s: Failed to register the driver "
+			"with ide.c\n", drive->name);
+		kfree(info);
+		MOD_DEC_USE_COUNT;
 		return 1;
 	}
-	memset (info, 0, sizeof (struct cdrom_info));
+	memset(info, 0, sizeof(struct cdrom_info));
 	drive->driver_data = info;
 	DRIVER(drive)->busy++;
-	if (ide_cdrom_setup (drive)) {
+	if (ide_cdrom_setup(drive)) {
 		DRIVER(drive)->busy--;
-		if (ide_cdrom_cleanup (drive))
-			printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
+		if (ide_cdrom_cleanup(drive))
+			printk("%s: ide_cdrom_cleanup failed in "
+				"ide_cdrom_init\n", drive->name);
+		MOD_DEC_USE_COUNT;
 		return 1;
 	}
 	DRIVER(drive)->busy--;
 	failed--;
 
-	ide_register_module(&ide_cdrom_module);
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
@@ -3045,41 +3228,51 @@
 	ide_drive_t *drive;
 	int failed = 0;
 
-	while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, &ide_cdrom_driver, failed)) != NULL)
-		if (ide_cdrom_cleanup (drive)) {
-			printk ("%s: cleanup_module() called while still busy\n", drive->name);
+	while ((drive = ide_scan_devices(ide_cdrom, ide_cdrom_driver.name,
+			&ide_cdrom_driver, failed)) != NULL)
+		if (ide_cdrom_cleanup(drive)) {
+			printk("%s: cleanup_module() called while still "
+				"busy\n", drive->name);
 			failed++;
 		}
-	ide_unregister_module (&ide_cdrom_module);
+	ide_unregister_module(&ide_cdrom_module);
 }
- 
+
 int ide_cdrom_init(void)
 {
+#ifdef CLASSIC_BUILTINS_METHOD
 	ide_drive_t *drive;
 	struct cdrom_info *info;
 	int failed = 0;
-
+#endif /* CLASSIC_BUILTINS_METHOD */
 	MOD_INC_USE_COUNT;
-	while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, NULL, failed++)) != NULL) {
+#ifdef CLASSIC_BUILTINS_METHOD
+	while ((drive = ide_scan_devices(ide_cdrom,
+			ide_cdrom_driver.name, NULL, failed++)) != NULL) {
 		/* skip drives that we were told to ignore */
 		if (ignore != NULL) {
 			if (strstr(ignore, drive->name)) {
-				printk("ide-cd: ignoring drive %s\n", drive->name);
+				printk("ide-cd: ignoring drive %s\n",
+					drive->name);
 				continue;
 			}
 		}
 		if (drive->scsi) {
-			printk("ide-cd: passing drive %s to ide-scsi emulation.\n", drive->name);
+			printk("ide-cd: passing drive %s to ide-scsi "
+				"emulation.\n", drive->name);
 			continue;
 		}
 		info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL);
 		if (info == NULL) {
-			printk ("%s: Can't allocate a cdrom structure\n", drive->name);
+			printk ("%s: Can't allocate a cdrom structure\n",
+				drive->name);
 			continue;
 		}
-		if (ide_register_subdriver (drive, &ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) {
-			printk ("%s: Failed to register the driver with ide.c\n", drive->name);
-			kfree (info);
+		if (ide_register_subdriver(drive, 
+				&ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) {
+			printk("%s: Failed to register the driver with "
+				"ide.c\n", drive->name);
+			kfree(info);
 			continue;
 		}
 		memset (info, 0, sizeof (struct cdrom_info));
@@ -3088,12 +3281,14 @@
 		if (ide_cdrom_setup (drive)) {
 			DRIVER(drive)->busy--;
 			if (ide_cdrom_cleanup (drive))
-				printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
+				printk ("%s: ide_cdrom_cleanup failed in "
+					"ide_cdrom_init\n", drive->name);
 			continue;
 		}
 		DRIVER(drive)->busy--;
 		failed--;
 	}
+#endif /* CLASSIC_BUILTINS_METHOD */
 	ide_register_module(&ide_cdrom_module);
 	MOD_DEC_USE_COUNT;
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-cd.h linux-2.4.21/drivers/ide/ide-cd.h
--- linux-2.4.20/drivers/ide/ide-cd.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-cd.h	2002-12-18 18:58:11.000000000 +0000
@@ -437,7 +437,7 @@
 
 	byte     curlba[3];
 	byte     nslots;
-	__u8 short slot_tablelen;
+	__u16	slot_tablelen;
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-cs.c linux-2.4.21/drivers/ide/ide-cs.c
--- linux-2.4.20/drivers/ide/ide-cs.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-cs.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,492 +0,0 @@
-/*======================================================================
-
-    A driver for PCMCIA IDE/ATA disk cards
-
-    ide_cs.c 1.26 1999/11/16 02:10:49
-
-    The contents of this file are subject to the Mozilla Public
-    License Version 1.1 (the "License"); you may not use this file
-    except in compliance with the License. You may obtain a copy of
-    the License at http://www.mozilla.org/MPL/
-
-    Software distributed under the License is distributed on an "AS
-    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-    implied. See the License for the specific language governing
-    rights and limitations under the License.
-
-    The initial developer of the original code is David A. Hinds
-    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
-    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
-
-    Alternatively, the contents of this file may be used under the
-    terms of the GNU General Public License version 2 (the "GPL"), in which
-    case the provisions of the GPL are applicable instead of the
-    above.  If you wish to allow the use of your version of this file
-    only under the terms of the GPL and not to allow others to use
-    your version of this file under the MPL, indicate your decision
-    by deleting the provisions above and replace them with the notice
-    and other provisions required by the GPL.  If you do not delete
-    the provisions above, a recipient may use your version of this
-    file under either the MPL or the GPL.
-    
-======================================================================*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <linux/hdreg.h>
-#include <linux/major.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/system.h>
-
-#include <pcmcia/version.h>
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/cisreg.h>
-
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"ide_cs.c 1.26 1999/11/16 02:10:49 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
-
-/*====================================================================*/
-
-/* Parameters that can be set with 'insmod' */
-
-/* Bit map of interrupts to choose from */
-static u_int irq_mask = 0xdeb8;
-static int irq_list[4] = { -1 };
-
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM(irq_list, "1-4i");
-
-MODULE_LICENSE("GPL");
-
-
-/*====================================================================*/
-
-static const char ide_major[] = {
-    IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
-#ifdef IDE4_MAJOR
-    IDE4_MAJOR, IDE5_MAJOR
-#endif
-};
-
-typedef struct ide_info_t {
-    dev_link_t	link;
-    int		ndev;
-    dev_node_t	node;
-    int		hd;
-} ide_info_t;
-
-static void ide_config(dev_link_t *link);
-static void ide_release(u_long arg);
-static int ide_event(event_t event, int priority,
-		     event_callback_args_t *args);
-
-static dev_info_t dev_info = "ide-cs";
-
-static dev_link_t *ide_attach(void);
-static void ide_detach(dev_link_t *);
-
-static dev_link_t *dev_list = NULL;
-
-/*====================================================================*/
-
-static void cs_error(client_handle_t handle, int func, int ret)
-{
-    error_info_t err = { func, ret };
-    CardServices(ReportError, handle, &err);
-}
-
-/*======================================================================
-
-    ide_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-======================================================================*/
-
-static dev_link_t *ide_attach(void)
-{
-    ide_info_t *info;
-    dev_link_t *link;
-    client_reg_t client_reg;
-    int i, ret;
-    
-    DEBUG(0, "ide_attach()\n");
-
-    /* Create new ide device */
-    info = kmalloc(sizeof(*info), GFP_KERNEL);
-    if (!info) return NULL;
-    memset(info, 0, sizeof(*info));
-    link = &info->link; link->priv = info;
-
-    link->release.function = &ide_release;
-    link->release.data = (u_long)link;
-    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
-    link->io.IOAddrLines = 3;
-    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
-    if (irq_list[0] == -1)
-	link->irq.IRQInfo2 = irq_mask;
-    else
-	for (i = 0; i < 4; i++)
-	    link->irq.IRQInfo2 |= 1 << irq_list[i];
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-    
-    /* Register with Card Services */
-    link->next = dev_list;
-    dev_list = link;
-    client_reg.dev_info = &dev_info;
-    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-    client_reg.EventMask =
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &ide_event;
-    client_reg.Version = 0x0210;
-    client_reg.event_callback_args.client_data = link;
-    ret = CardServices(RegisterClient, &link->handle, &client_reg);
-    if (ret != CS_SUCCESS) {
-	cs_error(link->handle, RegisterClient, ret);
-	ide_detach(link);
-	return NULL;
-    }
-    
-    return link;
-} /* ide_attach */
-
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
-static void ide_detach(dev_link_t *link)
-{
-    dev_link_t **linkp;
-    int ret;
-
-    DEBUG(0, "ide_detach(0x%p)\n", link);
-    
-    /* Locate device structure */
-    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-	if (*linkp == link) break;
-    if (*linkp == NULL)
-	return;
-
-    del_timer(&link->release);
-    if (link->state & DEV_CONFIG)
-	ide_release((u_long)link);
-    
-    if (link->handle) {
-	ret = CardServices(DeregisterClient, link->handle);
-	if (ret != CS_SUCCESS)
-	    cs_error(link->handle, DeregisterClient, ret);
-    }
-    
-    /* Unlink, free device structure */
-    *linkp = link->next;
-    kfree(link->priv);
-    
-} /* ide_detach */
-
-/*======================================================================
-
-    ide_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    ide device available to the system.
-
-======================================================================*/
-
-#define CS_CHECK(fn, args...) \
-while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
-
-#define CFG_CHECK(fn, args...) \
-if (CardServices(fn, args) != 0) goto next_entry
-
-int idecs_register (int arg1, int arg2, int irq)
-{
-        hw_regs_t hw;
-        ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
-        hw.irq = irq;
-        hw.chipset = ide_pci; /* this enables IRQ sharing w/ PCI irqs */
-        return ide_register_hw(&hw, NULL);
-}
-
-void ide_config(dev_link_t *link)
-{
-    client_handle_t handle = link->handle;
-    ide_info_t *info = link->priv;
-    tuple_t tuple;
-    u_short buf[128];
-    cisparse_t parse;
-    config_info_t conf;
-    cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
-    cistpl_cftable_entry_t dflt = { 0 };
-    int i, pass, last_ret, last_fn, hd=-1, io_base, ctl_base;
-
-    DEBUG(0, "ide_config(0x%p)\n", link);
-    
-    tuple.TupleData = (cisdata_t *)buf;
-    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
-    tuple.Attributes = 0;
-    tuple.DesiredTuple = CISTPL_CONFIG;
-    CS_CHECK(GetFirstTuple, handle, &tuple);
-    CS_CHECK(GetTupleData, handle, &tuple);
-    CS_CHECK(ParseTuple, handle, &tuple, &parse);
-    link->conf.ConfigBase = parse.config.base;
-    link->conf.Present = parse.config.rmask[0];
-    
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-
-    /* Not sure if this is right... look up the current Vcc */
-    CS_CHECK(GetConfigurationInfo, handle, &conf);
-    link->conf.Vcc = conf.Vcc;
-    
-    pass = io_base = ctl_base = 0;
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    tuple.Attributes = 0;
-    CS_CHECK(GetFirstTuple, handle, &tuple);
-    while (1) {
-	CFG_CHECK(GetTupleData, handle, &tuple);
-	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
-
-	/* Check for matching Vcc, unless we're desperate */
-	if (!pass) {
-	    if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
-		if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
-		    goto next_entry;
-	    } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
-		if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000)
-		    goto next_entry;
-	    }
-	}
-	
-	if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-	    link->conf.Vpp1 = link->conf.Vpp2 =
-		cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
-	else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
-	    link->conf.Vpp1 = link->conf.Vpp2 =
-		dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
-	
-	if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-	    cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-	    link->conf.ConfigIndex = cfg->index;
-	    link->io.BasePort1 = io->win[0].base;
-	    link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-	    if (!(io->flags & CISTPL_IO_16BIT))
-		link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-	    if (io->nwin == 2) {
-		link->io.NumPorts1 = 8;
-		link->io.BasePort2 = io->win[1].base;
-		link->io.NumPorts2 = 1;
-		CFG_CHECK(RequestIO, link->handle, &link->io);
-		io_base = link->io.BasePort1;
-		ctl_base = link->io.BasePort2;
-	    } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
-		link->io.NumPorts1 = io->win[0].len;
-		link->io.NumPorts2 = 0;
-		CFG_CHECK(RequestIO, link->handle, &link->io);
-		io_base = link->io.BasePort1;
-		ctl_base = link->io.BasePort1+0x0e;
-	    } else goto next_entry;
-	    /* If we've got this far, we're done */
-	    break;
-	}
-	
-    next_entry:
-	if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
-	if (pass) {
-	    CS_CHECK(GetNextTuple, handle, &tuple);
-	} else if (CardServices(GetNextTuple, handle, &tuple) != 0) {
-	    CS_CHECK(GetFirstTuple, handle, &tuple);
-	    memset(&dflt, 0, sizeof(dflt));
-	    pass++;
-	}
-    }
-    
-    CS_CHECK(RequestIRQ, handle, &link->irq);
-    CS_CHECK(RequestConfiguration, handle, &link->conf);
-
-    /* deal with brain dead IDE resource management */
-    release_region(link->io.BasePort1, link->io.NumPorts1);
-    if (link->io.NumPorts2)
-	release_region(link->io.BasePort2, link->io.NumPorts2);
-
-    /* retry registration in case device is still spinning up */
-    for (i = 0; i < 10; i++) {
-	if (ctl_base)
-	    outb(0x02, ctl_base); /* Set nIEN = disable device interrupts */
-	hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
-	if (hd >= 0) break;
-	if (link->io.NumPorts1 == 0x20) {
-	    if (ctl_base)
-		outb(0x02, ctl_base+0x10);
-	    hd = idecs_register(io_base+0x10, ctl_base+0x10,
-			      link->irq.AssignedIRQ);
-	    if (hd >= 0) {
-		io_base += 0x10; ctl_base += 0x10;
-		break;
-	    }
-	}
-	__set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ/10);
-    }
-    
-    if (hd < 0) {
-	printk(KERN_NOTICE "ide_cs: ide_register() at 0x%03x & 0x%03x"
-	       ", irq %u failed\n", io_base, ctl_base,
-	       link->irq.AssignedIRQ);
-	goto failed;
-    }
-
-    MOD_INC_USE_COUNT;
-    info->ndev = 1;
-    sprintf(info->node.dev_name, "hd%c", 'a'+(hd*2));
-    info->node.major = ide_major[hd];
-    info->node.minor = 0;
-    info->hd = hd;
-    link->dev = &info->node;
-    printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
-	   info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10,
-	   link->conf.Vpp1/10, link->conf.Vpp1%10);
-
-    link->state &= ~DEV_CONFIG_PENDING;
-    return;
-    
-cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
-failed:
-    ide_release((u_long)link);
-
-} /* ide_config */
-
-/*======================================================================
-
-    After a card is removed, ide_release() will unregister the net
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-    
-======================================================================*/
-
-void ide_release(u_long arg)
-{
-    dev_link_t *link = (dev_link_t *)arg;
-    ide_info_t *info = link->priv;
-    
-    DEBUG(0, "ide_release(0x%p)\n", link);
-
-    if (info->ndev) {
-	ide_unregister(info->hd);
-	MOD_DEC_USE_COUNT;
-    }
-
-    request_region(link->io.BasePort1, link->io.NumPorts1,"ide-cs");
-    if (link->io.NumPorts2)
-	request_region(link->io.BasePort2, link->io.NumPorts2,"ide-cs");
-    
-    info->ndev = 0;
-    link->dev = NULL;
-    
-    CardServices(ReleaseConfiguration, link->handle);
-    CardServices(ReleaseIO, link->handle, &link->io);
-    CardServices(ReleaseIRQ, link->handle, &link->irq);
-    
-    link->state &= ~DEV_CONFIG;
-
-} /* ide_release */
-
-/*======================================================================
-
-    The card status event handler.  Mostly, this schedules other
-    stuff to run after an event is received.  A CARD_REMOVAL event
-    also sets some flags to discourage the ide drivers from
-    talking to the ports.
-    
-======================================================================*/
-
-int ide_event(event_t event, int priority,
-	      event_callback_args_t *args)
-{
-    dev_link_t *link = args->client_data;
-
-    DEBUG(1, "ide_event(0x%06x)\n", event);
-    
-    switch (event) {
-    case CS_EVENT_CARD_REMOVAL:
-	link->state &= ~DEV_PRESENT;
-	if (link->state & DEV_CONFIG)
-	    mod_timer(&link->release, jiffies + HZ/20);
-	break;
-    case CS_EVENT_CARD_INSERTION:
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	ide_config(link);
-	break;
-    case CS_EVENT_PM_SUSPEND:
-	link->state |= DEV_SUSPEND;
-	/* Fall through... */
-    case CS_EVENT_RESET_PHYSICAL:
-	if (link->state & DEV_CONFIG)
-	    CardServices(ReleaseConfiguration, link->handle);
-	break;
-    case CS_EVENT_PM_RESUME:
-	link->state &= ~DEV_SUSPEND;
-	/* Fall through... */
-    case CS_EVENT_CARD_RESET:
-	if (DEV_OK(link))
-	    CardServices(RequestConfiguration, link->handle, &link->conf);
-	break;
-    }
-    return 0;
-} /* ide_event */
-
-/*====================================================================*/
-
-static int __init init_ide_cs(void)
-{
-    servinfo_t serv;
-    DEBUG(0, "%s\n", version);
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	printk(KERN_NOTICE "ide_cs: Card Services release "
-	       "does not match!\n");
-	return -1;
-    }
-    register_pccard_driver(&dev_info, &ide_attach, &ide_detach);
-    return 0;
-}
-
-static void __exit exit_ide_cs(void)
-{
-    DEBUG(0, "ide_cs: unloading\n");
-    unregister_pccard_driver(&dev_info);
-    while (dev_list != NULL)
-	ide_detach(dev_list);
-}
-
-module_init(init_ide_cs);
-module_exit(exit_ide_cs);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-disk.c linux-2.4.21/drivers/ide/ide-disk.c
--- linux-2.4.20/drivers/ide/ide-disk.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-disk.c	2002-12-18 18:58:01.000000000 +0000
@@ -1,5 +1,9 @@
 /*
- *  linux/drivers/ide/ide-disk.c	Version 1.10	June 9, 2000
+ *  linux/drivers/ide/ide-disk.c	Version 1.16	April 7, 2002
+ *
+ *  Copyright (C) 1998-2002  Linux ATA Developemt
+ *				Andre Hedrick <andre@linux-ide.org>
+ *
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
@@ -29,10 +33,14 @@
  * Version 1.10		request queue changes, Ultra DMA 100
  * Version 1.11		added 48-bit lba
  * Version 1.12		adding taskfile io access method
- *			Highmem I/O support, Jens Axboe <axboe@suse.de>
+ * Version 1.13		added standby and flush-cache for notifier
+ * Version 1.14		added acoustic-wcache
+ * Version 1.15		convert all calls to ide_raw_taskfile
+ *				since args will return register content.
+ * Version 1.16		added suspend-resume-checkpower
  */
 
-#define IDEDISK_VERSION	"1.12"
+#define IDEDISK_VERSION	"1.16"
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
@@ -49,6 +57,9 @@
 #include <linux/genhd.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+
+#define _IDE_DISK
+
 #include <linux/ide.h>
 
 #include <asm/byteorder.h>
@@ -56,48 +67,27 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-#ifdef CONFIG_BLK_DEV_PDC4030
-#define IS_PDC4030_DRIVE (HWIF(drive)->chipset == ide_pdc4030)
-#else
-#define IS_PDC4030_DRIVE (0)	/* auto-NULLs out pdc4030 code */
-#endif
-
-#ifdef CONFIG_IDE_TASKFILE_IO
-#  undef __TASKFILE__IO /* define __TASKFILE__IO */
-#else /* CONFIG_IDE_TASKFILE_IO */
-#  undef __TASKFILE__IO
-#endif /* CONFIG_IDE_TASKFILE_IO */
+/* FIXME: soem day we shouldnt need to look in here! */
 
-#ifndef __TASKFILE__IO
-
-static void idedisk_bswap_data (void *buffer, int wcount)
-{
-	u16 *p = buffer;
-
-	while (wcount--) {
-		*p = *p << 8 | *p >> 8; p++;
-		*p = *p << 8 | *p >> 8; p++;
-	}
-}
+#include "legacy/pdc4030.h"
 
-static inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	ide_input_data(drive, buffer, wcount);
-	if (drive->bswap)
-		idedisk_bswap_data(buffer, wcount);
-}
+static int driver_blocked;
 
-static inline void idedisk_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+static inline u32 idedisk_read_24 (ide_drive_t *drive)
 {
-	if (drive->bswap) {
-		idedisk_bswap_data(buffer, wcount);
-		ide_output_data(drive, buffer, wcount);
-		idedisk_bswap_data(buffer, wcount);
-	} else
-		ide_output_data(drive, buffer, wcount);
+#if 0
+	return	(HWIF(drive)->INB(IDE_HCYL_REG)<<16) |
+		(HWIF(drive)->INB(IDE_LCYL_REG)<<8) |
+		 HWIF(drive)->INB(IDE_SECTOR_REG);
+#else
+	u8 hcyl = HWIF(drive)->INB(IDE_HCYL_REG);
+	u8 lcyl = HWIF(drive)->INB(IDE_LCYL_REG);
+	u8 sect = HWIF(drive)->INB(IDE_SECTOR_REG);
+	return (hcyl<<16)|(lcyl<<8)|sect;
+#endif
 }
 
-#endif /* __TASKFILE__IO */
+static int idedisk_end_request(ide_drive_t *drive, int uptodate);
 
 /*
  * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
@@ -127,7 +117,7 @@
 	     || (id->cyls == 4092 && id->cur_cyls == 16383)) &&
 	    id->sectors == 63 &&
 	    (id->heads == 15 || id->heads == 16) &&
-	    id->lba_capacity >= 16383*63*id->heads)
+	    (id->lba_capacity >= 16383*63*id->heads))
 		return 1;
 
 	lba_sects   = id->lba_capacity;
@@ -149,31 +139,32 @@
 	return 0;	/* lba_capacity value may be bad */
 }
 
-#ifndef __TASKFILE__IO
+#ifndef CONFIG_IDE_TASKFILE_IO
 
 /*
  * read_intr() is the handler for disk read/multread interrupts
  */
 static ide_startstop_t read_intr (ide_drive_t *drive)
 {
-	byte stat;
-	int i;
-	unsigned int msect, nsect;
-	unsigned long flags;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u32 i = 0, nsect	= 0, msect = drive->mult_count;
 	struct request *rq;
+	unsigned long flags;
+	u8 stat;
 	char *to;
 
 	/* new way for dealing with premature shared PCI interrupts */
-	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
+	if (!OK_STAT(stat=hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
-			return ide_error(drive, "read_intr", stat);
+			return DRIVER(drive)->error(drive, "read_intr", stat);
 		}
 		/* no data yet, so wait for another interrupt */
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
 		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
 		return ide_started;
 	}
-
-	msect = drive->mult_count;
+	
 read_next:
 	rq = HWGROUP(drive)->rq;
 	if (msect) {
@@ -183,22 +174,31 @@
 	} else
 		nsect = 1;
 	to = ide_map_buffer(rq, &flags);
-	idedisk_input_data(drive, to, nsect * SECTOR_WORDS);
+	taskfile_input_data(drive, to, nsect * SECTOR_WORDS);
+
 #ifdef DEBUG
 	printk("%s:  read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n",
 		drive->name, rq->sector, rq->sector+nsect-1,
 		(unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect);
 #endif
+
 	ide_unmap_buffer(to, &flags);
 	rq->sector += nsect;
 	rq->errors = 0;
 	i = (rq->nr_sectors -= nsect);
 	if (((long)(rq->current_nr_sectors -= nsect)) <= 0)
-		ide_end_request(1, HWGROUP(drive));
+		idedisk_end_request(drive, 1);
+	/*
+	 * Another BH Page walker and DATA INTERGRITY Questioned on ERROR.
+	 * If passed back up on multimode read, BAD DATA could be ACKED
+	 * to FILE SYSTEMS above ...
+	 */
 	if (i > 0) {
 		if (msect)
 			goto read_next;
-		ide_set_handler (drive, &read_intr, WAIT_CMD, NULL);
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
+		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
                 return ide_started;
 	}
         return ide_stopped;
@@ -209,13 +209,16 @@
  */
 static ide_startstop_t write_intr (ide_drive_t *drive)
 {
-	byte stat;
-	int i;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = hwgroup->rq;
-
-	if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
-		printk("%s: write_intr error1: nr_sectors=%ld, stat=0x%02x\n", drive->name, rq->nr_sectors, stat);
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= hwgroup->rq;
+	u32 i = 0;
+	u8 stat;
+
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),
+			DRIVE_READY, drive->bad_wstat)) {
+		printk("%s: write_intr error1: nr_sectors=%ld, stat=0x%02x\n",
+			drive->name, rq->nr_sectors, stat);
         } else {
 #ifdef DEBUG
 		printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n",
@@ -228,20 +231,23 @@
 			i = --rq->nr_sectors;
 			--rq->current_nr_sectors;
 			if (((long)rq->current_nr_sectors) <= 0)
-				ide_end_request(1, hwgroup);
+				idedisk_end_request(drive, 1);
 			if (i > 0) {
 				unsigned long flags;
 				char *to = ide_map_buffer(rq, &flags);
-				idedisk_output_data (drive, to, SECTOR_WORDS);
+				taskfile_output_data(drive, to, SECTOR_WORDS);
 				ide_unmap_buffer(to, &flags);
-				ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
+				if (HWGROUP(drive)->handler != NULL)
+					BUG();
+				ide_set_handler(drive, &write_intr, WAIT_CMD, NULL);
                                 return ide_started;
 			}
                         return ide_stopped;
 		}
-		return ide_stopped;	/* the original code did this here (?) */
+		/* the original code did this here (?) */
+		return ide_stopped;
 	}
-	return ide_error(drive, "write_intr", stat);
+	return DRIVER(drive)->error(drive, "write_intr", stat);
 }
 
 /*
@@ -254,22 +260,27 @@
  * and IRQ context. The IRQ can happen any time after we've output the
  * full "mcount" number of sectors, so we must make sure we update the
  * state _before_ we output the final part of the data!
+ *
+ * The update and return to BH is a BLOCK Layer Fakey to get more data
+ * to satisfy the hardware atomic segment.  If the hardware atomic segment
+ * is shorter or smaller than the BH segment then we should be OKAY.
+ * This is only valid if we can rewind the rq->current_nr_sectors counter.
  */
 int ide_multwrite (ide_drive_t *drive, unsigned int mcount)
 {
- 	ide_hwgroup_t	*hwgroup= HWGROUP(drive);
- 	struct request	*rq = &hwgroup->wrq;
+ 	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+ 	struct request *rq	= &hwgroup->wrq;
  
   	do {
   		char *buffer;
   		int nsect = rq->current_nr_sectors;
 		unsigned long flags;
-
+ 
 		if (nsect > mcount)
 			nsect = mcount;
 		mcount -= nsect;
-
 		buffer = ide_map_buffer(rq, &flags);
+
 		rq->sector += nsect;
 		rq->nr_sectors -= nsect;
 		rq->current_nr_sectors -= nsect;
@@ -285,6 +296,7 @@
 				rq->bh = bh;
 				rq->current_nr_sectors = bh->b_size >> 9;
 				rq->hard_cur_sectors = rq->current_nr_sectors;
+				rq->buffer             = bh->b_data;
 			}
 		}
 
@@ -292,7 +304,7 @@
 		 * Ok, we're all setup for the interrupt
 		 * re-entering us on the last transfer.
 		 */
-		idedisk_output_data(drive, buffer, nsect<<7);
+		taskfile_output_data(drive, buffer, nsect<<7);
 		ide_unmap_buffer(buffer, &flags);
 	} while (mcount);
 
@@ -304,12 +316,14 @@
  */
 static ide_startstop_t multwrite_intr (ide_drive_t *drive)
 {
-	byte stat;
-	int i;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = &hwgroup->wrq;
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= &hwgroup->wrq;
+	u32 i = 0;
+	u8 stat;
 
-	if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
+	if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG),
+			DRIVE_READY, drive->bad_wstat)) {
 		if (stat & DRQ_STAT) {
 			/*
 			 *	The drive wants data. Remember rq is the copy
@@ -318,7 +332,9 @@
 			if (rq->nr_sectors) {
 				if (ide_multwrite(drive, drive->mult_count))
 					return ide_stopped;
-				ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL);
+				if (HWGROUP(drive)->handler != NULL)
+					BUG();
+				ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL);
 				return ide_started;
 			}
 		} else {
@@ -328,24 +344,19 @@
 			 */
 			if (!rq->nr_sectors) {	/* all done? */
 				rq = hwgroup->rq;
-				for (i = rq->nr_sectors; i > 0;){
+				for (i = rq->nr_sectors; i > 0;) {
 					i -= rq->current_nr_sectors;
-					ide_end_request(1, hwgroup);
+					idedisk_end_request(drive, 1);
 				}
 				return ide_stopped;
 			}
 		}
-		return ide_stopped;	/* the original code did this here (?) */
+		/* the original code did this here (?) */
+		return ide_stopped;
 	}
-	return ide_error(drive, "multwrite_intr", stat);
+	return DRIVER(drive)->error(drive, "multwrite_intr", stat);
 }
-#endif /* __TASKFILE__IO */
 
-#ifdef __TASKFILE__IO
-
-static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block);
-static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block);
-static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block);
 
 /*
  * do_rw_disk() issues READ and WRITE commands to a disk,
@@ -354,230 +365,32 @@
  */
 static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	if (rq->cmd == READ)
-		goto good_command;
-	if (rq->cmd == WRITE)
-		goto good_command;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+	ata_nsector_t		nsectors;
 
-	printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);
-	ide_end_request(0, HWGROUP(drive));
-	return ide_stopped;
+	nsectors.all		= (u16) rq->nr_sectors;
 
-good_command:
+	if (driver_blocked)
+		panic("Request while ide driver is blocked?");
 
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (IS_PDC4030_DRIVE) {
-		extern ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
+#if defined(CONFIG_BLK_DEV_PDC4030) || defined(CONFIG_BLK_DEV_PDC4030_MODULE)
+	if (IS_PDC4030_DRIVE)
 		return promise_rw_disk(drive, rq, block);
-	}
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 
-	if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing))	/* 48-bit LBA */
-		return lba_48_rw_disk(drive, rq, (unsigned long long) block);
-	if (drive->select.b.lba)		/* 28-bit LBA */
-		return lba_28_rw_disk(drive, rq, (unsigned long) block);
-
-	/* 28-bit CHS : DIE DIE DIE piece of legacy crap!!! */
-	return chs_rw_disk(drive, rq, (unsigned long) block);
-}
-
-static task_ioreg_t get_command (ide_drive_t *drive, int cmd)
-{
-	int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
-
-#if 1
-	lba48bit = drive->addressing;
-#endif
-
-	if ((cmd == READ) && (drive->using_dma))
-		return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA;
-	else if ((cmd == READ) && (drive->mult_count))
-		return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD;
-	else if (cmd == READ)
-		return (lba48bit) ? WIN_READ_EXT : WIN_READ;
-	else if ((cmd == WRITE) && (drive->using_dma))
-		return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
-	else if ((cmd == WRITE) && (drive->mult_count))
-		return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
-	else if (cmd == WRITE)
-		return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE;
-	else
-		return WIN_NOP;
-}
-
-static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
-{
-	struct hd_drive_task_hdr	taskfile;
-	struct hd_drive_hob_hdr		hobfile;
-	ide_task_t			args;
-
-	task_ioreg_t command	= get_command(drive, rq->cmd);
-	unsigned int track	= (block / drive->sect);
-	unsigned int sect	= (block % drive->sect) + 1;
-	unsigned int head	= (track % drive->head);
-	unsigned int cyl	= (track / drive->head);
-
-	memset(&taskfile, 0, sizeof(task_struct_t));
-	memset(&hobfile, 0, sizeof(hob_struct_t));
-
-	taskfile.sector_count	= (rq->nr_sectors==256)?0x00:rq->nr_sectors;
-	taskfile.sector_number	= sect;
-	taskfile.low_cylinder	= cyl;
-	taskfile.high_cylinder	= (cyl>>8);
-	taskfile.device_head	= head;
-	taskfile.device_head	|= drive->select.all;
-	taskfile.command	= command;
-
-#ifdef DEBUG
-	printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ");
-	if (lba)	printk("LBAsect=%lld, ", block);
-	else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
-	printk("sectors=%ld, ", rq->nr_sectors);
-	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
-#endif
-
-	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
-	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
-	args.command_type	= ide_cmd_type_parser(&args);
-	args.prehandler		= ide_pre_handler_parser(&taskfile, &hobfile);
-	args.handler		= ide_handler_parser(&taskfile, &hobfile);
-	args.posthandler	= NULL;
-	args.rq			= (struct request *) rq;
-	args.block		= block;
-	rq->special		= NULL;
-	rq->special		= (ide_task_t *)&args;
-
-	return do_rw_taskfile(drive, &args);
-}
-
-static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
-{
-	struct hd_drive_task_hdr	taskfile;
-	struct hd_drive_hob_hdr		hobfile;
-	ide_task_t			args;
-
-	task_ioreg_t command	= get_command(drive, rq->cmd);
-
-	memset(&taskfile, 0, sizeof(task_struct_t));
-	memset(&hobfile, 0, sizeof(hob_struct_t));
-
-	taskfile.sector_count	= (rq->nr_sectors==256)?0x00:rq->nr_sectors;
-	taskfile.sector_number	= block;
-	taskfile.low_cylinder	= (block>>=8);
-	taskfile.high_cylinder	= (block>>=8);
-	taskfile.device_head	= ((block>>8)&0x0f);
-	taskfile.device_head	|= drive->select.all;
-	taskfile.command	= command;
-
-
-#ifdef DEBUG
-	printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ");
-	if (lba)	printk("LBAsect=%lld, ", block);
-	else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
-	printk("sectors=%ld, ", rq->nr_sectors);
-	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
-#endif
-
-	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
-	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
-	args.command_type	= ide_cmd_type_parser(&args);
-	args.prehandler		= ide_pre_handler_parser(&taskfile, &hobfile);
-	args.handler		= ide_handler_parser(&taskfile, &hobfile);
-	args.posthandler	= NULL;
-	args.rq			= (struct request *) rq;
-	args.block		= block;
-	rq->special		= NULL;
-	rq->special		= (ide_task_t *)&args;
-
-	return do_rw_taskfile(drive, &args);
-}
-
-/*
- * 268435455  == 137439 MB or 28bit limit
- * 320173056  == 163929 MB or 48bit addressing
- * 1073741822 == 549756 MB or 48bit addressing fake drive
- */
-
-static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block)
-{
-	struct hd_drive_task_hdr	taskfile;
-	struct hd_drive_hob_hdr		hobfile;
-	ide_task_t			args;
-
-	task_ioreg_t command	= get_command(drive, rq->cmd);
-
-	memset(&taskfile, 0, sizeof(task_struct_t));
-	memset(&hobfile, 0, sizeof(hob_struct_t));
-
-	taskfile.sector_count	= rq->nr_sectors;
-	hobfile.sector_count	= (rq->nr_sectors>>8);
-
-	if (rq->nr_sectors == 65536) {
-		taskfile.sector_count	= 0x00;
-		hobfile.sector_count	= 0x00;
-	}
-
-	taskfile.sector_number	= block;	/* low lba */
-	taskfile.low_cylinder	= (block>>=8);	/* mid lba */
-	taskfile.high_cylinder	= (block>>=8);	/* hi  lba */
-	hobfile.sector_number	= (block>>=8);	/* low lba */
-	hobfile.low_cylinder	= (block>>=8);	/* mid lba */
-	hobfile.high_cylinder	= (block>>=8);	/* hi  lba */
-	taskfile.device_head	= drive->select.all;
-	hobfile.device_head	= taskfile.device_head;
-	hobfile.control		= (drive->ctl|0x80);
-	taskfile.command	= command;
-
-#ifdef DEBUG
-	printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ");
-	if (lba)	printk("LBAsect=%lld, ", block);
-	else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
-	printk("sectors=%ld, ", rq->nr_sectors);
-	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
-#endif
-
-	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
-	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
-	args.command_type	= ide_cmd_type_parser(&args);
-	args.prehandler		= ide_pre_handler_parser(&taskfile, &hobfile);
-	args.handler		= ide_handler_parser(&taskfile, &hobfile);
-	args.posthandler	= NULL;
-	args.rq			= (struct request *) rq;
-	args.block		= block;
-	rq->special		= NULL;
-	rq->special		= (ide_task_t *)&args;
-
-	return do_rw_taskfile(drive, &args);
-}
-
-#else /* !__TASKFILE__IO */
-/*
- * do_rw_disk() issues READ and WRITE commands to a disk,
- * using LBA if supported, or CHS otherwise, to address sectors.
- * It also takes care of issuing special DRIVE_CMDs.
- */
-static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
-{
 	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
 
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (drive->select.b.lba || IS_PDC4030_DRIVE) {
-#else /* !CONFIG_BLK_DEV_PDC4030 */
 	if (drive->select.b.lba) {
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-
-		if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
+		if (drive->addressing == 1) {
 			task_ioreg_t tasklets[10];
 
 			tasklets[0] = 0;
 			tasklets[1] = 0;
-			tasklets[2] = rq->nr_sectors;
-			tasklets[3] = (rq->nr_sectors>>8);
-			if (rq->nr_sectors == 65536) {
-				tasklets[2] = 0x00;
-				tasklets[3] = 0x00;
-			}
+			tasklets[2] = nsectors.b.low;
+			tasklets[3] = nsectors.b.high;
 			tasklets[4] = (task_ioreg_t) block;
 			tasklets[5] = (task_ioreg_t) (block>>8);
 			tasklets[6] = (task_ioreg_t) (block>>16);
@@ -587,7 +400,8 @@
 //			tasklets[8] = (task_ioreg_t) (block>>32);
 //			tasklets[9] = (task_ioreg_t) (block>>40);
 #ifdef DEBUG
-			printk("%s: %sing: LBAsect=%lu, sectors=%ld, buffer=0x%08lx, LBAsect=0x%012lx\n",
+			printk("%s: %sing: LBAsect=%lu, sectors=%ld, "
+				"buffer=0x%08lx, LBAsect=0x%012lx\n",
 				drive->name,
 				(rq->cmd==READ)?"read":"writ",
 				block,
@@ -599,87 +413,88 @@
 				tasklets[9], tasklets[8], tasklets[7],
 				tasklets[6], tasklets[5], tasklets[4]);
 #endif
-			OUT_BYTE(tasklets[1], IDE_FEATURE_REG);
-			OUT_BYTE(tasklets[3], IDE_NSECTOR_REG);
-			OUT_BYTE(tasklets[7], IDE_SECTOR_REG);
-			OUT_BYTE(tasklets[8], IDE_LCYL_REG);
-			OUT_BYTE(tasklets[9], IDE_HCYL_REG);
-
-			OUT_BYTE(tasklets[0], IDE_FEATURE_REG);
-			OUT_BYTE(tasklets[2], IDE_NSECTOR_REG);
-			OUT_BYTE(tasklets[4], IDE_SECTOR_REG);
-			OUT_BYTE(tasklets[5], IDE_LCYL_REG);
-			OUT_BYTE(tasklets[6], IDE_HCYL_REG);
-			OUT_BYTE(0x00|drive->select.all,IDE_SELECT_REG);
+			hwif->OUTB(tasklets[1], IDE_FEATURE_REG);
+			hwif->OUTB(tasklets[3], IDE_NSECTOR_REG);
+			hwif->OUTB(tasklets[7], IDE_SECTOR_REG);
+			hwif->OUTB(tasklets[8], IDE_LCYL_REG);
+			hwif->OUTB(tasklets[9], IDE_HCYL_REG);
+
+			hwif->OUTB(tasklets[0], IDE_FEATURE_REG);
+			hwif->OUTB(tasklets[2], IDE_NSECTOR_REG);
+			hwif->OUTB(tasklets[4], IDE_SECTOR_REG);
+			hwif->OUTB(tasklets[5], IDE_LCYL_REG);
+			hwif->OUTB(tasklets[6], IDE_HCYL_REG);
+			hwif->OUTB(0x00|drive->select.all,IDE_SELECT_REG);
 		} else {
 #ifdef DEBUG
-			printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n",
+			printk("%s: %sing: LBAsect=%ld, sectors=%ld, "
+				"buffer=0x%08lx\n",
 				drive->name, (rq->cmd==READ)?"read":"writ",
-				block, rq->nr_sectors, (unsigned long) rq->buffer);
+				block, rq->nr_sectors,
+				(unsigned long) rq->buffer);
 #endif
-			OUT_BYTE(0x00, IDE_FEATURE_REG);
-			OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG);
-			OUT_BYTE(block,IDE_SECTOR_REG);
-			OUT_BYTE(block>>=8,IDE_LCYL_REG);
-			OUT_BYTE(block>>=8,IDE_HCYL_REG);
-			OUT_BYTE(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
+			hwif->OUTB(0x00, IDE_FEATURE_REG);
+			hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
+			hwif->OUTB(block, IDE_SECTOR_REG);
+			hwif->OUTB(block>>=8, IDE_LCYL_REG);
+			hwif->OUTB(block>>=8, IDE_HCYL_REG);
+			hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
 		}
 	} else {
 		unsigned int sect,head,cyl,track;
 		track = block / drive->sect;
 		sect  = block % drive->sect + 1;
-		OUT_BYTE(sect,IDE_SECTOR_REG);
+		hwif->OUTB(sect, IDE_SECTOR_REG);
 		head  = track % drive->head;
 		cyl   = track / drive->head;
 
-		OUT_BYTE(0x00, IDE_FEATURE_REG);
-		OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG);
-		OUT_BYTE(cyl,IDE_LCYL_REG);
-		OUT_BYTE(cyl>>8,IDE_HCYL_REG);
-		OUT_BYTE(head|drive->select.all,IDE_SELECT_REG);
+		hwif->OUTB(0x00, IDE_FEATURE_REG);
+		hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
+		hwif->OUTB(cyl, IDE_LCYL_REG);
+		hwif->OUTB(cyl>>8, IDE_HCYL_REG);
+		hwif->OUTB(head|drive->select.all,IDE_SELECT_REG);
 #ifdef DEBUG
 		printk("%s: %sing: CHS=%d/%d/%d, sectors=%ld, buffer=0x%08lx\n",
 			drive->name, (rq->cmd==READ)?"read":"writ", cyl,
 			head, sect, rq->nr_sectors, (unsigned long) rq->buffer);
 #endif
 	}
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (IS_PDC4030_DRIVE) {
-		extern ide_startstop_t do_pdc4030_io(ide_drive_t *, struct request *);
-		return do_pdc4030_io (drive, rq);
-	}
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-	if (rq->cmd == READ) {
+
+	if (rq_data_dir(rq) == READ) {
 #ifdef CONFIG_BLK_DEV_IDEDMA
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))
+		if (drive->using_dma && !hwif->ide_dma_read(drive))
 			return ide_started;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
 		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
-		if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
-			OUT_BYTE(drive->mult_count ? WIN_MULTREAD_EXT : WIN_READ_EXT, IDE_COMMAND_REG);
-		} else {
-			OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
-		}
+
+		command = ((drive->mult_count) ?
+			   ((lba48) ? WIN_MULTREAD_EXT : WIN_MULTREAD) :
+			   ((lba48) ? WIN_READ_EXT : WIN_READ));
+		hwif->OUTB(command, IDE_COMMAND_REG);
 		return ide_started;
-	}
-	if (rq->cmd == WRITE) {
+	} else if (rq_data_dir(rq) == WRITE) {
 		ide_startstop_t startstop;
 #ifdef CONFIG_BLK_DEV_IDEDMA
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive)))
+		if (drive->using_dma && !(HWIF(drive)->ide_dma_write(drive)))
 			return ide_started;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
-		if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
-			OUT_BYTE(drive->mult_count ? WIN_MULTWRITE_EXT : WIN_WRITE_EXT, IDE_COMMAND_REG);
-		} else {
-			OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
-		}
-		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
-			printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name,
+
+		command = ((drive->mult_count) ?
+			   ((lba48) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE) :
+			   ((lba48) ? WIN_WRITE_EXT : WIN_WRITE));
+		hwif->OUTB(command, IDE_COMMAND_REG);
+
+		if (ide_wait_stat(&startstop, drive, DATA_READY,
+				drive->bad_wstat, WAIT_DRQ)) {
+			printk(KERN_ERR "%s: no DRQ after issuing %s\n",
+				drive->name,
 				drive->mult_count ? "MULTWRITE" : "WRITE");
 			return startstop;
 		}
 		if (!drive->unmask)
-			__cli();	/* local CPU only */
+			local_irq_disable();
 		if (drive->mult_count) {
 			ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	/*
@@ -690,8 +505,12 @@
 	 * before returning.  Fortunately, this NEVER happens (right?).
 	 *
 	 * Except when you get an error it seems...
+	 *
+	 * MAJOR DATA INTEGRITY BUG !!! only if we error 
 	 */
 			hwgroup->wrq = *rq; /* scratchpad */
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
 			ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL);
 			if (ide_multwrite(drive, drive->mult_count)) {
 				unsigned long flags;
@@ -703,36 +522,210 @@
 			}
 		} else {
 			unsigned long flags;
-			char *buffer = ide_map_buffer(rq, &flags);
-			ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
-			idedisk_output_data(drive, buffer, SECTOR_WORDS);
-			ide_unmap_buffer(buffer, &flags);
+			char *to = ide_map_buffer(rq, &flags);
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
+			ide_set_handler(drive, &write_intr, WAIT_CMD, NULL);
+			taskfile_output_data(drive, to, SECTOR_WORDS);
+			ide_unmap_buffer(to, &flags);
 		}
 		return ide_started;
 	}
 	printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);
-	ide_end_request(0, HWGROUP(drive));
+	idedisk_end_request(drive, 0);
 	return ide_stopped;
 }
 
-#endif /* __TASKFILE__IO */
+#else /* CONFIG_IDE_TASKFILE_IO */
+
+static ide_startstop_t chs_rw_disk(ide_drive_t *, struct request *, unsigned long);
+static ide_startstop_t lba_28_rw_disk(ide_drive_t *, struct request *, unsigned long);
+static ide_startstop_t lba_48_rw_disk(ide_drive_t *, struct request *, unsigned long long);
+
+/*
+ * do_rw_disk() issues READ and WRITE commands to a disk,
+ * using LBA if supported, or CHS otherwise, to address sectors.
+ * It also takes care of issuing special DRIVE_CMDs.
+ */
+static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	if (!blk_fs_request(rq)) {
+		printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);
+		idedisk_end_request(drive, 0);
+		return ide_stopped;
+	}
+
+	/*
+	 * 268435455  == 137439 MB or 28bit limit
+	 *
+	 * need to add split taskfile operations based on 28bit threshold.
+	 */
+
+#if defined(CONFIG_BLK_DEV_PDC4030) || defined(CONFIG_BLK_DEV_PDC4030_MODULE)
+        if (IS_PDC4030_DRIVE)
+                return promise_rw_disk(drive, rq, block);
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+
+	if (drive->addressing == 1)		/* 48-bit LBA */
+		return lba_48_rw_disk(drive, rq, (unsigned long long) block);
+	if (drive->select.b.lba)		/* 28-bit LBA */
+		return lba_28_rw_disk(drive, rq, (unsigned long) block);
+
+	/* 28-bit CHS : DIE DIE DIE piece of legacy crap!!! */
+	return chs_rw_disk(drive, rq, (unsigned long) block);
+}
+
+static task_ioreg_t get_command (ide_drive_t *drive, int cmd)
+{
+	int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
+
+#if 1
+	lba48bit = (drive->addressing == 1) ? 1 : 0;
+#endif
+
+	if ((cmd == READ) && (drive->using_dma))
+		return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA;
+	else if ((cmd == READ) && (drive->mult_count))
+		return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD;
+	else if (cmd == READ)
+		return (lba48bit) ? WIN_READ_EXT : WIN_READ;
+	else if ((cmd == WRITE) && (drive->using_dma))
+		return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+	else if ((cmd == WRITE) && (drive->mult_count))
+		return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
+	else if (cmd == WRITE)
+		return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE;
+	else
+		return WIN_NOP;
+}
+
+static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	ide_task_t		args;
+	int			sectors;
+	ata_nsector_t		nsectors;
+	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
+	unsigned int track	= (block / drive->sect);
+	unsigned int sect	= (block % drive->sect) + 1;
+	unsigned int head	= (track % drive->head);
+	unsigned int cyl	= (track / drive->head);
+
+	nsectors.all = (u16) rq->nr_sectors;
+#ifdef DEBUG
+	printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");
+	printk("CHS=%d/%d/%d, ", cyl, head, sect);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
+
+	memset(&args, 0, sizeof(ide_task_t));
+
+	sectors	= (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;
+	args.tfRegister[IDE_SECTOR_OFFSET]	= sect;
+	args.tfRegister[IDE_LCYL_OFFSET]	= cyl;
+	args.tfRegister[IDE_HCYL_OFFSET]	= (cyl>>8);
+	args.tfRegister[IDE_SELECT_OFFSET]	= head;
+	args.tfRegister[IDE_SELECT_OFFSET]	|= drive->select.all;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= command;
+	args.command_type			= ide_cmd_type_parser(&args);
+	args.rq					= (struct request *) rq;
+	rq->special				= (ide_task_t *)&args;
+	return do_rw_taskfile(drive, &args);
+}
+
+static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	ide_task_t		args;
+	int			sectors;
+	ata_nsector_t		nsectors;
+	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
+
+	nsectors.all = (u16) rq->nr_sectors;
+
+#ifdef DEBUG
+	printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");
+	printk("LBAsect=%lld, ", block);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
+
+	memset(&args, 0, sizeof(ide_task_t));
+
+	sectors = (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;
+	args.tfRegister[IDE_SECTOR_OFFSET]	= block;
+	args.tfRegister[IDE_LCYL_OFFSET]	= (block>>=8);
+	args.tfRegister[IDE_HCYL_OFFSET]	= (block>>=8);
+	args.tfRegister[IDE_SELECT_OFFSET]	= ((block>>8)&0x0f);
+	args.tfRegister[IDE_SELECT_OFFSET]	|= drive->select.all;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= command;
+	args.command_type			= ide_cmd_type_parser(&args);
+	args.rq					= (struct request *) rq;
+	rq->special				= (ide_task_t *)&args;
+	return do_rw_taskfile(drive, &args);
+}
+
+/*
+ * 268435455  == 137439 MB or 28bit limit
+ * 320173056  == 163929 MB or 48bit addressing
+ * 1073741822 == 549756 MB or 48bit addressing fake drive
+ */
+
+static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block)
+{
+	ide_task_t		args;
+	int			sectors;
+	ata_nsector_t		nsectors;
+	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
+
+	nsectors.all = (u16) rq->nr_sectors;
+
+#ifdef DEBUG
+	printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");
+	printk("LBAsect=%lld, ", block);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
+
+	memset(&args, 0, sizeof(ide_task_t));
+
+	sectors = (rq->nr_sectors == 65536) ? 0 : rq->nr_sectors;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;
+	args.tfRegister[IDE_SECTOR_OFFSET]	= block;	/* low lba */
+	args.tfRegister[IDE_LCYL_OFFSET]	= (block>>=8);	/* mid lba */
+	args.tfRegister[IDE_HCYL_OFFSET]	= (block>>=8);	/* hi  lba */
+	args.tfRegister[IDE_SELECT_OFFSET]	= drive->select.all;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= command;
+	args.hobRegister[IDE_NSECTOR_OFFSET_HOB]= sectors >> 8;
+	args.hobRegister[IDE_SECTOR_OFFSET_HOB]	= (block>>=8);	/* low lba */
+	args.hobRegister[IDE_LCYL_OFFSET_HOB]	= (block>>=8);	/* mid lba */
+	args.hobRegister[IDE_HCYL_OFFSET_HOB]	= (block>>=8);	/* hi  lba */
+	args.hobRegister[IDE_SELECT_OFFSET_HOB]	= drive->select.all;
+	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
+	args.command_type			= ide_cmd_type_parser(&args);
+	args.rq					= (struct request *) rq;
+	rq->special				= (ide_task_t *)&args;
+	return do_rw_taskfile(drive, &args);
+}
+
+#endif /* CONFIG_IDE_TASKFILE_IO */
 
 static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	MOD_INC_USE_COUNT;
 	if (drive->removable && drive->usage == 1) {
-		struct hd_drive_task_hdr taskfile;
-		struct hd_drive_hob_hdr hobfile;
-		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-		taskfile.command = WIN_DOORLOCK;
+		ide_task_t args;
+		memset(&args, 0, sizeof(ide_task_t));
+		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK;
+		args.command_type = ide_cmd_type_parser(&args);
 		check_disk_change(inode->i_rdev);
 		/*
 		 * Ignore the return code from door_lock,
 		 * since the open() has already succeeded,
 		 * and the door_lock is irrelevant at this point.
 		 */
-		if (drive->doorlocking && ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
+		if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
 			drive->doorlocking = 0;
 	}
 	return 0;
@@ -743,13 +736,12 @@
 static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	if (drive->removable && !drive->usage) {
-		struct hd_drive_task_hdr taskfile;
-		struct hd_drive_hob_hdr hobfile;
-		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-		taskfile.command = WIN_DOORUNLOCK;
+		ide_task_t args;
+		memset(&args, 0, sizeof(ide_task_t));
+		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORUNLOCK;
+		args.command_type = ide_cmd_type_parser(&args);
 		invalidate_bdev(inode->i_bdev, 0);
-		if (drive->doorlocking && ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
+		if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
 			drive->doorlocking = 0;
 	}
 	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
@@ -761,7 +753,8 @@
 
 static int idedisk_media_change (ide_drive_t *drive)
 {
-	return drive->removable;	/* if removable, always assume it was changed */
+	/* if removable, always assume it was changed */
+	return drive->removable;
 }
 
 static void idedisk_revalidate (ide_drive_t *drive)
@@ -771,6 +764,198 @@
 			current_capacity(drive));
 }
 
+static int idedisk_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		add_blkdev_randomness(MAJOR(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return ret;
+}
+
+static u8 idedisk_dump_status (ide_drive_t *drive, const char *msg, u8 stat)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long flags;
+	u8 err = 0;
+
+	local_irq_set(flags);
+	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
+#if FANCY_STATUS_DUMPS
+	printk(" { ");
+	if (stat & BUSY_STAT)
+		printk("Busy ");
+	else {
+		if (stat & READY_STAT)	printk("DriveReady ");
+		if (stat & WRERR_STAT)	printk("DeviceFault ");
+		if (stat & SEEK_STAT)	printk("SeekComplete ");
+		if (stat & DRQ_STAT)	printk("DataRequest ");
+		if (stat & ECC_STAT)	printk("CorrectedError ");
+		if (stat & INDEX_STAT)	printk("Index ");
+		if (stat & ERR_STAT)	printk("Error ");
+	}
+	printk("}");
+#endif	/* FANCY_STATUS_DUMPS */
+	printk("\n");
+	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+		err = hwif->INB(IDE_ERROR_REG);
+		printk("%s: %s: error=0x%02x", drive->name, msg, err);
+#if FANCY_STATUS_DUMPS
+		printk(" { ");
+		if (err & ABRT_ERR)	printk("DriveStatusError ");
+		if (err & ICRC_ERR)
+			printk("Bad%s ", (err & ABRT_ERR) ? "CRC" : "Sector");
+		if (err & ECC_ERR)	printk("UncorrectableError ");
+		if (err & ID_ERR)	printk("SectorIdNotFound ");
+		if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
+		if (err & MARK_ERR)	printk("AddrMarkNotFound ");
+		printk("}");
+		if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR ||
+		    (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+			if (drive->addressing == 1) {
+				__u64 sectors = 0;
+				u32 low = 0, high = 0;
+				low = idedisk_read_24(drive);
+				hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
+				high = idedisk_read_24(drive);
+				sectors = ((__u64)high << 24) | low;
+				printk(", LBAsect=%llu, high=%d, low=%d",
+				       (unsigned long long) sectors,
+				       high, low);
+			} else {
+				u8 cur = hwif->INB(IDE_SELECT_REG);
+				if (cur & 0x40) {	/* using LBA? */
+					printk(", LBAsect=%ld", (unsigned long)
+					 ((cur&0xf)<<24)
+					 |(hwif->INB(IDE_HCYL_REG)<<16)
+					 |(hwif->INB(IDE_LCYL_REG)<<8)
+					 | hwif->INB(IDE_SECTOR_REG));
+				} else {
+					printk(", CHS=%d/%d/%d",
+					 (hwif->INB(IDE_HCYL_REG)<<8) +
+					  hwif->INB(IDE_LCYL_REG),
+					  cur & 0xf,
+					  hwif->INB(IDE_SECTOR_REG));
+				}
+			}
+			if (HWGROUP(drive) && HWGROUP(drive)->rq)
+				printk(", sector=%ld",
+					HWGROUP(drive)->rq->sector);
+		}
+	}
+#endif	/* FANCY_STATUS_DUMPS */
+	printk("\n");
+	local_irq_restore(flags);
+	return err;
+}
+
+ide_startstop_t idedisk_error (ide_drive_t *drive, const char *msg, u8 stat)
+{
+	ide_hwif_t *hwif;
+	struct request *rq;
+	u8 err;
+	int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
+
+	err = idedisk_dump_status(drive, msg, stat);
+
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+
+	hwif = HWIF(drive);
+	/* retry only "normal" I/O: */
+	switch (rq->cmd) {
+		case IDE_DRIVE_CMD:
+		case IDE_DRIVE_TASK:
+		case IDE_DRIVE_TASKFILE:
+			rq->errors = 1;
+			ide_end_drive_cmd(drive, stat, err);
+			return ide_stopped;
+#if 0
+		case IDE_DRIVE_TASKFILE:
+			rq->errors = 1;
+			ide_end_taskfile(drive, stat, err);
+			return ide_stopped;
+#endif
+		default:
+			break;
+	}
+
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
+		/* other bits are useless when BUSY */
+		rq->errors |= ERROR_RESET;
+	} else if (stat & ERR_STAT) {
+		/* err has different meaning on cdrom and tape */
+		if (err == ABRT_ERR) {
+			if (drive->select.b.lba &&
+			    /* some newer drives don't support WIN_SPECIFY */
+			    hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY)
+				return ide_stopped;
+		} else if ((err & BAD_CRC) == BAD_CRC) {
+			/* UDMA crc error, just retry the operation */
+			drive->crc_count++;
+		} else if (err & (BBD_ERR | ECC_ERR)) {
+			/* retries won't help these */
+			rq->errors = ERROR_MAX;
+		} else if (err & TRK0_ERR) {
+			/* help it find track zero */
+			rq->errors |= ERROR_RECAL;
+		}
+	}
+	if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ) {
+		/*
+		 * try_to_flush_leftover_data() is invoked in response to
+		 * a drive unexpectedly having its DRQ_STAT bit set.  As
+		 * an alternative to resetting the drive, this routine
+		 * tries to clear the condition by read a sector's worth
+		 * of data from the drive.  Of course, this may not help
+		 * if the drive is *waiting* for data from *us*.
+		 */
+		while (i > 0) {
+			u32 buffer[16];
+			unsigned int wcount = (i > 16) ? 16 : i;
+			i -= wcount;
+			taskfile_input_data(drive, buffer, wcount);
+		}
+	}
+	if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) {
+		/* force an abort */
+		hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
+	}
+	if (rq->errors >= ERROR_MAX)
+		DRIVER(drive)->end_request(drive, 0);
+	else {
+		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+			++rq->errors;
+			return ide_do_reset(drive);
+		}
+		if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
+			drive->special.b.recalibrate = 1;
+		++rq->errors;
+	}
+	return ide_stopped;
+}
+
 /*
  * Queries for true maximum capacity of the drive.
  * Returns maximum LBA address (> 0) of the drive, 0 if failed.
@@ -780,16 +965,11 @@
 	ide_task_t args;
 	unsigned long addr = 0;
 
-	if (!(drive->id->command_set_1 & 0x0400) &&
-	    !(drive->id->cfs_enable_2 & 0x0100))
-		return addr;
-
 	/* Create IDE/ATA command request structure */
 	memset(&args, 0, sizeof(ide_task_t));
 	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX;
-	args.handler				= task_no_data_intr;
-
+	args.command_type			= ide_cmd_type_parser(&args);
 	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
 
@@ -814,8 +994,7 @@
 
 	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX_EXT;
-	args.handler				= task_no_data_intr;
-
+	args.command_type			= ide_cmd_type_parser(&args);
         /* submit command request */
         ide_raw_taskfile(drive, &args, NULL);
 
@@ -851,7 +1030,7 @@
 	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >> 16) & 0xff);
 	args.tfRegister[IDE_SELECT_OFFSET]	= ((addr_req >> 24) & 0x0f) | 0x40;
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX;
-	args.handler				= task_no_data_intr;
+	args.command_type			= ide_cmd_type_parser(&args);
 	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
 	/* if OK, read new maximum address value */
@@ -883,7 +1062,7 @@
 	args.hobRegister[IDE_HCYL_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
 	args.hobRegister[IDE_SELECT_OFFSET_HOB]	= 0x40;
 	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
-        args.handler				= task_no_data_intr;
+	args.command_type			= ide_cmd_type_parser(&args);
 	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
 	/* if OK, compute maximum address value */
@@ -899,6 +1078,8 @@
 	return addr_set;
 }
 
+#endif /* CONFIG_IDEDISK_STROKE */
+
 /*
  * Tests if the drive supports Host Protected Area feature.
  * Returns true if supported, false otherwise.
@@ -906,12 +1087,11 @@
 static inline int idedisk_supports_host_protected_area(ide_drive_t *drive)
 {
 	int flag = (drive->id->cfs_enable_1 & 0x0400) ? 1 : 0;
-	printk("%s: host protected area => %d\n", drive->name, flag);
+	if (flag)
+		printk("%s: host protected area => %d\n", drive->name, flag);
 	return flag;
 }
 
-#endif /* CONFIG_IDEDISK_STROKE */
-
 /*
  * Compute drive->capacity, the full capacity of the drive
  * Called with drive->id != NULL.
@@ -937,6 +1117,8 @@
 	drive->capacity48 = 0;
 	drive->select.b.lba = 0;
 
+	(void) idedisk_supports_host_protected_area(drive);
+
 	if (id->cfs_enable_2 & 0x0400) {
 		capacity_2 = id->lba_capacity_2;
 		drive->head		= drive->bios_head = 255;
@@ -955,10 +1137,11 @@
 				drive->id->lba_capacity_2 = capacity_2;
                         }
 #else /* !CONFIG_IDEDISK_STROKE */
-			printk("%s: setmax_ext LBA %llu, native  %llu\n",
+			printk(KERN_INFO "%s: setmax_ext LBA %llu, native  %llu\n",
 				drive->name, set_max_ext, capacity_2);
 #endif /* CONFIG_IDEDISK_STROKE */
 		}
+		drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect);
 		drive->bios_cyl		= drive->cyl;
 		drive->capacity48	= capacity_2;
 		drive->capacity		= (unsigned long) capacity_2;
@@ -981,7 +1164,7 @@
 			drive->id->lba_capacity = capacity;
 		}
 #else /* !CONFIG_IDEDISK_STROKE */
-		printk("%s: setmax LBA %lu, native  %lu\n",
+		printk(KERN_INFO "%s: setmax LBA %lu, native  %lu\n",
 			drive->name, set_max, capacity);
 #endif /* CONFIG_IDEDISK_STROKE */
 	}
@@ -989,7 +1172,7 @@
 	drive->capacity = capacity;
 
 	if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
-                drive->capacity48 = id->lba_capacity_2;
+		drive->capacity48 = id->lba_capacity_2;
 		drive->head = 255;
 		drive->sect = 63;
 		drive->cyl = (unsigned long)(drive->capacity48) / (drive->head * drive->sect);
@@ -1008,47 +1191,40 @@
 	special_t *s = &drive->special;
 
 	if (s->b.set_geometry) {
-		struct hd_drive_task_hdr taskfile;
-		struct hd_drive_hob_hdr hobfile;
-		ide_handler_t *handler = NULL;
-
-		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-
 		s->b.set_geometry	= 0;
-		taskfile.sector_number	= drive->sect;
-		taskfile.low_cylinder	= drive->cyl;
-		taskfile.high_cylinder	= drive->cyl>>8;
-		taskfile.device_head	= ((drive->head-1)|drive->select.all)&0xBF;
 		if (!IS_PDC4030_DRIVE) {
-			taskfile.sector_count	= drive->sect;
-			taskfile.command	= WIN_SPECIFY;
-			handler			= ide_handler_parser(&taskfile, &hobfile);
+			ide_task_t args;
+			memset(&args, 0, sizeof(ide_task_t));
+			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
+			args.tfRegister[IDE_SECTOR_OFFSET]  = drive->sect;
+			args.tfRegister[IDE_LCYL_OFFSET]    = drive->cyl;
+			args.tfRegister[IDE_HCYL_OFFSET]    = drive->cyl>>8;
+			args.tfRegister[IDE_SELECT_OFFSET]  = ((drive->head-1)|drive->select.all)&0xBF;
+			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY;
+			args.command_type = ide_cmd_type_parser(&args);
+			do_rw_taskfile(drive, &args);
 		}
-		do_taskfile(drive, &taskfile, &hobfile, handler);
 	} else if (s->b.recalibrate) {
 		s->b.recalibrate = 0;
 		if (!IS_PDC4030_DRIVE) {
-			struct hd_drive_task_hdr taskfile;
-			struct hd_drive_hob_hdr hobfile;
-			memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-			memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-			taskfile.sector_count	= drive->sect;
-			taskfile.command	= WIN_RESTORE;
-			do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile));
+			ide_task_t args;
+			memset(&args, 0, sizeof(ide_task_t));
+			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
+			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE;
+			args.command_type = ide_cmd_type_parser(&args);
+			do_rw_taskfile(drive, &args);
 		}
 	} else if (s->b.set_multmode) {
 		s->b.set_multmode = 0;
 		if (drive->id && drive->mult_req > drive->id->max_multsect)
 			drive->mult_req = drive->id->max_multsect;
 		if (!IS_PDC4030_DRIVE) {
-			struct hd_drive_task_hdr taskfile;
-			struct hd_drive_hob_hdr hobfile;
-			memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-			memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-			taskfile.sector_count	= drive->mult_req;
-			taskfile.command	= WIN_SETMULT;
-			do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile));
+			ide_task_t args;
+			memset(&args, 0, sizeof(ide_task_t));
+			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req;
+			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT;
+			args.command_type = ide_cmd_type_parser(&args);
+			do_rw_taskfile(drive, &args);
 		}
 	} else if (s->all) {
 		int special = s->all;
@@ -1078,45 +1254,44 @@
 
 static int smart_enable(ide_drive_t *drive)
 {
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	taskfile.feature	= SMART_ENABLE;
-	taskfile.low_cylinder	= SMART_LCYL_PASS;
-	taskfile.high_cylinder	= SMART_HCYL_PASS;
-	taskfile.command	= WIN_SMART;
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
-}
-
-static int get_smart_values(ide_drive_t *drive, byte *buf)
-{
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	taskfile.feature	= SMART_READ_VALUES;
-	taskfile.sector_count	= 0x01;
-	taskfile.low_cylinder	= SMART_LCYL_PASS;
-	taskfile.high_cylinder	= SMART_HCYL_PASS;
-	taskfile.command	= WIN_SMART;
+	ide_task_t args;
+
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_ENABLE;
+	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
+	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
+	args.command_type			= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, NULL);
+}
+
+static int get_smart_values(ide_drive_t *drive, u8 *buf)
+{
+	ide_task_t args;
+
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_READ_VALUES;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
+	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
+	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
+	args.command_type			= ide_cmd_type_parser(&args);
 	(void) smart_enable(drive);
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
+	return ide_raw_taskfile(drive, &args, buf);
 }
 
-static int get_smart_thresholds(ide_drive_t *drive, byte *buf)
+static int get_smart_thresholds(ide_drive_t *drive, u8 *buf)
 {
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	taskfile.feature	= SMART_READ_THRESHOLDS;
-	taskfile.sector_count	= 0x01;
-	taskfile.low_cylinder	= SMART_LCYL_PASS;
-	taskfile.high_cylinder	= SMART_HCYL_PASS;
-	taskfile.command	= WIN_SMART;
+	ide_task_t args;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_READ_THRESHOLDS;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
+	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
+	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
+	args.command_type			= ide_cmd_type_parser(&args);
 	(void) smart_enable(drive);
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
+	return ide_raw_taskfile(drive, &args, buf);
 }
 
 static int proc_idedisk_read_cache
@@ -1185,23 +1360,12 @@
 
 #endif	/* CONFIG_PROC_FS */
 
+/*
+ * This is tightly woven into the driver->do_special can not touch.
+ * DON'T do it again until a total personality rewrite is committed.
+ */
 static int set_multcount(ide_drive_t *drive, int arg)
 {
-#ifdef __TASKFILE__IO
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-
-	if (drive->special.b.set_multmode)
-		return -EBUSY;
-
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	taskfile.sector_count	= drive->mult_req;
-	taskfile.command	= WIN_SETMULT;
-	drive->mult_req		= arg;
-	drive->special.b.set_multmode = 1;
-	ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
-#else /* !__TASKFILE__IO */
 	struct request rq;
 
 	if (drive->special.b.set_multmode)
@@ -1211,7 +1375,6 @@
 	drive->mult_req = arg;
 	drive->special.b.set_multmode = 1;
 	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
-#endif /* __TASKFILE__IO */
 	return (drive->mult_count == arg) ? 0 : -EIO;
 }
 
@@ -1227,57 +1390,112 @@
 
 static int write_cache (ide_drive_t *drive, int arg)
 {
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	taskfile.feature	= (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
-	taskfile.command	= WIN_SETFEATURES;
+	ide_task_t args;
 
 	if (!(drive->id->cfs_enable_2 & 0x3000))
 		return 1;
 
-	(void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ?
+			SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;
+	args.command_type			= ide_cmd_type_parser(&args);
+	(void) ide_raw_taskfile(drive, &args, NULL);
+
 	drive->wcache = arg;
 	return 0;
 }
 
+static int call_idedisk_standby (ide_drive_t *drive, int arg)
+{
+	ide_task_t args;
+	u8 standby = (arg) ? WIN_STANDBYNOW2 : WIN_STANDBYNOW1;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_COMMAND_OFFSET]	= standby;
+	args.command_type			= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, NULL);
+}
+
 static int do_idedisk_standby (ide_drive_t *drive)
 {
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	taskfile.command	= WIN_STANDBYNOW1;
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	return call_idedisk_standby(drive, 0);
+}
+
+static int call_idedisk_suspend (ide_drive_t *drive, int arg)
+{
+	ide_task_t args;
+	u8 suspend = (arg) ? WIN_SLEEPNOW2 : WIN_SLEEPNOW1;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_COMMAND_OFFSET]	= suspend;
+	args.command_type			= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, NULL);
+}
+
+static int do_idedisk_suspend (ide_drive_t *drive)
+{
+	if (drive->suspend_reset)
+		return 1;
+
+	return call_idedisk_suspend(drive, 0);
+}
+
+#if 0
+static int call_idedisk_checkpower (ide_drive_t *drive, int arg)
+{
+	ide_task_t args;
+	u8 ckpw = (arg) ? WIN_CHECKPOWERMODE2 : WIN_CHECKPOWERMODE1;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_COMMAND_OFFSET]	= ckpw;
+	args.command_type			= ide_cmd_type_parser(&args);
+	ide_raw_taskfile(drive, &args, NULL);
+#if 0
+if (errno != EIO || args[0] != 0 || args[1] != 0)
+   state = "unknown";
+else
+   state = "sleeping";
+} else {
+   state = (args[2] == 255) ? "active/idle" : "standby";
+#endif
+	return 0;
+}
+
+static int do_idedisk_checkpower (ide_drive_t *drive)
+{
+	return call_idedisk_checkpower(drive, 0);
+}
+#endif
+
+static int do_idedisk_resume (ide_drive_t *drive)
+{
+	if (!drive->suspend_reset)
+		return 1;
+	return 0;
 }
 
 static int do_idedisk_flushcache (ide_drive_t *drive)
 {
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	if (drive->id->cfs_enable_2 & 0x2400) {
-		taskfile.command	= WIN_FLUSH_CACHE_EXT;
-	} else {
-		taskfile.command	= WIN_FLUSH_CACHE;
-	}
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	ide_task_t args;
+
+	memset(&args, 0, sizeof(ide_task_t));
+	if (drive->id->cfs_enable_2 & 0x2400)
+		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE_EXT;
+	else
+		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE;
+	args.command_type	 		= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, NULL);
 }
 
 static int set_acoustic (ide_drive_t *drive, int arg)
 {
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-
-	taskfile.feature	= (arg)?SETFEATURES_EN_AAM:SETFEATURES_DIS_AAM;
-	taskfile.sector_count	= arg;
+	ide_task_t args;
 
-	taskfile.command	= WIN_SETFEATURES;
-	(void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ? SETFEATURES_EN_AAM :
+							  SETFEATURES_DIS_AAM;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= arg;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;
+	args.command_type = ide_cmd_type_parser(&args);
+	ide_raw_taskfile(drive, &args, NULL);
 	drive->acoustic = arg;
 	return 0;
 }
@@ -1286,9 +1504,11 @@
 {
 	drive->addressing =  0;
 
+	if (HWIF(drive)->addressing)
+		return 0;
+
 	if (!(drive->id->cfs_enable_2 & 0x0400))
                 return -EIO;
-
 	drive->addressing = arg;
 	return 0;
 }
@@ -1321,12 +1541,35 @@
  	ide_add_setting(drive,	"max_failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->max_failures,		NULL);
 }
 
+static int idedisk_ioctl (ide_drive_t *drive, struct inode *inode,
+		struct file *file, unsigned int cmd, unsigned long arg)
+{
+#if 0
+HDIO_GET_ADDRESS
+HDIO_SET_ADDRESS
+HDIO_GET_WCACHE
+HDIO_SET_WCACHE
+HDIO_GET_ACOUSTIC
+HDIO_SET_ACOUSTIC
+HDIO_GET_MULTCOUNT
+HDIO_SET_MULTCOUNT
+HDIO_GET_NOWERR
+HDIO_SET_NOWERR
+#endif
+	return -EINVAL;
+}
+
 static void idedisk_setup (ide_drive_t *drive)
 {
 	int i;
 	
 	struct hd_driveid *id = drive->id;
 	unsigned long capacity;
+
+#if 0
+	if (IS_PDC4030_DRIVE)
+		DRIVER(drive)->do_request = promise_rw_disk;
+#endif
 	
 	idedisk_add_settings(drive);
 
@@ -1337,7 +1580,7 @@
 	 * CompactFlash cards and their brethern look just like hard drives
 	 * to us, but they are removable and don't have a doorlock mechanism.
 	 */
-	if (drive->removable && !drive_is_flashcard(drive)) {
+	if (drive->removable && !(drive->is_flash)) {
 		/*
 		 * Removable disks (eg. SYQUEST); ignore 'WD' drives 
 		 */
@@ -1355,6 +1598,14 @@
 		break;
 	}
 
+#if 1
+	(void) probe_lba_addressing(drive, 1);
+#else
+	/* if using 48-bit addressing bump the request size up */
+	if (probe_lba_addressing(drive, 1))
+		blk_queue_max_sectors(&drive->queue, 2048);
+#endif
+
 	/* Extract geometry if we did not already have one for the drive */
 	if (!drive->cyl || !drive->head || !drive->sect) {
 		drive->cyl     = drive->bios_cyl  = id->cyls;
@@ -1402,7 +1653,7 @@
 	       drive->bios_cyl, drive->bios_head, drive->bios_sect);
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (drive->using_dma)
-		(void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+		(void) HWIF(drive)->ide_dma_verbose(drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	printk("\n");
 
@@ -1424,10 +1675,9 @@
 	drive->no_io_32bit = id->dword_io ? 1 : 0;
 	if (drive->id->cfs_enable_2 & 0x3000)
 		write_cache(drive, (id->cfs_enable_2 & 0x3000));
-	(void) probe_lba_addressing(drive, 1);
 }
 
-static int idedisk_cleanup (ide_drive_t *drive)
+static int idedisk_cleanup(ide_drive_t *drive)
 {
 	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
 		if (do_idedisk_flushcache(drive))
@@ -1436,7 +1686,8 @@
 	return ide_unregister_subdriver(drive);
 }
 
-int idedisk_reinit(ide_drive_t *drive);
+int idedisk_init (void);
+int idedisk_attach(ide_drive_t *drive);
 
 /*
  *      IDE subdriver functions, registered with ide.c
@@ -1450,10 +1701,14 @@
 	supports_dsc_overlap:	0,
 	cleanup:		idedisk_cleanup,
 	standby:		do_idedisk_standby,
+	suspend:		do_idedisk_suspend,
+	resume:			do_idedisk_resume,
 	flushcache:		do_idedisk_flushcache,
 	do_request:		do_rw_disk,
-	end_request:		NULL,
-	ioctl:			NULL,
+	end_request:		idedisk_end_request,
+	sense:			idedisk_dump_status,
+	error:			idedisk_error,
+	ioctl:			idedisk_ioctl,
 	open:			idedisk_open,
 	release:		idedisk_release,
 	media_change:		idedisk_media_change,
@@ -1462,12 +1717,12 @@
 	capacity:		idedisk_capacity,
 	special:		idedisk_special,
 	proc:			idedisk_proc,
-	reinit:			idedisk_reinit,
+	init:			idedisk_init,
+	attach:			idedisk_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 };
 
-int idedisk_init (void);
 static ide_module_t idedisk_module = {
 	IDE_DRIVER_MODULE,
 	idedisk_init,
@@ -1477,30 +1732,30 @@
 
 MODULE_DESCRIPTION("ATA DISK Driver");
 
-int idedisk_reinit (ide_drive_t *drive)
+int idedisk_attach (ide_drive_t *drive)
 {
-	int failed = 0;
+	int ret = 0;
 
 	MOD_INC_USE_COUNT;
-
-	if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) {
-		printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
-		return 1;
+	if (ide_register_subdriver(drive,
+			&idedisk_driver, IDE_SUBDRIVER_VERSION)) {
+		printk(KERN_ERR "ide-disk: %s: Failed to register the "
+			"driver with ide.c\n", drive->name);
+		ret= 1;
+		goto bye_game_over;
 	}
 	DRIVER(drive)->busy++;
 	idedisk_setup(drive);
 	if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
-		printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
+		printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
+			drive->name, drive->head);
 		(void) idedisk_cleanup(drive);
-		DRIVER(drive)->busy--;
-		return 1;
+		ret= 1;
 	}
 	DRIVER(drive)->busy--;
-	failed--;
-
-	ide_register_module(&idedisk_module);
+bye_game_over:
 	MOD_DEC_USE_COUNT;
-	return 0;
+	return ret;
 }
 
 static void __exit idedisk_exit (void)
@@ -1508,14 +1763,17 @@
 	ide_drive_t *drive;
 	int failed = 0;
 
-	while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, &idedisk_driver, failed)) != NULL) {
+	while ((drive = ide_scan_devices(ide_disk, idedisk_driver.name,
+			&idedisk_driver, failed)) != NULL) {
 		if (idedisk_cleanup (drive)) {
-			printk (KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name);
+			printk(KERN_ERR "%s: cleanup_module() called while "
+				"still busy\n", drive->name);
 			failed++;
 		}
-		/* We must remove proc entries defined in this module.
-		   Otherwise we oops while accessing these entries */
 #ifdef CONFIG_PROC_FS
+		/* We must remove proc entries defined in this module.
+		 * Otherwise we oops while accessing these entries
+		 */
 		if (drive->proc)
 			ide_remove_proc_entries(drive->proc, idedisk_proc);
 #endif
@@ -1525,19 +1783,28 @@
 
 int idedisk_init (void)
 {
+#ifdef CLASSIC_BUILTINS_METHOD
 	ide_drive_t *drive;
 	int failed = 0;
-	
+#endif /* CLASSIC_BUILTINS_METHOD */
+
 	MOD_INC_USE_COUNT;
-	while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, NULL, failed++)) != NULL) {
-		if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) {
-			printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
+
+#ifdef CLASSIC_BUILTINS_METHOD
+	while ((drive = ide_scan_devices(ide_disk,
+			idedisk_driver.name, NULL, failed++)) != NULL) {
+		if (ide_register_subdriver(drive,
+				&idedisk_driver, IDE_SUBDRIVER_VERSION)) {
+			printk(KERN_ERR "ide-disk: %s: Failed to register "
+				"the driver with ide.c\n", drive->name);
 			continue;
 		}
 		DRIVER(drive)->busy++;
 		idedisk_setup(drive);
-		if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
-			printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
+		if ((!drive->head || drive->head > 16) &&
+		    (!drive->select.b.lba)) {
+			printk(KERN_ERR "%s: INVALID GEOMETRY: %d "
+				"PHYSICAL HEADS?\n", drive->name, drive->head);
 			(void) idedisk_cleanup(drive);
 			DRIVER(drive)->busy--;
 			continue;
@@ -1545,11 +1812,85 @@
 		DRIVER(drive)->busy--;
 		failed--;
 	}
+#endif /* CLASSIC_BUILTINS_METHOD */
+
 	ide_register_module(&idedisk_module);
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
+ide_startstop_t panic_box(ide_drive_t *drive)
+{
+#if 0
+	panic("%s: Attempted to corrupt something: ide operation "
+#else
+	printk(KERN_ERR "%s: Attempted to corrupt something: ide operation "
+#endif
+		"was pending accross suspend/resume.\n", drive->name);
+	return ide_stopped;
+}
+
+int ide_disks_busy(void)
+{
+	int i;
+	for (i=0; i<MAX_HWIFS; i++) {
+		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
+		if (!hwgroup) continue;
+		if ((hwgroup->handler) && (hwgroup->handler != panic_box))
+			return 1;
+	}
+	return 0;
+}
+
+void ide_disk_suspend(void)
+{
+	int i;
+	while (ide_disks_busy()) {
+		printk("*");
+		schedule();
+	}
+	for (i=0; i<MAX_HWIFS; i++) {
+		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
+
+		if (!hwgroup) continue;
+		hwgroup->handler_save = hwgroup->handler;
+		hwgroup->handler = panic_box;
+	}
+	driver_blocked = 1;
+	if (ide_disks_busy())
+		panic("How did you get that request through?!");
+}
+
+/* unsuspend and resume should be equal in the ideal world */
+
+void ide_disk_unsuspend(void)
+{
+	int i;
+	for (i=0; i<MAX_HWIFS; i++) {
+		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
+
+		if (!hwgroup) continue;
+		hwgroup->handler = NULL; /* hwgroup->handler_save; */
+		hwgroup->handler_save = NULL;
+	}
+	driver_blocked = 0;
+}
+
+void ide_disk_resume(void)
+{
+	int i;
+	for (i=0; i<MAX_HWIFS; i++) {
+		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
+
+		if (!hwgroup) continue;
+		if (hwgroup->handler != panic_box)
+			panic("Handler was not set to panic?");
+		hwgroup->handler_save = NULL;
+		hwgroup->handler = NULL;
+	}
+	driver_blocked = 0;
+}
+
 module_init(idedisk_init);
 module_exit(idedisk_exit);
 MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-dma.c linux-2.4.21/drivers/ide/ide-dma.c
--- linux-2.4.20/drivers/ide/ide-dma.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-dma.c	2002-12-18 18:58:04.000000000 +0000
@@ -70,14 +70,13 @@
  *
  * And, yes, Intel Zappa boards really *do* use both PIIX IDE ports.
  *
- * check_drive_lists(ide_drive_t *drive, int good_bad)
- *
  * ATA-66/100 and recovery functions, I forgot the rest......
- * SELECT_READ_WRITE(hwif,drive,func) for active tuning based on IO direction.
  *
  */
 
 #include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/timer.h>
@@ -86,22 +85,12 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 
-/*
- * Long lost data from 2.0.34 that is now in 2.0.39
- *
- * This was used in ./drivers/block/triton.c to do DMA Base address setup
- * when PnP failed.  Oh the things we forget.  I believe this was part
- * of SFF-8038i that has been withdrawn from public access... :-((
- */
-#define DEFAULT_BMIBA	0xe800	/* in case BIOS did not init it */
-#define DEFAULT_BMCRBA	0xcc00	/* VIA's default value */
-#define DEFAULT_BMALIBA	0xd400	/* ALI's default value */
-
-extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
+#define CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
 
 #ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
 
@@ -123,7 +112,6 @@
 
 	{ "WDC AC11000H"	,	"ALL"		},
 	{ "WDC AC22100H"	,	"ALL"		},
-	{ "WDC AC31000H"	,	"ALL"		},
 	{ "WDC AC32500H"	,	"ALL"		},
 	{ "WDC AC33100H"	,	"ALL"		},
 	{ "WDC AC31600H"	,	"ALL"		},
@@ -159,11 +147,20 @@
 
 };
 
-int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
+/**
+ *	in_drive_list	-	look for drive in black/white list
+ *	@id: drive identifier
+ *	@drive_table: list to inspect
+ *
+ *	Look for a drive in the blacklist and the whitelist tables
+ *	Returns 1 if the drive is found in the table.
+ */
+
+static int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
 {
 	for ( ; drive_table->id_model ; drive_table++)
 		if ((!strcmp(drive_table->id_model, id->model)) &&
-		    ((!strstr(drive_table->id_firmware, id->fw_rev)) ||
+		    ((strstr(drive_table->id_firmware, id->fw_rev)) ||
 		     (!strcmp(drive_table->id_firmware, "ALL"))))
 			return 1;
 	return 0;
@@ -203,121 +200,112 @@
 
 #endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
 
-/*
- * 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
- * two or more sectors, we could get by with a limit of 128 entries here for
- * the usual worst case.  Most requests seem to include some contiguous blocks,
- * further reducing the number of table entries required.
- *
- * The driver reverts to PIO mode for individual requests that exceed
- * this limit (possible with 512 byte blocksizes, eg. MSDOS f/s), so handling
- * 100% of all crazy scenarios here is not necessary.
- *
- * As it turns out though, we must allocate a full 4KB page for this,
- * so the two PRD tables (ide0 & ide1) will each get half of that,
- * allowing each to have about 256 entries (8 bytes each) from this.
- */
-#define PRD_BYTES	8
-#define PRD_ENTRIES	(PAGE_SIZE / (2 * PRD_BYTES))
-
-/*
- * dma_intr() is the handler for disk read/write DMA interrupts
+/**
+ *	ide_dma_intr	-	IDE DMA interrupt handler
+ *	@drive: the drive the interrupt is for
+ *
+ *	Handle an interrupt completing a read/write DMA transfer on an 
+ *	IDE device
  */
+ 
 ide_startstop_t ide_dma_intr (ide_drive_t *drive)
 {
+	u8 stat = 0, dma_stat = 0;
 	int i;
-	byte stat, dma_stat;
 
-	dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
-	stat = GET_STAT();			/* get drive status */
+	dma_stat = HWIF(drive)->ide_dma_end(drive);
+	stat = HWIF(drive)->INB(IDE_STATUS_REG);	/* get drive status */
 	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
 		if (!dma_stat) {
 			struct request *rq = HWGROUP(drive)->rq;
-			rq = HWGROUP(drive)->rq;
+	//		rq = HWGROUP(drive)->rq;
 			for (i = rq->nr_sectors; i > 0;) {
 				i -= rq->current_nr_sectors;
-				ide_end_request(1, HWGROUP(drive));
+				DRIVER(drive)->end_request(drive, 1);
 			}
 			return ide_stopped;
 		}
 		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
 		       drive->name, dma_stat);
 	}
-	return ide_error(drive, "dma_intr", stat);
+	return DRIVER(drive)->error(drive, "dma_intr", stat);
 }
 
-static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq)
+EXPORT_SYMBOL_GPL(ide_dma_intr);
+
+/**
+ *	ide_build_sglist	-	map IDE scatter gather for DMA I/O
+ *	@hwif: the interface to build the DMA table for
+ *	@rq: the request holding the sg list
+ *	@ddir: data direction
+ *
+ *	Perform the PCI mapping magic neccessary to access the source or
+ *	target buffers of a request via PCI DMA. The lower layers of the
+ *	kernel provide the neccessary cache management so that we can
+ *	operate in a portable fashion
+ */
+ 
+static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq, int ddir)
 {
 	struct buffer_head *bh;
 	struct scatterlist *sg = hwif->sg_table;
-	unsigned long lastdataend = ~0UL;
 	int nents = 0;
 
 	if (hwif->sg_dma_active)
 		BUG();
 
-	if (rq->cmd == READ)
-		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-	else
-		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
-
 	bh = rq->bh;
 	do {
-		struct scatterlist *sge;
+		unsigned char *virt_addr = bh->b_data;
+		unsigned int size = bh->b_size;
 
-		/*
-		 * continue segment from before?
-		 */
-		if (bh_phys(bh) == lastdataend) {
-			sg[nents - 1].length += bh->b_size;
-			lastdataend += bh->b_size;
-			continue;
-		}
-
-		/*
-		 * start new segment
-		 */
 		if (nents >= PRD_ENTRIES)
 			return 0;
 
-		sge = &sg[nents];
-		memset(sge, 0, sizeof(*sge));
-
-		if (bh->b_page) {
-			sge->page = bh->b_page;
-			sge->offset = bh_offset(bh);
-		} else {
-			if (((unsigned long) bh->b_data) < PAGE_SIZE)
-				BUG();
-
-			sge->address = bh->b_data;
+		while ((bh = bh->b_reqnext) != NULL) {
+			if ((virt_addr + size) != (unsigned char *) bh->b_data)
+				break;
+			size += bh->b_size;
 		}
-
-		sge->length = bh->b_size;
-		lastdataend = bh_phys(bh) + bh->b_size;
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = size;
+		if(size == 0)
+			BUG();
 		nents++;
-	} while ((bh = bh->b_reqnext) != NULL);
+	} while (bh != NULL);
 
-	return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
+	if(nents == 0)
+		BUG();
+		
+	hwif->sg_dma_direction = ddir;
+	return pci_map_sg(hwif->pci_dev, sg, nents, ddir);
 }
 
+/**
+ *	ide_raw_build_sglist	-	map IDE scatter gather for DMA
+ *	@hwif: the interface to build the DMA table for
+ *	@rq: the request holding the sg list
+ *
+ *	Perform the PCI mapping magic neccessary to access the source or
+ *	target buffers of a taskfile request via PCI DMA. The lower layers 
+ *	of the  kernel provide the neccessary cache management so that we can
+ *	operate in a portable fashion
+ */
+ 
 static int ide_raw_build_sglist (ide_hwif_t *hwif, struct request *rq)
 {
 	struct scatterlist *sg = hwif->sg_table;
 	int nents = 0;
 	ide_task_t *args = rq->special;
-	unsigned char *virt_addr = rq->buffer;
+	u8 *virt_addr = rq->buffer;
 	int sector_count = rq->nr_sectors;
 
-//	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA) ||
-//	    (args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA_EXT))
 	if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
 		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
 	else
 		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-	
+#if 1
 	if (sector_count > 128) {
 		memset(&sg[nents], 0, sizeof(*sg));
 		sg[nents].address = virt_addr;
@@ -330,37 +318,54 @@
 	sg[nents].address = virt_addr;
 	sg[nents].length =  sector_count  * SECTOR_SIZE;
 	nents++;
-   
+#else
+        while (sector_count > 128) {
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address	= virt_addr;
+		sg[nents].length	= 128 * SECTOR_SIZE;
+		nents++;
+		virt_addr		= virt_addr + (128 * SECTOR_SIZE);
+		sector_count		-= 128;
+	};
+	memset(&sg[nents], 0, sizeof(*sg));
+	sg[nents].address	= virt_addr;
+	sg[nents].length	= sector_count * SECTOR_SIZE;
+	nents++;
+#endif
 	return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
 }
 
-/*
- * ide_build_dmatable() prepares a dma request.
- * Returns 0 if all went okay, returns 1 otherwise.
- * May also be invoked from trm290.c
- */
-int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func)
-{
-	unsigned int *table = HWIF(drive)->dmatable_cpu;
-#ifdef CONFIG_BLK_DEV_TRM290
-	unsigned int is_trm290_chipset = (HWIF(drive)->chipset == ide_trm290);
-#else
-	const int is_trm290_chipset = 0;
-#endif
+/**
+ *	ide_build_dmatable	-	build IDE DMA table
+ *
+ *	ide_build_dmatable() prepares a dma request. We map the command
+ *	to get the pci bus addresses of the buffers and then build up
+ *	the PRD table that the IDE layer wants to be fed. The code
+ *	knows about the 64K wrap bug in the CS5530.
+ *
+ *	Returns 0 if all went okay, returns 1 otherwise.
+ *	May also be invoked from trm290.c
+ */
+ 
+int ide_build_dmatable (ide_drive_t *drive, struct request *rq, int ddir)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned int *table	= hwif->dmatable_cpu;
+	unsigned int is_trm290	= (hwif->chipset == ide_trm290) ? 1 : 0;
 	unsigned int count = 0;
 	int i;
 	struct scatterlist *sg;
 
-	if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE)
-		HWIF(drive)->sg_nents = i = ide_raw_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
+	if (rq->cmd == IDE_DRIVE_TASKFILE)
+		hwif->sg_nents = i = ide_raw_build_sglist(hwif, rq);
 	else
-		HWIF(drive)->sg_nents = i = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
+		hwif->sg_nents = i = ide_build_sglist(hwif, rq, ddir);
 
 	if (!i)
 		return 0;
 
-	sg = HWIF(drive)->sg_table;
-	while (i) {
+	sg = hwif->sg_table;
+	while (i && sg_dma_len(sg)) {
 		u32 cur_addr;
 		u32 cur_len;
 
@@ -374,35 +379,36 @@
 		 */
 
 		while (cur_len) {
-			u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);
-			
-			if (count++ >= PRD_ENTRIES)
-				BUG();
-
-			if (bcount > cur_len)
-				bcount = cur_len;
-			*table++ = cpu_to_le32(cur_addr);
-			xcount = bcount & 0xffff;
-			if (is_trm290_chipset)
-				xcount = ((xcount >> 2) - 1) << 16;
-			if (xcount == 0x0000) {
-				/* 
-				 * Most chipsets correctly interpret a length
-				 * of 0x0000 as 64KB, but at least one
-				 * (e.g. CS5530) misinterprets it as zero (!).
-				 * So here we break the 64KB entry into two
-				 * 32KB entries instead.
-				 */
-				if (count++ >= PRD_ENTRIES)
-					goto use_pio_instead;
-
-				*table++ = cpu_to_le32(0x8000);
-				*table++ = cpu_to_le32(cur_addr + 0x8000);
-				xcount = 0x8000;
+			if (count++ >= PRD_ENTRIES) {
+				printk("%s: DMA table too small\n", drive->name);
+				goto use_pio_instead;
+			} else {
+				u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);
+
+				if (bcount > cur_len)
+					bcount = cur_len;
+				*table++ = cpu_to_le32(cur_addr);
+				xcount = bcount & 0xffff;
+				if (is_trm290)
+					xcount = ((xcount >> 2) - 1) << 16;
+				if (xcount == 0x0000) {
+	/* 
+	 * Most chipsets correctly interpret a length of 0x0000 as 64KB,
+	 * but at least one (e.g. CS5530) misinterprets it as zero (!).
+	 * So here we break the 64KB entry into two 32KB entries instead.
+	 */
+					if (count++ >= PRD_ENTRIES) {
+						printk("%s: DMA table too small\n", drive->name);
+						goto use_pio_instead;
+					}
+					*table++ = cpu_to_le32(0x8000);
+					*table++ = cpu_to_le32(cur_addr + 0x8000);
+					xcount = 0x8000;
+				}
+				*table++ = cpu_to_le32(xcount);
+				cur_addr += bcount;
+				cur_len -= bcount;
 			}
-			*table++ = cpu_to_le32(xcount);
-			cur_addr += bcount;
-			cur_len -= bcount;
 		}
 
 		sg++;
@@ -410,21 +416,33 @@
 	}
 
 	if (count) {
-		if (!is_trm290_chipset)
+		if (!is_trm290)
 			*--table |= cpu_to_le32(0x80000000);
 		return count;
 	}
 	printk("%s: empty DMA table?\n", drive->name);
 use_pio_instead:
-	pci_unmap_sg(HWIF(drive)->pci_dev,
-		     HWIF(drive)->sg_table,
-		     HWIF(drive)->sg_nents,
-		     HWIF(drive)->sg_dma_direction);
-	HWIF(drive)->sg_dma_active = 0;
+	pci_unmap_sg(hwif->pci_dev,
+		     hwif->sg_table,
+		     hwif->sg_nents,
+		     hwif->sg_dma_direction);
+	hwif->sg_dma_active = 0;
 	return 0; /* revert to PIO for this request */
 }
 
-/* Teardown mappings after DMA has completed.  */
+EXPORT_SYMBOL_GPL(ide_build_dmatable);
+
+/**
+ *	ide_destroy_dmatable	-	clean up DMA mapping
+ *	@drive: The drive to unmap
+ *
+ *	Teardown mappings after DMA has completed. This must be called
+ *	after the completion of each use of ide_build_dmatable and before
+ *	the next use of ide_build_dmatable. Failure to do so will cause
+ *	an oops as only one mapping can be live for each target at a given
+ *	time.
+ */
+ 
 void ide_destroy_dmatable (ide_drive_t *drive)
 {
 	struct pci_dev *dev = HWIF(drive)->pci_dev;
@@ -435,336 +453,513 @@
 	HWIF(drive)->sg_dma_active = 0;
 }
 
-/*
- *  For both Blacklisted and Whitelisted drives.
- *  This is setup to be called as an extern for future support
- *  to other special driver code.
+EXPORT_SYMBOL_GPL(ide_destroy_dmatable);
+
+/**
+ *	config_drive_for_dma	-	attempt to activate IDE DMA
+ *	@drive: the drive to place in DMA mode
+ *
+ *	If the drive supports at least mode 2 DMA or UDMA of any kind
+ *	then attempt to place it into DMA mode. Drives that are known to
+ *	support DMA but predate the DMA properties or that are known
+ *	to have DMA handling bugs are also set up appropriately based
+ *	on the good/bad drive lists.
  */
-int check_drive_lists (ide_drive_t *drive, int good_bad)
+ 
+static int config_drive_for_dma (ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
+	ide_hwif_t *hwif = HWIF(drive);
 
-#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
-	if (good_bad) {
-		return in_drive_list(id, drive_whitelist);
-	} else {
-		int blacklist = in_drive_list(id, drive_blacklist);
-		if (blacklist)
-			printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model);
-		return(blacklist);
-	}
-#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
-	const char **list;
+	if (id && (id->capability & 1) && hwif->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			return hwif->ide_dma_off(drive);
+
+		/*
+		 * Enable DMA on any drive that has
+		 * UltraDMA (mode 0/1/2/3/4/5/6) enabled
+		 */
+		if ((id->field_valid & 4) && ((id->dma_ultra >> 8) & 0x7f))
+			return hwif->ide_dma_on(drive);
+		/*
+		 * Enable DMA on any drive that has mode2 DMA
+		 * (multi or single) enabled
+		 */
+		if (id->field_valid & 2)	/* regular DMA */
+			if ((id->dma_mword & 0x404) == 0x404 ||
+			    (id->dma_1word & 0x404) == 0x404)
+				return hwif->ide_dma_on(drive);
 
-	if (good_bad) {
 		/* Consult the list of known "good" drives */
-		list = good_dma_drives;
-		while (*list) {
-			if (!strcmp(*list++,id->model))
-				return 1;
-		}
-	} else {
-		/* Consult the list of known "bad" drives */
-		list = bad_dma_drives;
-		while (*list) {
-			if (!strcmp(*list++,id->model)) {
-				printk("%s: Disabling (U)DMA for %s\n",
-					drive->name, id->model);
-				return 1;
-			}
-		}
+		if (hwif->ide_dma_good_drive(drive))
+			return hwif->ide_dma_on(drive);
 	}
-#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
-	return 0;
+//	if (hwif->tuneproc != NULL) hwif->tuneproc(drive, 255);
+	return hwif->ide_dma_off_quietly(drive);
 }
 
-int report_drive_dmaing (ide_drive_t *drive)
+/**
+ *	dma_timer_expiry	-	handle a DMA timeout
+ *	@drive: Drive that timed out
+ *
+ *	An IDE DMA transfer timed out. In the event of an error we ask
+ *	the driver to resolve the problem, if a DMA transfer is still
+ *	in progress we continue to wait (arguably we need to add a 
+ *	secondary 'I dont care what the drive thinks' timeout here)
+ *	Finally if we have an interrupt but for some reason got the
+ *	timeout first we complete the I/O. This can occur if an 
+ *	interrupt is lost or due to bugs.
+ */
+ 
+static int dma_timer_expiry (ide_drive_t *drive)
 {
-	struct hd_driveid *id = drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
 
-	if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
-	    (id->dma_ultra & (id->dma_ultra >> 14) & 3)) {
-		if ((id->dma_ultra >> 15) & 1) {
-			printk(", UDMA(mode 7)");	/* UDMA BIOS-enabled! */
-		} else {
-			printk(", UDMA(133)");	/* UDMA BIOS-enabled! */
-		}
-	} else if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
-	  	  (id->dma_ultra & (id->dma_ultra >> 11) & 7)) {
-		if ((id->dma_ultra >> 13) & 1) {
-			printk(", UDMA(100)");	/* UDMA BIOS-enabled! */
-		} else if ((id->dma_ultra >> 12) & 1) {
-			printk(", UDMA(66)");	/* UDMA BIOS-enabled! */
-		} else {
-			printk(", UDMA(44)");	/* UDMA BIOS-enabled! */
-		}
-	} else if ((id->field_valid & 4) &&
-		   (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
-		if ((id->dma_ultra >> 10) & 1) {
-			printk(", UDMA(33)");	/* UDMA BIOS-enabled! */
-		} else if ((id->dma_ultra >> 9) & 1) {
-			printk(", UDMA(25)");	/* UDMA BIOS-enabled! */
-		} else {
-			printk(", UDMA(16)");	/* UDMA BIOS-enabled! */
-		}
-	} else if (id->field_valid & 4) {
-		printk(", (U)DMA");	/* Can be BIOS-enabled! */
-	} else {
-		printk(", DMA");
+	printk(KERN_WARNING "%s: dma_timer_expiry: dma status == 0x%02x\n",
+		drive->name, dma_stat);
+
+	if ((dma_stat & 0x18) == 0x18)	/* BUSY Stupid Early Timer !! */
+		return WAIT_CMD;
+
+	HWGROUP(drive)->expiry = NULL;	/* one free ride for now */
+
+	/* 1 dmaing, 2 error, 4 intr */
+	
+	if (dma_stat & 2) {	/* ERROR */
+		(void) hwif->ide_dma_end(drive);
+		return DRIVER(drive)->error(drive,
+			"dma_timer_expiry", hwif->INB(IDE_STATUS_REG));
 	}
-	return 1;
+	if (dma_stat & 1)	/* DMAing */
+		return WAIT_CMD;
+
+	if (dma_stat & 4)	/* Got an Interrupt */
+		HWGROUP(drive)->handler(drive);
+
+	return 0;
 }
 
-static int config_drive_for_dma (ide_drive_t *drive)
+/**
+ *	__ide_dma_host_off	-	Generic DMA kill
+ *	@drive: drive to control
+ *
+ *	Perform the generic IDE controller DMA off operation. This
+ *	works for most IDE bus mastering controllers
+ */
+
+int __ide_dma_host_off (ide_drive_t *drive)
 {
-	int config_allows_dma = 1;
-	struct hd_driveid *id = drive->id;
-	ide_hwif_t *hwif = HWIF(drive);
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
 
-#ifdef CONFIG_IDEDMA_ONLYDISK
-	if (drive->media != ide_disk)
-		config_allows_dma = 0;
-#endif
+	hwif->OUTB((dma_stat & ~(1<<(5+unit))), hwif->dma_status);
+	return 0;
+}
 
-	if (id && (id->capability & 1) && hwif->autodma && config_allows_dma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive))
-			return hwif->dmaproc(ide_dma_off, drive);
+EXPORT_SYMBOL(__ide_dma_host_off);
 
-		/* Enable DMA on any drive that has UltraDMA (mode 6/7/?) enabled */
-		if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
-			if ((id->dma_ultra & (id->dma_ultra >> 14) & 2))
-				return hwif->dmaproc(ide_dma_on, drive);
-		/* Enable DMA on any drive that has UltraDMA (mode 3/4/5) enabled */
-		if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
-			if ((id->dma_ultra & (id->dma_ultra >> 11) & 7))
-				return hwif->dmaproc(ide_dma_on, drive);
-		/* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
-		if (id->field_valid & 4)	/* UltraDMA */
-			if ((id->dma_ultra & (id->dma_ultra >> 8) & 7))
-				return hwif->dmaproc(ide_dma_on, drive);
-		/* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
-		if (id->field_valid & 2)	/* regular DMA */
-			if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404)
-				return hwif->dmaproc(ide_dma_on, drive);
-		/* Consult the list of known "good" drives */
-		if (ide_dmaproc(ide_dma_good_drive, drive))
-			return hwif->dmaproc(ide_dma_on, drive);
+/**
+ *	__ide_dma_host_off_quietly	-	Generic DMA kill
+ *	@drive: drive to control
+ *
+ *	Turn off the current DMA on this IDE controller. 
+ */
+
+int __ide_dma_off_quietly (ide_drive_t *drive)
+{
+	drive->using_dma = 0;
+	ide_toggle_bounce(drive, 0);
+	return HWIF(drive)->ide_dma_host_off(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_off_quietly);
+
+/**
+ *	__ide_dma_host_off	-	Generic DMA kill
+ *	@drive: drive to control
+ *
+ *	Turn off the current DMA on this IDE controller. Inform the
+ *	user that DMA has been disabled. 
+ */
+
+int __ide_dma_off (ide_drive_t *drive)
+{
+	printk(KERN_INFO "%s: DMA disabled\n", drive->name);
+	return HWIF(drive)->ide_dma_off_quietly(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_off);
+
+/**
+ *	__ide_dma_host_on	-	Enable DMA on a host
+ *	@drive: drive to enable for DMA
+ *
+ *	Enable DMA on an IDE controller following generic bus mastering
+ *	IDE controller behaviour
+ */
+ 
+int __ide_dma_host_on (ide_drive_t *drive)
+{
+	if (drive->using_dma) {
+		ide_hwif_t *hwif	= HWIF(drive);
+		u8 unit			= (drive->select.b.unit & 0x01);
+		u8 dma_stat		= hwif->INB(hwif->dma_status);
+
+		hwif->OUTB((dma_stat|(1<<(5+unit))), hwif->dma_status);
+		return 0;
 	}
-	return hwif->dmaproc(ide_dma_off_quietly, drive);
+	return 1;
 }
 
-#ifndef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
-/*
- * 1 dmaing, 2 error, 4 intr
+EXPORT_SYMBOL(__ide_dma_host_on);
+
+/**
+ *	__ide_dma_on		-	Enable DMA on a device
+ *	@drive: drive to enable DMA on
+ *
+ *	Enable IDE DMA for a device on this IDE controller.
  */
-static int dma_timer_expiry (ide_drive_t *drive)
+ 
+int __ide_dma_on (ide_drive_t *drive)
 {
-	byte dma_stat = inb(HWIF(drive)->dma_base+2);
+	drive->using_dma = 1;
+	ide_toggle_bounce(drive, 1);
+	return HWIF(drive)->ide_dma_host_on(drive);
+}
 
-#ifdef DEBUG
-	printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat);
-#endif /* DEBUG */
+EXPORT_SYMBOL(__ide_dma_on);
 
+/**
+ *	__ide_dma_check		-	check DMA setup
+ *	@drive: drive to check
+ *
+ *	Don't use - due for extermination
+ */
+ 
+int __ide_dma_check (ide_drive_t *drive)
+{
+	return config_drive_for_dma(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_check);
+
+int __ide_dma_read (ide_drive_t *drive /*, struct request *rq */)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= HWGROUP(drive)->rq;
+//	ide_task_t *args	= rq->special;
+	unsigned int reading	= 1 << 3;
+	unsigned int count	= 0;
+	u8 dma_stat = 0, lba48	= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+
+	if (!(count = ide_build_dmatable(drive, rq, PCI_DMA_FROMDEVICE)))
+		/* try PIO instead of DMA */
+		return 1;
+	/* PRD table */
+	hwif->OUTL(hwif->dmatable_dma, hwif->dma_prdtable);
+	/* specify r/w */
+	hwif->OUTB(reading, hwif->dma_command);
+	/* read dma_status for INTR & ERROR flags */
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* clear INTR & ERROR flags */
+	hwif->OUTB(dma_stat|6, hwif->dma_status);
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+	/* paranoia check */
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry);
+
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
 #if 0
-	HWGROUP(drive)->expiry = NULL;	/* one free ride for now */
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA;
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
 #endif
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
 
-	if (dma_stat & 2) {	/* ERROR */
-		byte stat = GET_STAT();
-		return ide_error(drive, "dma_timer_expiry", stat);
+	return HWIF(drive)->ide_dma_count(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_read);
+
+int __ide_dma_write (ide_drive_t *drive /*, struct request *rq */)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= HWGROUP(drive)->rq;
+//	ide_task_t *args	= rq->special;
+	unsigned int reading	= 0;
+	unsigned int count	= 0;
+	u8 dma_stat = 0, lba48	= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+
+	if (!(count = ide_build_dmatable(drive, rq, PCI_DMA_TODEVICE)))
+		/* try PIO instead of DMA */
+		return 1;
+	/* PRD table */
+	hwif->OUTL(hwif->dmatable_dma, hwif->dma_prdtable);
+	/* specify r/w */
+	hwif->OUTB(reading, hwif->dma_command);
+	/* read dma_status for INTR & ERROR flags */
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* clear INTR & ERROR flags */
+	hwif->OUTB(dma_stat|6, hwif->dma_status);
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+	/* paranoia check */
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
 	}
-	if (dma_stat & 1)	/* DMAing */
-		return WAIT_CMD;
+#else
+	command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
+	return HWIF(drive)->ide_dma_count(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_write);
+
+int __ide_dma_begin (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_cmd		= hwif->INB(hwif->dma_command);
+
+	/* Note that this is done *after* the cmd has
+	 * been issued to the drive, as per the BM-IDE spec.
+	 * The Promise Ultra33 doesn't work correctly when
+	 * we do this part before issuing the drive cmd.
+	 */
+	/* start DMA */
+	hwif->OUTB(dma_cmd|1, hwif->dma_command);
 	return 0;
 }
-#else /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
-static ide_startstop_t ide_dma_timeout_revovery (ide_drive_t *drive)
+
+EXPORT_SYMBOL(__ide_dma_begin);
+
+/* returns 1 on error, 0 otherwise */
+int __ide_dma_end (ide_drive_t *drive)
 {
-	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
 	ide_hwif_t *hwif	= HWIF(drive);
-	int enable_dma		= drive->using_dma;
-	unsigned long flags;
-	ide_startstop_t startstop;
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	hwgroup->handler = NULL;
-	del_timer(&hwgroup->timer);
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	u8 dma_stat = 0, dma_cmd = 0;
 
 	drive->waiting_for_dma = 0;
+	/* get dma_command mode */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop DMA */
+	hwif->OUTB(dma_cmd&~1, hwif->dma_command);
+	/* get DMA status */
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* clear the INTR & ERROR bits */
+	hwif->OUTB(dma_stat|6, hwif->dma_status);
+	/* purge DMA mappings */
+	ide_destroy_dmatable(drive);
+	/* verify good DMA status */
+	return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
+}
 
-	startstop = ide_do_reset(drive);
+EXPORT_SYMBOL(__ide_dma_end);
 
-	if ((enable_dma) && !(drive->using_dma))
-		(void) hwif->dmaproc(ide_dma_on, drive);
+/* returns 1 if dma irq issued, 0 otherwise */
+int __ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
 
-	return startstop;
+#if 0  /* do not set unless you know what you are doing */
+	if (dma_stat & 4) {
+		u8 stat = hwif->INB(IDE_STATUS_REG);
+		hwif->OUTB(hwif->dma_status, dma_stat & 0xE4);
+	}
+#endif
+	/* return 1 if INTR asserted */
+	if ((dma_stat & 4) == 4)
+		return 1;
+	if (!drive->waiting_for_dma)
+		printk(KERN_WARNING "%s: (%s) called while not waiting\n",
+			drive->name, __FUNCTION__);
+	drive->waiting_for_dma++;
+	return 0;
 }
-#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
 
-static inline void ide_toggle_bounce(ide_drive_t *drive, int on)
-{
-	dma64_addr_t addr = BLK_BOUNCE_HIGH;
+EXPORT_SYMBOL(__ide_dma_test_irq);
 
-	if (HWIF(drive)->no_highio || HWIF(drive)->pci_dev == NULL)
-		return;
+int __ide_dma_bad_drive (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
 
-	if (on && drive->media == ide_disk) {
-		if (!PCI_DMA_BUS_IS_PHYS)
-			addr = BLK_BOUNCE_ANY;
-		else
-			addr = HWIF(drive)->pci_dev->dma_mask;
+#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
+	int blacklist = in_drive_list(id, drive_blacklist);
+	if (blacklist) {
+		printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model);
+		return(blacklist);
+	}
+#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+	const char **list;
+	/* Consult the list of known "bad" drives */
+	list = bad_dma_drives;
+	while (*list) {
+		if (!strcmp(*list++,id->model)) {
+			printk("%s: Disabling (U)DMA for %s\n",
+				drive->name, id->model);
+			return 1;
+		}
 	}
+#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+	return 0;
+}
 
-	blk_queue_bounce_limit(&drive->queue, addr);
+EXPORT_SYMBOL(__ide_dma_bad_drive);
+
+int __ide_dma_good_drive (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+
+#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
+	return in_drive_list(id, drive_whitelist);
+#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+	const char **list;
+	/* Consult the list of known "good" drives */
+	list = good_dma_drives;
+	while (*list) {
+		if (!strcmp(*list++,id->model))
+			return 1;
+	}
+#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+	return 0;
 }
 
+EXPORT_SYMBOL(__ide_dma_good_drive);
+
 /*
- * ide_dmaproc() initiates/aborts DMA read/write operations on a drive.
- *
- * The caller is assumed to have selected the drive and programmed the drive's
- * sector address using CHS or LBA.  All that remains is to prepare for DMA
- * and then issue the actual read/write DMA/PIO command to the drive.
- *
- * For ATAPI devices, we just prepare for DMA and return. The caller should
- * then issue the packet command to the drive and call us again with
- * ide_dma_begin afterwards.
- *
- * Returns 0 if all went well.
- * Returns 1 if DMA read/write could not be started, in which case
- * the caller should revert to PIO for the current request.
- * May also be invoked from trm290.c
- */
-int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-//	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
-	ide_hwif_t *hwif		= HWIF(drive);
-	unsigned long dma_base		= hwif->dma_base;
-	byte unit			= (drive->select.b.unit & 0x01);
-	unsigned int count, reading = 0, set_high = 1;
-	byte dma_stat;
-
-	switch (func) {
-		case ide_dma_off:
-			printk("%s: DMA disabled\n", drive->name);
-		case ide_dma_off_quietly:
-			set_high = 0;
-			outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-		case ide_dma_on:
-			drive->using_dma = (func == ide_dma_on);
-			if (drive->using_dma)
-				outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-			ide_toggle_bounce(drive, set_high);
-			return 0;
-		case ide_dma_check:
-			return config_drive_for_dma (drive);
-		case ide_dma_read:
-			reading = 1 << 3;
-		case ide_dma_write:
-			SELECT_READ_WRITE(hwif,drive,func);
-			if (!(count = ide_build_dmatable(drive, func)))
-				return 1;	/* try PIO instead of DMA */
-			outl(hwif->dmatable_dma, dma_base + 4); /* PRD table */
-			outb(reading, dma_base);			/* specify r/w */
-			outb(inb(dma_base+2)|6, dma_base+2);		/* clear INTR & ERROR flags */
-			drive->waiting_for_dma = 1;
-			if (drive->media != ide_disk)
-				return 0;
-#ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
-			ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, NULL);	/* issue cmd to drive */
-#else /* !CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
-			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry);	/* issue cmd to drive */
-#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
-			if ((HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) &&
-			    (drive->addressing == 1)) {
-				ide_task_t *args = HWGROUP(drive)->rq->special;
-				OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
-			} else if (drive->addressing) {
-				OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
+ * Used for HOST FIFO counters for VDMA
+ * PIO over DMA, effective ATA-Bridge operator.
+ */
+int __ide_dma_count (ide_drive_t *drive)
+{
+	return HWIF(drive)->ide_dma_begin(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_count);
+
+int __ide_dma_verbose (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+
+	if (id->field_valid & 4) {
+		if ((id->dma_ultra >> 8) && (id->dma_mword >> 8)) {
+			printk(", BUG DMA OFF");
+			return hwif->ide_dma_off_quietly(drive);
+		}
+		if (id->dma_ultra & ((id->dma_ultra >> 8) & hwif->ultra_mask)) {
+			if (((id->dma_ultra >> 11) & 0x1F) &&
+			    eighty_ninty_three(drive)) {
+				if ((id->dma_ultra >> 15) & 1) {
+					printk(", UDMA(mode 7)");
+				} else if ((id->dma_ultra >> 14) & 1) {
+					printk(", UDMA(133)");
+				} else if ((id->dma_ultra >> 13) & 1) {
+					printk(", UDMA(100)");
+				} else if ((id->dma_ultra >> 12) & 1) {
+					printk(", UDMA(66)");
+				} else if ((id->dma_ultra >> 11) & 1) {
+					printk(", UDMA(44)");
+				} else
+					goto mode_two;
 			} else {
-				OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-			}
-			return HWIF(drive)->dmaproc(ide_dma_begin, drive);
-		case ide_dma_begin:
-			/* Note that this is done *after* the cmd has
-			 * been issued to the drive, as per the BM-IDE spec.
-			 * The Promise Ultra33 doesn't work correctly when
-			 * we do this part before issuing the drive cmd.
-			 */
-			outb(inb(dma_base)|1, dma_base);		/* start DMA */
-			return 0;
-		case ide_dma_end: /* returns 1 on error, 0 otherwise */
-			drive->waiting_for_dma = 0;
-			outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-			dma_stat = inb(dma_base+2);		/* get DMA status */
-			outb(dma_stat|6, dma_base+2);	/* clear the INTR & ERROR bits */
-			ide_destroy_dmatable(drive);	/* purge DMA mappings */
-			return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;	/* verify good DMA status */
-		case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = inb(dma_base+2);
-#if 0  /* do not set unless you know what you are doing */
-			if (dma_stat & 4) {
-				byte stat = GET_STAT();
-				outb(dma_base+2, dma_stat & 0xE4);
+		mode_two:
+				if ((id->dma_ultra >> 10) & 1) {
+					printk(", UDMA(33)");
+				} else if ((id->dma_ultra >> 9) & 1) {
+					printk(", UDMA(25)");
+				} else if ((id->dma_ultra >> 8) & 1) {
+					printk(", UDMA(16)");
+				}
 			}
-#endif
-			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-		case ide_dma_bad_drive:
-		case ide_dma_good_drive:
-			return check_drive_lists(drive, (func == ide_dma_good_drive));
-		case ide_dma_verbose:
-			return report_drive_dmaing(drive);
-		case ide_dma_timeout:
-			// FIXME: Many IDE chipsets do not permit command file register access
-			// FIXME: while the bus-master function is still active.
-			// FIXME: To prevent deadlock with those chipsets, we must be extremely
-			// FIXME: careful here (and in ide_intr() as well) to NOT access any
-			// FIXME: registers from the 0x1Fx/0x17x sets before terminating the
-			// FIXME: bus-master operation via the bus-master control reg.
-			// FIXME: Otherwise, chipset deadlock will occur, and some systems will
-			// FIXME: lock up completely!!
-#ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
-			/*
-			 * Have to issue an abort and requeue the request
-			 * DMA engine got turned off by a goofy ASIC, and
-			 * we have to clean up the mess, and here is as good
-			 * as any.  Do it globally for all chipsets.
-			 */
-			outb(0x00, dma_base);		/* stop DMA */
-			dma_stat = inb(dma_base+2);	/* get DMA status */
-			outb(dma_stat|6, dma_base+2);	/* clear the INTR & ERROR bits */
-			printk("%s: %s: Lets do it again!" \
-				"stat = 0x%02x, dma_stat = 0x%02x\n",
-				drive->name, ide_dmafunc_verbose(func),
-				GET_STAT(), dma_stat);
-
-			if (dma_stat & 0xF0)
-				return ide_dma_timeout_revovery(drive);
-
-			printk("%s: %s: (restart_request) Lets do it again!" \
-				"stat = 0x%02x, dma_stat = 0x%02x\n",
-				drive->name, ide_dmafunc_verbose(func),
-				GET_STAT(), dma_stat);
-
-			return restart_request(drive);  // BUG: return types do not match!!
-//#else
-//			return HWGROUP(drive)->handler(drive);
-#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
-		case ide_dma_retune:
-		case ide_dma_lostirq:
-			printk("ide_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func),  func);
-			return 1;
-		default:
-			printk("ide_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func);
-			return 1;
+		} else {
+			printk(", (U)DMA");	/* Can be BIOS-enabled! */
+		}
+	} else if (id->field_valid & 2) {
+		if ((id->dma_mword >> 8) && (id->dma_1word >> 8)) {
+			printk(", BUG DMA OFF");
+			return hwif->ide_dma_off_quietly(drive);
+		}
+		printk(", DMA");
+	} else if (id->field_valid & 1) {
+		printk(", BUG");
 	}
+	return 1;
 }
 
+EXPORT_SYMBOL(__ide_dma_verbose);
+
+/**
+ *	__ide_dma_retune	-	default retune handler
+ *	@drive: drive to retune
+ *
+ *	Default behaviour when we decide to return the IDE DMA setup.
+ *	The default behaviour is "we don't"
+ */
+ 
+int __ide_dma_retune (ide_drive_t *drive)
+{
+	printk(KERN_WARNING "%s: chipset supported call only\n", __FUNCTION__);
+	return 1;
+}
+
+EXPORT_SYMBOL(__ide_dma_retune);
+
+int __ide_dma_lostirq (ide_drive_t *drive)
+{
+	printk("%s: DMA interrupt recovery\n", drive->name);
+	return 1;
+}
+
+EXPORT_SYMBOL(__ide_dma_lostirq);
+
+int __ide_dma_timeout (ide_drive_t *drive)
+{
+	printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
+	if (HWIF(drive)->ide_dma_test_irq(drive))
+		return 0;
+	return HWIF(drive)->ide_dma_end(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_timeout);
+
 /*
  * Needed for allowing full modular support of ide-driver
  */
-int ide_release_dma (ide_hwif_t *hwif)
+int ide_release_dma_engine (ide_hwif_t *hwif)
 {
 	if (hwif->dmatable_cpu) {
 		pci_free_consistent(hwif->pci_dev,
@@ -777,128 +972,206 @@
 		kfree(hwif->sg_table);
 		hwif->sg_table = NULL;
 	}
+	return 1;
+}
+
+int ide_release_mmio_dma (ide_hwif_t *hwif)
+{
+	if ((hwif->dma_extra) && (hwif->channel == 0))
+		release_mem_region((hwif->dma_base + 16), hwif->dma_extra);
+	release_mem_region(hwif->dma_base, 8);
+	if (hwif->dma_base2)
+		release_mem_region(hwif->dma_base, 8);
+	return 1;
+}
+
+int ide_release_iomio_dma (ide_hwif_t *hwif)
+{
 	if ((hwif->dma_extra) && (hwif->channel == 0))
 		release_region((hwif->dma_base + 16), hwif->dma_extra);
 	release_region(hwif->dma_base, 8);
+	if (hwif->dma_base2)
+		release_region(hwif->dma_base, 8);
 	return 1;
 }
 
 /*
- *	This can be called for a dynamically installed interface. Don't __init it
+ * Needed for allowing full modular support of ide-driver
  */
- 
-void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports)
+int ide_release_dma (ide_hwif_t *hwif)
 {
-	printk("    %s: BM-DMA at 0x%04lx-0x%04lx", hwif->name, dma_base, dma_base + num_ports - 1);
-	if (check_region(dma_base, num_ports)) {
-		printk(" -- ERROR, PORT ADDRESSES ALREADY IN USE\n");
-		return;
-	}
-	request_region(dma_base, num_ports, hwif->name);
-	hwif->dma_base = dma_base;
-	hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
-						    PRD_ENTRIES * PRD_BYTES,
-						    &hwif->dmatable_dma);
-	if (hwif->dmatable_cpu == NULL)
-		goto dma_alloc_failure;
+	if (hwif->chipset == ide_etrax100)
+		return 1;
+
+	ide_release_dma_engine(hwif);
+	if (hwif->mmio)
+		return ide_release_mmio_dma(hwif);
+	return ide_release_iomio_dma(hwif);
+}
 
+int ide_allocate_dma_engine (ide_hwif_t *hwif)
+{
+	hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
+						  PRD_ENTRIES * PRD_BYTES,
+						  &hwif->dmatable_dma);
 	hwif->sg_table = kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES,
-				 GFP_KERNEL);
-	if (hwif->sg_table == NULL) {
-		pci_free_consistent(hwif->pci_dev, PRD_ENTRIES * PRD_BYTES,
-				    hwif->dmatable_cpu, hwif->dmatable_dma);
-		goto dma_alloc_failure;
-	}
+				GFP_KERNEL);
 
-	hwif->dmaproc = &ide_dmaproc;
+	if ((hwif->dmatable_cpu) && (hwif->sg_table))
+		return 0;
 
-	if (hwif->chipset != ide_trm290) {
-		byte dma_stat = inb(dma_base+2);
-		printk(", BIOS settings: %s:%s, %s:%s",
-		       hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
-		       hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
+	printk(KERN_ERR "%s: -- Error, unable to allocate%s%s table(s).\n",
+		(hwif->dmatable_cpu == NULL) ? " CPU" : "",
+		(hwif->sg_table == NULL) ?  " SG DMA" : " DMA",
+		hwif->cds->name);
+
+	ide_release_dma_engine(hwif);
+	return 1;
+}
+
+int ide_mmio_dma (ide_hwif_t *hwif, unsigned long base, unsigned int ports)
+{
+	printk(KERN_INFO "    %s: MMIO-DMA at 0x%08lx-0x%08lx",
+		hwif->name, base, base + ports - 1);
+	if (check_mem_region(base, ports)) {
+		printk(" -- Error, MMIO ports already in use.\n");
+		return 1;
 	}
-	printk("\n");
-	return;
+	request_mem_region(base, ports, hwif->name);
+	hwif->dma_base = base;
+	if ((hwif->cds->extra) && (hwif->channel == 0)) {
+		request_region(base+16, hwif->cds->extra, hwif->cds->name);
+		hwif->dma_extra = hwif->cds->extra;
+	}
+	
+	/* There is an issue to watch here. The master might not be 
+	   registered because the BIOS disabled it. Eventually this should
+	   be fixed by always registering the mate */
+	   
+	if(hwif->mate == NULL)
+		hwif->dma_master = base;
+	else
+		hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base;
+	if (hwif->dma_base2) {
+		if (!check_mem_region(hwif->dma_base2, ports))
+			request_mem_region(hwif->dma_base2, ports, hwif->name);
+	}
+	return 0;
+}
 
-dma_alloc_failure:
-	printk(" -- ERROR, UNABLE TO ALLOCATE DMA TABLES\n");
+int ide_iomio_dma (ide_hwif_t *hwif, unsigned long base, unsigned int ports)
+{
+	printk(KERN_INFO "    %s: BM-DMA at 0x%04lx-0x%04lx",
+		hwif->name, base, base + ports - 1);
+	if (!request_region(base, ports, hwif->name)) {
+		printk(" -- Error, ports in use.\n");
+		return 1;
+	}
+	hwif->dma_base = base;
+	if ((hwif->cds->extra) && (hwif->channel == 0)) {
+		request_region(base+16, hwif->cds->extra, hwif->cds->name);
+		hwif->dma_extra = hwif->cds->extra;
+	}
+	/* There is an issue to watch here. The master might not be 
+	   registered because the BIOS disabled it. Eventually this should
+	   be fixed by always registering the mate */
+	   
+	if(hwif->mate == NULL)
+		hwif->dma_master = base;
+	else
+		hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base;
+	if (hwif->dma_base2) {
+		if (!request_region(hwif->dma_base2, ports, hwif->name))
+		{
+			printk(" -- Error, secondary ports in use.\n");
+			release_region(base, ports);
+			return 1;
+		}
+	}
+	return 0;
 }
 
 /*
- * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
+ * 
  */
-unsigned long __init ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name)
+int ide_dma_iobase (ide_hwif_t *hwif, unsigned long base, unsigned int ports)
 {
-	unsigned long	dma_base = 0;
-	struct pci_dev	*dev = hwif->pci_dev;
+	if (hwif->mmio)
+		return ide_mmio_dma(hwif, base, ports);
+	return ide_iomio_dma(hwif, base, ports);
+}
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
-	int second_chance = 0;
-
-second_chance_to_dma:
-#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
-
-	if (hwif->mate && hwif->mate->dma_base) {
-		dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
-	} else {
-		dma_base = pci_resource_start(dev, 4);
-		if (!dma_base) {
-			printk("%s: dma_base is invalid (0x%04lx)\n", name, dma_base);
-			dma_base = 0;
-		}
-	}
+/*
+ * This can be called for a dynamically installed interface. Don't __init it
+ */
+void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports)
+{
+	if (ide_dma_iobase(hwif, dma_base, num_ports))
+		return;
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
-	if ((!dma_base) && (!second_chance)) {
-		unsigned long set_bmiba = 0;
-		second_chance++;
-		switch(dev->vendor) {
-			case PCI_VENDOR_ID_AL:
-				set_bmiba = DEFAULT_BMALIBA; break;
-			case PCI_VENDOR_ID_VIA:
-				set_bmiba = DEFAULT_BMCRBA; break;
-			case PCI_VENDOR_ID_INTEL:
-				set_bmiba = DEFAULT_BMIBA; break;
-			default:
-				return dma_base;
-		}
-		pci_write_config_dword(dev, 0x20, set_bmiba|1);
-		goto second_chance_to_dma;
+	if (ide_allocate_dma_engine(hwif)) {
+		ide_release_dma(hwif);
+		return;
 	}
-#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
 
-	if (dma_base) {
-		if (extra) /* PDC20246, PDC20262, HPT343, & HPT366 */
-			request_region(dma_base+16, extra, name);
-		dma_base += hwif->channel ? 8 : 0;
-		hwif->dma_extra = extra;
-
-		switch(dev->device) {
-			case PCI_DEVICE_ID_AL_M5219:
-			case PCI_DEVICE_ID_AMD_VIPER_7409:
-			case PCI_DEVICE_ID_CMD_643:
-				outb(inb(dma_base+2) & 0x60, dma_base+2);
-				if (inb(dma_base+2) & 0x80) {
-					printk("%s: simplex device: DMA forced\n", name);
-				}
-				break;
-			default:
-				/*
-				 * If the device claims "simplex" DMA,
-				 * this means only one of the two interfaces
-				 * can be trusted with DMA at any point in time.
-				 * So we should enable DMA only on one of the
-				 * two interfaces.
-				 */
-				if ((inb(dma_base+2) & 0x80)) {	/* simplex device? */
-					if ((!hwif->drives[0].present && !hwif->drives[1].present) ||
-					    (hwif->mate && hwif->mate->dma_base)) {
-						printk("%s: simplex device:  DMA disabled\n", name);
-						dma_base = 0;
-					}
-				}
-		}
+	if (!(hwif->dma_command))
+		hwif->dma_command	= hwif->dma_base;
+	if (!(hwif->dma_vendor1))
+		hwif->dma_vendor1	= (hwif->dma_base + 1);
+	if (!(hwif->dma_status))
+		hwif->dma_status	= (hwif->dma_base + 2);
+	if (!(hwif->dma_vendor3))
+		hwif->dma_vendor3	= (hwif->dma_base + 3);
+	if (!(hwif->dma_prdtable))
+		hwif->dma_prdtable	= (hwif->dma_base + 4);
+
+	if (!hwif->ide_dma_off)
+		hwif->ide_dma_off = &__ide_dma_off;
+	if (!hwif->ide_dma_off_quietly)
+		hwif->ide_dma_off_quietly = &__ide_dma_off_quietly;
+	if (!hwif->ide_dma_host_off)
+		hwif->ide_dma_host_off = &__ide_dma_host_off;
+	if (!hwif->ide_dma_on)
+		hwif->ide_dma_on = &__ide_dma_on;
+	if (!hwif->ide_dma_host_on)
+		hwif->ide_dma_host_on = &__ide_dma_host_on;
+	if (!hwif->ide_dma_check)
+		hwif->ide_dma_check = &__ide_dma_check;
+	if (!hwif->ide_dma_read)
+		hwif->ide_dma_read = &__ide_dma_read;
+	if (!hwif->ide_dma_write)
+		hwif->ide_dma_write = &__ide_dma_write;
+	if (!hwif->ide_dma_count)
+		hwif->ide_dma_count = &__ide_dma_count;
+	if (!hwif->ide_dma_begin)
+		hwif->ide_dma_begin = &__ide_dma_begin;
+	if (!hwif->ide_dma_end)
+		hwif->ide_dma_end = &__ide_dma_end;
+	if (!hwif->ide_dma_test_irq)
+		hwif->ide_dma_test_irq = &__ide_dma_test_irq;
+	if (!hwif->ide_dma_bad_drive)
+		hwif->ide_dma_bad_drive = &__ide_dma_bad_drive;
+	if (!hwif->ide_dma_good_drive)
+		hwif->ide_dma_good_drive = &__ide_dma_good_drive;
+	if (!hwif->ide_dma_verbose)
+		hwif->ide_dma_verbose = &__ide_dma_verbose;
+	if (!hwif->ide_dma_timeout)
+		hwif->ide_dma_timeout = &__ide_dma_timeout;
+	if (!hwif->ide_dma_retune)
+		hwif->ide_dma_retune = &__ide_dma_retune;
+	if (!hwif->ide_dma_lostirq)
+		hwif->ide_dma_lostirq = &__ide_dma_lostirq;
+
+	if (hwif->chipset != ide_trm290) {
+		u8 dma_stat = hwif->INB(hwif->dma_status);
+		printk(", BIOS settings: %s:%s, %s:%s",
+		       hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
+		       hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
 	}
-	return dma_base;
+	printk("\n");
+
+	if (!(hwif->dma_master))
+		BUG();
 }
+
+EXPORT_SYMBOL_GPL(ide_setup_dma);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-features.c linux-2.4.21/drivers/ide/ide-features.c
--- linux-2.4.20/drivers/ide/ide-features.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-features.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,385 +0,0 @@
-/*
- * linux/drivers/block/ide-features.c	Version 0.04	June 9, 2000
- *
- *  Copyright (C) 1999-2000	Linus Torvalds & authors (see below)
- *  
- *  Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
- *
- *  Extracts if ide.c to address the evolving transfer rate code for
- *  the SETFEATURES_XFER callouts.  Various parts of any given function
- *  are credited to previous ATA-IDE maintainers.
- *
- *  Auto-CRC downgrade for Ultra DMA(ing)
- *
- *  May be copied or modified under the terms of the GNU General Public License
- */
-
-#include <linux/config.h>
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/blkpg.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-
-#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/bitops.h>
-
-/*
- * A Verbose noise maker for debugging on the attempted transfer rates.
- */
-char *ide_xfer_verbose (byte xfer_rate)
-{
-	switch(xfer_rate) {
-		case XFER_UDMA_7:	return("UDMA 7");
-		case XFER_UDMA_6:	return("UDMA 6");
-		case XFER_UDMA_5:	return("UDMA 5");
-		case XFER_UDMA_4:	return("UDMA 4");
-		case XFER_UDMA_3:	return("UDMA 3");
-		case XFER_UDMA_2:	return("UDMA 2");
-		case XFER_UDMA_1:	return("UDMA 1");
-		case XFER_UDMA_0:	return("UDMA 0");
-		case XFER_MW_DMA_2:	return("MW DMA 2");
-		case XFER_MW_DMA_1:	return("MW DMA 1");
-		case XFER_MW_DMA_0:	return("MW DMA 0");
-		case XFER_SW_DMA_2:	return("SW DMA 2");
-		case XFER_SW_DMA_1:	return("SW DMA 1");
-		case XFER_SW_DMA_0:	return("SW DMA 0");
-		case XFER_PIO_4:	return("PIO 4");
-		case XFER_PIO_3:	return("PIO 3");
-		case XFER_PIO_2:	return("PIO 2");
-		case XFER_PIO_1:	return("PIO 1");
-		case XFER_PIO_0:	return("PIO 0");
-		case XFER_PIO_SLOW:	return("PIO SLOW");
-		default:		return("XFER ERROR");
-	}
-}
-
-/*
- *
- */
-char *ide_media_verbose (ide_drive_t *drive)
-{
-	switch (drive->media) {
-		case ide_scsi:		return("scsi   ");
-		case ide_disk:		return("disk   ");
-		case ide_optical:	return("optical");
-		case ide_cdrom:		return("cdrom  ");
-		case ide_tape:		return("tape   ");
-		case ide_floppy:	return("floppy ");
-		default:		return("???????");
-	}
-}
-
-/*
- * A Verbose noise maker for debugging on the attempted dmaing calls.
- */
-char *ide_dmafunc_verbose (ide_dma_action_t dmafunc)
-{
-	switch (dmafunc) {
-		case ide_dma_read:		return("ide_dma_read");
-		case ide_dma_write:		return("ide_dma_write");
-		case ide_dma_begin:		return("ide_dma_begin");
-		case ide_dma_end:		return("ide_dma_end:");
-		case ide_dma_check:		return("ide_dma_check");
-		case ide_dma_on:		return("ide_dma_on");
-		case ide_dma_off:		return("ide_dma_off");
-		case ide_dma_off_quietly:	return("ide_dma_off_quietly");
-		case ide_dma_test_irq:		return("ide_dma_test_irq");
-		case ide_dma_bad_drive:		return("ide_dma_bad_drive");
-		case ide_dma_good_drive:	return("ide_dma_good_drive");
-		case ide_dma_verbose:		return("ide_dma_verbose");
-		case ide_dma_retune:		return("ide_dma_retune");
-		case ide_dma_lostirq:		return("ide_dma_lostirq");
-		case ide_dma_timeout:		return("ide_dma_timeout");
-		default:			return("unknown");
-	}
-}
-
-/*
- *
- */
-byte ide_auto_reduce_xfer (ide_drive_t *drive)
-{
-	if (!drive->crc_count)
-		return drive->current_speed;
-	drive->crc_count = 0;
-
-	switch(drive->current_speed) {
-		case XFER_UDMA_7:	return XFER_UDMA_6;
-		case XFER_UDMA_6:	return XFER_UDMA_5;
-		case XFER_UDMA_5:	return XFER_UDMA_4;
-		case XFER_UDMA_4:	return XFER_UDMA_3;
-		case XFER_UDMA_3:	return XFER_UDMA_2;
-		case XFER_UDMA_2:	return XFER_UDMA_1;
-		case XFER_UDMA_1:	return XFER_UDMA_0;
-			/*
-			 * OOPS we do not goto non Ultra DMA modes
-			 * without iCRC's available we force
-			 * the system to PIO and make the user
-			 * invoke the ATA-1 ATA-2 DMA modes.
-			 */
-		case XFER_UDMA_0:
-		default:		return XFER_PIO_4;
-	}
-}
-
-/*
- * Update the 
- */
-int ide_driveid_update (ide_drive_t *drive)
-{
-	/*
-	 * Re-read drive->id for possible DMA mode
-	 * change (copied from ide-probe.c)
-	 */
-	struct hd_driveid *id;
-	unsigned long timeout, flags;
-
-	SELECT_MASK(HWIF(drive), drive, 1);
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
-	ide_delay_50ms();
-	OUT_BYTE(WIN_IDENTIFY, IDE_COMMAND_REG);
-	timeout = jiffies + WAIT_WORSTCASE;
-	do {
-		if (0 < (signed long)(jiffies - timeout)) {
-			SELECT_MASK(HWIF(drive), drive, 0);
-			return 0;	/* drive timed-out */
-		}
-		ide_delay_50ms();	/* give drive a breather */
-	} while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT);
-	ide_delay_50ms();	/* wait for IRQ and DRQ_STAT */
-	if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
-		SELECT_MASK(HWIF(drive), drive, 0);
-		printk("%s: CHECK for good STATUS\n", drive->name);
-		return 0;
-	}
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only; some systems need this */
-	SELECT_MASK(HWIF(drive), drive, 0);
-	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
-	if (!id) {
-		__restore_flags(flags);	/* local CPU only */
-		return 0;
-	}
-	ide_input_data(drive, id, SECTOR_WORDS);
-	(void) GET_STAT();	/* clear drive IRQ */
-	ide__sti();		/* local CPU only */
-	__restore_flags(flags);	/* local CPU only */
-	ide_fix_driveid(id);
-	if (id) {
-		drive->id->dma_ultra = id->dma_ultra;
-		drive->id->dma_mword = id->dma_mword;
-		drive->id->dma_1word = id->dma_1word;
-		/* anything more ? */
-		kfree(id);
-	}
-
-	return 1;
-}
-
-/*
- * Verify that we are doing an approved SETFEATURES_XFER with respect
- * to the hardware being able to support request.  Since some hardware
- * can improperly report capabilties, we check to see if the host adapter
- * in combination with the device (usually a disk) properly detect
- * and acknowledge each end of the ribbon.
- */
-int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
-{
-	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
-	    (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
-	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
-		if (!HWIF(drive)->udma_four) {
-			printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", HWIF(drive)->name);
-			return 1;
-		}
-#ifndef CONFIG_IDEDMA_IVB
-		if ((drive->id->hw_config & 0x6000) == 0) {
-#else /* !CONFIG_IDEDMA_IVB */
-		if (((drive->id->hw_config & 0x2000) == 0) ||
-		    ((drive->id->hw_config & 0x4000) == 0)) {
-#endif /* CONFIG_IDEDMA_IVB */
-			printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", drive->name);
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- * Backside of HDIO_DRIVE_CMD call of SETFEATURES_XFER.
- * 1 : Safe to update drive->id DMA registers.
- * 0 : OOPs not allowed.
- */
-int set_transfer (ide_drive_t *drive, ide_task_t *args)
-{
-	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
-	    (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) &&
-	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) &&
-	    (drive->id->dma_ultra ||
-	     drive->id->dma_mword ||
-	     drive->id->dma_1word))
-		return 1;
-
-	return 0;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- *  All hosts that use the 80c ribbon mus use!
- */
-byte eighty_ninty_three (ide_drive_t *drive)
-{
-#ifdef CONFIG_BLK_DEV_IDEPCI
-	if (HWIF(drive)->pci_devid.vid==0x105a)
-	    return(HWIF(drive)->udma_four);
-#endif
-	/* PDC202XX: that's because some HDD will return wrong info */
-	return ((byte) ((HWIF(drive)->udma_four) &&
-#ifndef CONFIG_IDEDMA_IVB
-			(drive->id->hw_config & 0x4000) &&
-#endif /* CONFIG_IDEDMA_IVB */
-			(drive->id->hw_config & 0x6000)) ? 1 : 0);
-}
-#endif // CONFIG_BLK_DEV_IDEDMA
-
-/*
- * Similar to ide_wait_stat(), except it never calls ide_error internally.
- * This is a kludge to handle the new ide_config_drive_speed() function,
- * and should not otherwise be used anywhere.  Eventually, the tuneproc's
- * should be updated to return ide_startstop_t, in which case we can get
- * rid of this abomination again.  :)   -ml
- *
- * It is gone..........
- *
- * const char *msg == consider adding for verbose errors.
- */
-int ide_config_drive_speed (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	int	i, error = 1;
-	byte stat;
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
-	byte unit = (drive->select.b.unit & 0x01);
-	outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2);
-#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
-
-	/*
-	 * Don't use ide_wait_cmd here - it will
-	 * attempt to set_geometry and recalibrate,
-	 * but for some reason these don't work at
-	 * this point (lost interrupt).
-	 */
-        /*
-         * Select the drive, and issue the SETFEATURES command
-         */
-	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
-	udelay(1);
-	SELECT_DRIVE(HWIF(drive), drive);
-	SELECT_MASK(HWIF(drive), drive, 0);
-	udelay(1);
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
-	OUT_BYTE(speed, IDE_NSECTOR_REG);
-	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
-	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
-	if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
-		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
-	udelay(1);
-	/*
-	 * Wait for drive to become non-BUSY
-	 */
-	if ((stat = GET_STAT()) & BUSY_STAT) {
-		unsigned long flags, timeout;
-		__save_flags(flags);	/* local CPU only */
-		ide__sti();		/* local CPU only -- for jiffies */
-		timeout = jiffies + WAIT_CMD;
-		while ((stat = GET_STAT()) & BUSY_STAT) {
-			if (0 < (signed long)(jiffies - timeout))
-				break;
-		}
-		__restore_flags(flags); /* local CPU only */
-	}
-
-	/*
-	 * Allow status to settle, then read it again.
-	 * A few rare drives vastly violate the 400ns spec here,
-	 * so we'll wait up to 10usec for a "good" status
-	 * rather than expensively fail things immediately.
-	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
-	 */
-	for (i = 0; i < 10; i++) {
-		udelay(1);
-		if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
-			error = 0;
-			break;
-		}
-	}
-
-	SELECT_MASK(HWIF(drive), drive, 0);
-
-	enable_irq(hwif->irq);
-
-	if (error) {
-		(void) ide_dump_status(drive, "set_drive_speed_status", stat);
-		return error;
-	}
-
-	drive->id->dma_ultra &= ~0xFF00;
-	drive->id->dma_mword &= ~0x0F00;
-	drive->id->dma_1word &= ~0x0F00;
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
-	if (speed > XFER_PIO_4) {
-		outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2);
-	} else {
-		outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2);
-	}
-#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
-
-	switch(speed) {
-		case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
-		case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
-		case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
-		case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
-		case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
-		case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
-		case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
-		case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
-		case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
-		case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
-		case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
-		case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
-		case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
-		case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
-		default: break;
-	}
-	return error;
-}
-
-EXPORT_SYMBOL(ide_auto_reduce_xfer);
-EXPORT_SYMBOL(ide_driveid_update);
-EXPORT_SYMBOL(ide_ata66_check);
-EXPORT_SYMBOL(set_transfer);
-#ifdef CONFIG_BLK_DEV_IDEDMA
-EXPORT_SYMBOL(eighty_ninty_three);
-#endif // CONFIG_BLK_DEV_IDEDMA
-EXPORT_SYMBOL(ide_config_drive_speed);
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-floppy.c linux-2.4.21/drivers/ide/ide-floppy.c
--- linux-2.4.20/drivers/ide/ide-floppy.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-floppy.c	2002-12-18 18:58:05.000000000 +0000
@@ -153,10 +153,10 @@
 	char *b_data;				/* Pointer which runs on the buffers */
 	int b_count;				/* Missing/Available data on the current buffer */
 	struct request *rq;			/* The corresponding request */
-	byte *buffer;				/* Data buffer */
-	byte *current_position;			/* Pointer into the above buffer */
+	u8 *buffer;				/* Data buffer */
+	u8 *current_position;			/* Pointer into the above buffer */
 	void (*callback) (ide_drive_t *);	/* Called when this packet command is completed */
-	byte pc_buffer[IDEFLOPPY_PC_BUFFER_SIZE];	/* Temporary buffer */
+	u8 pc_buffer[IDEFLOPPY_PC_BUFFER_SIZE];	/* Temporary buffer */
 	unsigned long flags;			/* Status/Action bit flags: long for set_bit */
 } idefloppy_pc_t;
 
@@ -272,29 +272,41 @@
 typedef struct {
 	ide_drive_t *drive;
 
-	idefloppy_pc_t *pc;			/* Current packet command */
-	idefloppy_pc_t *failed_pc; 		/* Last failed packet command */
-	idefloppy_pc_t pc_stack[IDEFLOPPY_PC_STACK];/* Packet command stack */
-	int pc_stack_index;			/* Next free packet command storage space */
+	/* Current packet command */
+	idefloppy_pc_t *pc;
+	/* Last failed packet command */
+	idefloppy_pc_t *failed_pc;
+	/* Packet command stack */
+	idefloppy_pc_t pc_stack[IDEFLOPPY_PC_STACK];
+	/* Next free packet command storage space */
+	int pc_stack_index;
 	struct request rq_stack[IDEFLOPPY_PC_STACK];
-	int rq_stack_index;			/* We implement a circular array */
+	/* We implement a circular array */
+	int rq_stack_index;
 
 	/*
 	 *	Last error information
 	 */
-	byte sense_key, asc, ascq;
-	byte ticks;		/* delay this long before sending packet command */
+	u8 sense_key, asc, ascq;
+	/* delay this long before sending packet command */
+	u8 ticks;
 	int progress_indication;
 
 	/*
 	 *	Device information
 	 */
-	int blocks, block_size, bs_factor;			/* Current format */
-	idefloppy_capacity_descriptor_t capacity;		/* Last format capacity */
-	idefloppy_flexible_disk_page_t flexible_disk_page;	/* Copy of the flexible disk page */
-	int wp;							/* Write protect */
-	int srfp;			/* Supports format progress report */
-	unsigned long flags;			/* Status/Action flags */
+	/* Current format */
+	int blocks, block_size, bs_factor;
+	/* Last format capacity */
+	idefloppy_capacity_descriptor_t capacity;
+	/* Copy of the flexible disk page */
+	idefloppy_flexible_disk_page_t flexible_disk_page;
+	/* Write protect */
+	int wp;
+	/* Supports format progress report */
+	int srfp;
+	/* Status/Action flags */
+	unsigned long flags;
 } idefloppy_floppy_t;
 
 #define IDEFLOPPY_TICKS_DELAY	3	/* default delay for ZIP 100 */
@@ -349,20 +361,20 @@
 /*
  *	Special requests for our block device strategy routine.
  */
-#define	IDEFLOPPY_FIRST_RQ		90
+#define	IDEFLOPPY_FIRST_RQ	90
 
 /*
  * 	IDEFLOPPY_PC_RQ is used to queue a packet command in the request queue.
  */
-#define	IDEFLOPPY_PC_RQ			90
+#define	IDEFLOPPY_PC_RQ		90
 
-#define IDEFLOPPY_LAST_RQ		90
+#define IDEFLOPPY_LAST_RQ	90
 
 /*
  *	A macro which can be used to check if a given request command
  *	originated in the driver or in the buffer cache layer.
  */
-#define IDEFLOPPY_RQ_CMD(cmd) 		((cmd >= IDEFLOPPY_FIRST_RQ) && (cmd <= IDEFLOPPY_LAST_RQ))
+#define IDEFLOPPY_RQ_CMD(cmd) 	((cmd >= IDEFLOPPY_FIRST_RQ) && (cmd <= IDEFLOPPY_LAST_RQ))
 
 /*
  *	Error codes which are returned in rq->errors to the higher part
@@ -371,170 +383,6 @@
 #define	IDEFLOPPY_ERROR_GENERAL		101
 
 /*
- *	The ATAPI Status Register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned check		:1;	/* Error occurred */
-		unsigned idx		:1;	/* Reserved */
-		unsigned corr		:1;	/* Correctable error occurred */
-		unsigned drq		:1;	/* Data is request by the device */
-		unsigned dsc		:1;	/* Media access command finished */
-		unsigned reserved5	:1;	/* Reserved */
-		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
-		unsigned bsy		:1;	/* The device has access to the command block */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned bsy		:1;	/* The device has access to the command block */
-		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
-		unsigned reserved5	:1;	/* Reserved */
-		unsigned dsc		:1;	/* Media access command finished */
-		unsigned drq		:1;	/* Data is request by the device */
-		unsigned corr		:1;	/* Correctable error occurred */
-		unsigned idx		:1;	/* Reserved */
-		unsigned check		:1;	/* Error occurred */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_status_reg_t;
-
-/*
- *	The ATAPI error register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned ili		:1;	/* Illegal Length Indication */
-		unsigned eom		:1;	/* End Of Media Detected */
-		unsigned abrt		:1;	/* Aborted command - As defined by ATA */
-		unsigned mcr		:1;	/* Media Change Requested - As defined by ATA */
-		unsigned sense_key	:4;	/* Sense key of the last failed packet command */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned sense_key	:4;	/* Sense key of the last failed packet command */
-		unsigned mcr		:1;	/* Media Change Requested - As defined by ATA */
-		unsigned abrt		:1;	/* Aborted command - As defined by ATA */
-		unsigned eom		:1;	/* End Of Media Detected */
-		unsigned ili		:1;	/* Illegal Length Indication */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_error_reg_t;
-
-/*
- *	ATAPI Feature Register
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned dma		:1;	/* Using DMA or PIO */
-		unsigned reserved321	:3;	/* Reserved */
-		unsigned reserved654	:3;	/* Reserved (Tag Type) */
-		unsigned reserved7	:1;	/* Reserved */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned reserved7	:1;	/* Reserved */
-		unsigned reserved654	:3;	/* Reserved (Tag Type) */
-		unsigned reserved321	:3;	/* Reserved */
-		unsigned dma		:1;	/* Using DMA or PIO */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_feature_reg_t;
-
-/*
- *	ATAPI Byte Count Register.
- */
-typedef union {
-	unsigned all			:16;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned low		:8;	/* LSB */
-		unsigned high		:8;	/* MSB */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned high		:8;	/* MSB */
-		unsigned low		:8;	/* LSB */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_bcount_reg_t;
-
-/*
- *	ATAPI Interrupt Reason Register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
-		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
-		unsigned reserved	:6;	/* Reserved */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned reserved	:6;	/* Reserved */
-		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
-		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_ireason_reg_t;
-
-/*
- *	ATAPI floppy Drive Select Register
- */
-typedef union {	
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned sam_lun	:3;	/* Logical unit number */
-		unsigned reserved3	:1;	/* Reserved */
-		unsigned drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
-		unsigned one5		:1;	/* Should be set to 1 */
-		unsigned reserved6	:1;	/* Reserved */
-		unsigned one7		:1;	/* Should be set to 1 */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned one7		:1;	/* Should be set to 1 */
-		unsigned reserved6	:1;	/* Reserved */
-		unsigned one5		:1;	/* Should be set to 1 */
-		unsigned drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
-		unsigned reserved3	:1;	/* Reserved */
-		unsigned sam_lun	:3;	/* Logical unit number */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_drivesel_reg_t;
-
-/*
- *	ATAPI Device Control Register
- */
-typedef union {			
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned zero0		:1;	/* Should be set to zero */
-		unsigned nien		:1;	/* Device interrupt is disabled (1) or enabled (0) */
-		unsigned srst		:1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
-		unsigned one3		:1;	/* Should be set to 1 */
-		unsigned reserved4567	:4;	/* Reserved */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned reserved4567	:4;	/* Reserved */
-		unsigned one3		:1;	/* Should be set to 1 */
-		unsigned srst		:1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
-		unsigned nien		:1;	/* Device interrupt is disabled (1) or enabled (0) */
-		unsigned zero0		:1;	/* Should be set to zero */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_control_reg_t;
-
-/*
  *	The following is used to format the general configuration word of
  *	the ATAPI IDENTIFY DEVICE command.
  */
@@ -668,32 +516,61 @@
 static void idefloppy_discard_data (ide_drive_t *drive, unsigned int bcount)
 {
 	while (bcount--)
-		IN_BYTE (IDE_DATA_REG);
+		(void) HWIF(drive)->INB(IDE_DATA_REG);
 }
 
 #if IDEFLOPPY_DEBUG_BUGS
 static void idefloppy_write_zeros (ide_drive_t *drive, unsigned int bcount)
 {
 	while (bcount--)
-		OUT_BYTE (0, IDE_DATA_REG);
+		HWIF(drive)->OUTB(0, IDE_DATA_REG);
 }
 #endif /* IDEFLOPPY_DEBUG_BUGS */
 
+
+static int idefloppy_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		add_blkdev_randomness(MAJOR(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return ret;
+}
+
 /*
- *	idefloppy_end_request is used to finish servicing a request.
+ *	idefloppy_do_end_request is used to finish servicing a request.
  *
  *	For read/write requests, we will call ide_end_request to pass to the
  *	next buffer.
  */
-static void idefloppy_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
+static int idefloppy_do_end_request (ide_drive_t *drive, int uptodate)
 {
-	ide_drive_t *drive = hwgroup->drive;
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	struct request *rq = hwgroup->rq;
+	struct request *rq = HWGROUP(drive)->rq;
 	int error;
 
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "Reached idefloppy_end_request\n");
+	printk(KERN_INFO "Reached idefloppy_end_request\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
 	switch (uptodate) {
@@ -705,13 +582,16 @@
 		floppy->failed_pc = NULL;
 	/* Why does this happen? */
 	if (!rq)
-		return;
-	if (!IDEFLOPPY_RQ_CMD (rq->cmd)) {
-		ide_end_request (uptodate, hwgroup);
-		return;
+		return 0;
+	if (!IDEFLOPPY_RQ_CMD(rq->cmd)) {
+		/* our real local end request function */
+		idefloppy_end_request(drive, uptodate);
+		return 0;
 	}
 	rq->errors = error;
-	ide_end_drive_cmd (drive, 0, 0);
+	/* fixme: need to move this local also */
+	ide_end_drive_cmd(drive, 0, 0);
+	return 0;
 }
 
 static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount)
@@ -724,18 +604,21 @@
 		if (pc->b_count == bh->b_size) {
 			rq->sector += rq->current_nr_sectors;
 			rq->nr_sectors -= rq->current_nr_sectors;
-			idefloppy_end_request (1, HWGROUP(drive));
+			idefloppy_do_end_request(drive, 1);
 			if ((bh = rq->bh) != NULL)
 				pc->b_count = 0;
 		}
 		if (bh == NULL) {
-			printk (KERN_ERR "%s: bh == NULL in idefloppy_input_buffers, bcount == %d\n", drive->name, bcount);
-			idefloppy_discard_data (drive, bcount);
+			printk(KERN_ERR "%s: bh == NULL in "
+				"idefloppy_input_buffers, bcount == %d\n",
+				drive->name, bcount);
+			idefloppy_discard_data(drive, bcount);
 			return;
 		}
-		count = IDEFLOPPY_MIN (bh->b_size - pc->b_count, bcount);
-		atapi_input_bytes (drive, bh->b_data + pc->b_count, count);
-		bcount -= count; pc->b_count += count;
+		count = IDEFLOPPY_MIN(bh->b_size - pc->b_count, bcount);
+		HWIF(drive)->atapi_input_bytes(drive, bh->b_data + pc->b_count, count);
+		bcount -= count;
+		pc->b_count += count;
 	}
 }
 
@@ -749,20 +632,24 @@
 		if (!pc->b_count) {
 			rq->sector += rq->current_nr_sectors;
 			rq->nr_sectors -= rq->current_nr_sectors;
-			idefloppy_end_request (1, HWGROUP(drive));
+			idefloppy_do_end_request(drive, 1);
 			if ((bh = rq->bh) != NULL) {
 				pc->b_data = bh->b_data;
 				pc->b_count = bh->b_size;
 			}
 		}
 		if (bh == NULL) {
-			printk (KERN_ERR "%s: bh == NULL in idefloppy_output_buffers, bcount == %d\n", drive->name, bcount);
+			printk(KERN_ERR "%s: bh == NULL in "
+				"idefloppy_output_buffers, bcount == %d\n",
+				drive->name, bcount);
 			idefloppy_write_zeros (drive, bcount);
 			return;
 		}
-		count = IDEFLOPPY_MIN (pc->b_count, bcount);
-		atapi_output_bytes (drive, pc->b_data, count);
-		bcount -= count; pc->b_data += count; pc->b_count -= count;
+		count = IDEFLOPPY_MIN(pc->b_count, bcount);
+		HWIF(drive)->atapi_output_bytes(drive, pc->b_data, count);
+		bcount -= count;
+		pc->b_data += count;
+		pc->b_count -= count;
 	}
 }
 
@@ -773,7 +660,7 @@
 	struct buffer_head *bh = rq->bh;
 
 	while ((bh = rq->bh) != NULL)
-		idefloppy_end_request (1, HWGROUP(drive));
+		idefloppy_do_end_request(drive, 1);
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
@@ -784,17 +671,17 @@
  */
 static void idefloppy_queue_pc_head (ide_drive_t *drive,idefloppy_pc_t *pc,struct request *rq)
 {
-	ide_init_drive_cmd (rq);
-	rq->buffer = (char *) pc;
+	ide_init_drive_cmd(rq);
+	rq->buffer = (char *)pc;
 	rq->cmd = IDEFLOPPY_PC_RQ;
-	(void) ide_do_drive_cmd (drive, rq, ide_preempt);
+	(void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
 static idefloppy_pc_t *idefloppy_next_pc_storage (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	if (floppy->pc_stack_index==IDEFLOPPY_PC_STACK)
+	if (floppy->pc_stack_index == IDEFLOPPY_PC_STACK)
 		floppy->pc_stack_index=0;
 	return (&floppy->pc_stack[floppy->pc_stack_index++]);
 }
@@ -803,8 +690,8 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	if (floppy->rq_stack_index==IDEFLOPPY_PC_STACK)
-		floppy->rq_stack_index=0;
+	if (floppy->rq_stack_index == IDEFLOPPY_PC_STACK)
+		floppy->rq_stack_index = 0;
 	return (&floppy->rq_stack[floppy->rq_stack_index++]);
 }
 
@@ -816,14 +703,20 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	floppy->sense_key = result->sense_key; floppy->asc = result->asc; floppy->ascq = result->ascq;
-	floppy->progress_indication= result->sksv[0] & 0x80 ?
-		(unsigned short)get_unaligned((u16 *)(result->sksv+1)):0x10000;
+	floppy->sense_key = result->sense_key;
+	floppy->asc = result->asc;
+	floppy->ascq = result->ascq;
+	floppy->progress_indication = result->sksv[0] & 0x80 ?
+		(u16)get_unaligned((u16 *)(result->sksv+1)):0x10000;
 #if IDEFLOPPY_DEBUG_LOG
 	if (floppy->failed_pc)
-		printk (KERN_INFO "ide-floppy: pc = %x, sense key = %x, asc = %x, ascq = %x\n",floppy->failed_pc->c[0],result->sense_key,result->asc,result->ascq);
+		printk(KERN_INFO "ide-floppy: pc = %x, sense key = %x, "
+			"asc = %x, ascq = %x\n", floppy->failed_pc->c[0],
+			result->sense_key, result->asc, result->ascq);
 	else
-		printk (KERN_INFO "ide-floppy: sense key = %x, asc = %x, ascq = %x\n",result->sense_key,result->asc,result->ascq);
+		printk(KERN_INFO "ide-floppy: sense key = %x, asc = %x, "
+			"ascq = %x\n", result->sense_key,
+			result->asc, result->ascq);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 }
 
@@ -832,14 +725,14 @@
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "ide-floppy: Reached idefloppy_request_sense_callback\n");
+	printk(KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 	if (!floppy->pc->error) {
-		idefloppy_analyze_error (drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer);
-		idefloppy_end_request (1,HWGROUP (drive));
+		idefloppy_analyze_error(drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer);
+		idefloppy_do_end_request(drive, 1);
 	} else {
-		printk (KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
-		idefloppy_end_request (0,HWGROUP (drive));
+		printk(KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
+		idefloppy_do_end_request(drive, 0);
 	}
 }
 
@@ -851,10 +744,10 @@
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "ide-floppy: Reached idefloppy_pc_callback\n");
+	printk (KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_end_request (floppy->pc->error ? 0:1, HWGROUP(drive));
+	idefloppy_do_end_request(drive, floppy->pc->error ? 0 : 1);
 }
 
 /*
@@ -862,7 +755,7 @@
  */
 static void idefloppy_init_pc (idefloppy_pc_t *pc)
 {
-	memset (pc->c, 0, 12);
+	memset(pc->c, 0, 12);
 	pc->retries = 0;
 	pc->flags = 0;
 	pc->request_transfer = 0;
@@ -874,7 +767,7 @@
 
 static void idefloppy_create_request_sense_cmd (idefloppy_pc_t *pc)
 {
-	idefloppy_init_pc (pc);	
+	idefloppy_init_pc(pc);	
 	pc->c[0] = IDEFLOPPY_REQUEST_SENSE_CMD;
 	pc->c[4] = 255;
 	pc->request_transfer = 18;
@@ -890,13 +783,13 @@
 {
 	idefloppy_pc_t *pc;
 	struct request *rq;
-	idefloppy_error_reg_t error;
+	atapi_error_t error;
 
-	error.all = IN_BYTE (IDE_ERROR_REG);
-	pc = idefloppy_next_pc_storage (drive);
-	rq = idefloppy_next_rq_storage (drive);
-	idefloppy_create_request_sense_cmd (pc);
-	idefloppy_queue_pc_head (drive, pc, rq);
+	error.all = HWIF(drive)->INB(IDE_ERROR_REG);
+	pc = idefloppy_next_pc_storage(drive);
+	rq = idefloppy_next_rq_storage(drive);
+	idefloppy_create_request_sense_cmd(pc);
+	idefloppy_queue_pc_head(drive, pc, rq);
 }
 
 /*
@@ -906,24 +799,25 @@
 static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_status_reg_t status;
-	idefloppy_bcount_reg_t bcount;
-	idefloppy_ireason_reg_t ireason;
-	idefloppy_pc_t *pc=floppy->pc;
+	atapi_status_t status;
+	atapi_bcount_t bcount;
+	atapi_ireason_t ireason;
+	idefloppy_pc_t *pc = floppy->pc;
 	struct request *rq = pc->rq;
 	unsigned int temp;
 
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "ide-floppy: Reached idefloppy_pc_intr interrupt handler\n");
+	printk(KERN_INFO "ide-floppy: Reached %s interrupt handler\n",
+		__FUNCTION__);
 #endif /* IDEFLOPPY_DEBUG_LOG */	
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
-			set_bit (PC_DMA_ERROR, &pc->flags);
+	if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+		if (HWIF(drive)->ide_dma_end(drive)) {
+			set_bit(PC_DMA_ERROR, &pc->flags);
 		} else {
-			pc->actually_transferred=pc->request_transfer;
-			idefloppy_update_buffers (drive, pc);
+			pc->actually_transferred = pc->request_transfer;
+			idefloppy_update_buffers(drive, pc);
 		}
 #if IDEFLOPPY_DEBUG_LOG
 		printk (KERN_INFO "ide-floppy: DMA finished\n");
@@ -931,83 +825,116 @@
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	status.all = GET_STAT();					/* Clear the interrupt */
+	/* Clear the interrupt */
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 
-	if (!status.b.drq) {						/* No more interrupts */
+	if (!status.b.drq) {			/* No more interrupts */
 #if IDEFLOPPY_DEBUG_LOG
-		printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
+		printk(KERN_INFO "Packet command completed, %d bytes "
+			"transferred\n", pc->actually_transferred);
 #endif /* IDEFLOPPY_DEBUG_LOG */
-		clear_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
 
-		ide__sti();	/* local CPU only */
+		local_irq_enable();
 
-		if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) {	/* Error detected */
+		if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {
+			/* Error detected */
 #if IDEFLOPPY_DEBUG_LOG
-			printk (KERN_INFO "ide-floppy: %s: I/O error\n",drive->name);
+			printk(KERN_INFO "ide-floppy: %s: I/O error\n",
+				drive->name);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 			rq->errors++;
 			if (pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
-				printk (KERN_ERR "ide-floppy: I/O error in request sense command\n");
-				return ide_do_reset (drive);
+				printk(KERN_ERR "ide-floppy: I/O error in "
+					"request sense command\n");
+				return ide_do_reset(drive);
 			}
-			idefloppy_retry_pc (drive);				/* Retry operation */
-			return ide_stopped; /* queued, but not started */
+			/* Retry operation */
+			idefloppy_retry_pc(drive);
+			/* queued, but not started */
+			return ide_stopped;
 		}
 		pc->error = 0;
 		if (floppy->failed_pc == pc)
-			floppy->failed_pc=NULL;
-		pc->callback(drive);			/* Command finished - Call the callback function */
+			floppy->failed_pc = NULL;
+		/* Command finished - Call the callback function */
+		pc->callback(drive);
 		return ide_stopped;
 	}
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n");
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-		return ide_do_reset (drive);
+	if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+		printk(KERN_ERR "ide-floppy: The floppy wants to issue "
+			"more interrupts in DMA mode\n");
+		(void) HWIF(drive)->ide_dma_off(drive);
+		return ide_do_reset(drive);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
-	bcount.b.high=IN_BYTE (IDE_BCOUNTH_REG);			/* Get the number of bytes to transfer */
-	bcount.b.low=IN_BYTE (IDE_BCOUNTL_REG);			/* on this interrupt */
-	ireason.all=IN_BYTE (IDE_IREASON_REG);
+	/* Get the number of bytes to transfer */
+	bcount.b.high = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+	bcount.b.low = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	/* on this interrupt */
+	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
 
 	if (ireason.b.cod) {
-		printk (KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n");
-		return ide_do_reset (drive);
+		printk(KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n");
+		return ide_do_reset(drive);
 	}
-	if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) {	/* Hopefully, we will never get here */
-		printk (KERN_ERR "ide-floppy: We wanted to %s, ", ireason.b.io ? "Write":"Read");
-		printk (KERN_ERR "but the floppy wants us to %s !\n",ireason.b.io ? "Read":"Write");
-		return ide_do_reset (drive);
+	if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {
+		/* Hopefully, we will never get here */
+		printk(KERN_ERR "ide-floppy: We wanted to %s, ",
+			ireason.b.io ? "Write":"Read");
+		printk(KERN_ERR "but the floppy wants us to %s !\n",
+			ireason.b.io ? "Read":"Write");
+		return ide_do_reset(drive);
 	}
-	if (!test_bit (PC_WRITING, &pc->flags)) {			/* Reading - Check that we have enough space */
+	if (!test_bit(PC_WRITING, &pc->flags)) {
+		/* Reading - Check that we have enough space */
 		temp = pc->actually_transferred + bcount.all;
-		if ( temp > pc->request_transfer) {
+		if (temp > pc->request_transfer) {
 			if (temp > pc->buffer_size) {
-				printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n");
-				idefloppy_discard_data (drive,bcount.all);
-				ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);
+				printk(KERN_ERR "ide-floppy: The floppy wants "
+					"to send us more data than expected "
+					"- discarding data\n");
+				idefloppy_discard_data(drive,bcount.all);
+				if (HWGROUP(drive)->handler != NULL)
+					BUG();
+				ide_set_handler(drive,
+						&idefloppy_pc_intr,
+						IDEFLOPPY_WAIT_CMD,
+						NULL);
 				return ide_started;
 			}
 #if IDEFLOPPY_DEBUG_LOG
-			printk (KERN_NOTICE "ide-floppy: The floppy wants to send us more data than expected - allowing transfer\n");
+			printk(KERN_NOTICE "ide-floppy: The floppy wants to "
+				"send us more data than expected - "
+				"allowing transfer\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 		}
 	}
-	if (test_bit (PC_WRITING, &pc->flags)) {
+	if (test_bit(PC_WRITING, &pc->flags)) {
 		if (pc->buffer != NULL)
-			atapi_output_bytes (drive,pc->current_position,bcount.all);	/* Write the current buffer */
+			/* Write the current buffer */
+			HWIF(drive)->atapi_output_bytes(drive,
+						pc->current_position,
+						bcount.all);
 		else
-			idefloppy_output_buffers (drive, pc, bcount.all);
+			idefloppy_output_buffers(drive, pc, bcount.all);
 	} else {
 		if (pc->buffer != NULL)
-			atapi_input_bytes (drive,pc->current_position,bcount.all);	/* Read the current buffer */
+			/* Read the current buffer */
+			HWIF(drive)->atapi_input_bytes(drive,
+						pc->current_position,
+						bcount.all);
 		else
-			idefloppy_input_buffers (drive, pc, bcount.all);
+			idefloppy_input_buffers(drive, pc, bcount.all);
 	}
-	pc->actually_transferred+=bcount.all;				/* Update the current position */
-	pc->current_position+=bcount.all;
-
-	ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
+	/* Update the current position */
+	pc->actually_transferred += bcount.all;
+	pc->current_position += bcount.all;
+
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
 	return ide_started;
 }
 
@@ -1020,19 +947,25 @@
 {
 	ide_startstop_t startstop;
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_ireason_reg_t ireason;
+	atapi_ireason_t ireason;
 
-	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
-		printk (KERN_ERR "ide-floppy: Strange, packet command initiated yet DRQ isn't asserted\n");
+	if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
+		printk(KERN_ERR "ide-floppy: Strange, packet command "
+				"initiated yet DRQ isn't asserted\n");
 		return startstop;
 	}
-	ireason.all=IN_BYTE (IDE_IREASON_REG);
+	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
 	if (!ireason.b.cod || ireason.b.io) {
-		printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
-		return ide_do_reset (drive);
-	}
-	ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);	/* Set the interrupt routine */
-	atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
+		printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while "
+				"issuing a packet command\n");
+		return ide_do_reset(drive);
+	}
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	/* Set the interrupt routine */
+	ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);
+	/* Send the actual packet */
+	HWIF(drive)->atapi_output_bytes(drive, floppy->pc->c, 12);
 	return ide_started;
 }
 
@@ -1053,35 +986,42 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
-	return IDEFLOPPY_WAIT_CMD;		/* Timeout for the packet command */
+	/* Send the actual packet */
+	HWIF(drive)->atapi_output_bytes(drive, floppy->pc->c, 12);
+	/* Timeout for the packet command */
+	return IDEFLOPPY_WAIT_CMD;
 }
 
 static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	ide_startstop_t startstop;
-	idefloppy_ireason_reg_t ireason;
+	atapi_ireason_t ireason;
 
-	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
-		printk (KERN_ERR "ide-floppy: Strange, packet command initiated yet DRQ isn't asserted\n");
+	if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
+		printk(KERN_ERR "ide-floppy: Strange, packet command "
+				"initiated yet DRQ isn't asserted\n");
 		return startstop;
 	}
-	ireason.all=IN_BYTE (IDE_IREASON_REG);
+	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
 	if (!ireason.b.cod || ireason.b.io) {
-		printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
-		return ide_do_reset (drive);
+		printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) "
+				"while issuing a packet command\n");
+		return ide_do_reset(drive);
 	}
 	/* 
-	 * The following delay solves a problem with ATAPI Zip 100 drives where the
-	 * Busy flag was apparently being deasserted before the unit was ready to
-	 * receive data. This was happening on a 1200 MHz Athlon system. 10/26/01
-	 * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will 
-	 * not be actually used until after the packet is moved in about 50 msec.
+	 * The following delay solves a problem with ATAPI Zip 100 drives
+	 * where the Busy flag was apparently being deasserted before the
+	 * unit was ready to receive data. This was happening on a
+	 * 1200 MHz Athlon system. 10/26/01 25msec is too short,
+	 * 40 and 50msec work well. idefloppy_pc_intr will not be actually
+	 * used until after the packet is moved in about 50 msec.
 	 */
-	ide_set_handler (drive, 
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, 
 	  &idefloppy_pc_intr, 		/* service routine for packet command */
-	  floppy->ticks,			/* wait this long before "failing" */
+	  floppy->ticks,		/* wait this long before "failing" */
 	  &idefloppy_transfer_pc2);	/* fail == transfer_pc2 */
 	return ide_started;
 }
@@ -1092,81 +1032,109 @@
 static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_bcount_reg_t bcount;
-	int dma_ok = 0;
+	atapi_feature_t feature;
+	atapi_bcount_t bcount;
 	ide_handler_t *pkt_xfer_routine;
 
 #if IDEFLOPPY_DEBUG_BUGS
-	if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD && pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
-		printk (KERN_ERR "ide-floppy: possible ide-floppy.c bug - Two request sense in serial were issued\n");
+	if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD &&
+	    pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
+		printk(KERN_ERR "ide-floppy: possible ide-floppy.c bug - "
+			"Two request sense in serial were issued\n");
 	}
 #endif /* IDEFLOPPY_DEBUG_BUGS */
 
-	if (floppy->failed_pc == NULL && pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD)
-		floppy->failed_pc=pc;
-	floppy->pc=pc;							/* Set the current packet command */
+	if (floppy->failed_pc == NULL &&
+	    pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD)
+		floppy->failed_pc = pc;
+	/* Set the current packet command */
+	floppy->pc = pc;
 
-	if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES || test_bit (PC_ABORT, &pc->flags)) {
+	if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES ||
+	    test_bit(PC_ABORT, &pc->flags)) {
 		/*
 		 *	We will "abort" retrying a packet command in case
 		 *	a legitimate error code was received.
 		 */
-		if (!test_bit (PC_ABORT, &pc->flags)) {
-			if (!test_bit (PC_SUPPRESS_ERROR, &pc->flags)) {
-				;
-      printk( KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
-				drive->name, pc->c[0], floppy->sense_key, floppy->asc, floppy->ascq);
+		if (!test_bit(PC_ABORT, &pc->flags)) {
+			if (!test_bit(PC_SUPPRESS_ERROR, &pc->flags)) {
+				printk(KERN_ERR "ide-floppy: %s: I/O error, "
+						"pc = %2x, key = %2x, "
+						"asc = %2x, ascq = %2x\n",
+						drive->name, pc->c[0],
+						floppy->sense_key,
+						floppy->asc, floppy->ascq);
 			}
-			pc->error = IDEFLOPPY_ERROR_GENERAL;		/* Giving up */
+			/* Giving up */
+			pc->error = IDEFLOPPY_ERROR_GENERAL;
 		}
-		floppy->failed_pc=NULL;
+		floppy->failed_pc = NULL;
 		pc->callback(drive);
 		return ide_stopped;
 	}
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "Retry number - %d\n",pc->retries);
+	printk (KERN_INFO "Retry number - %d\n", pc->retries);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
 	pc->retries++;
-	pc->actually_transferred=0;					/* We haven't transferred any data yet */
-	pc->current_position=pc->buffer;
+	/* We haven't transferred any data yet */
+	pc->actually_transferred = 0;
+	pc->current_position = pc->buffer;
 	bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
+		(void) HWIF(drive)->ide_dma_off(drive);
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	feature.all = 0;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) {
+		if (test_bit(PC_WRITING, &pc->flags)) {
+			feature.b.dma = !HWIF(drive)->ide_dma_write(drive);
+		} else {
+			feature.b.dma = !HWIF(drive)->ide_dma_read(drive);
+		}
 	}
-	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
-	OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);			/* Use PIO/DMA */
-	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
-	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
-	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
+		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+	/* Use PIO/DMA */
+	HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);
+	HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
+	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
+	HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (dma_ok) {							/* Begin DMA, if necessary */
-		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+	if (feature.b.dma) {	/* Begin DMA, if necessary */
+		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->ide_dma_begin(drive));
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	/* Can we transfer the packet when we get the interrupt or wait? */
-	if (test_bit (IDEFLOPPY_ZIP_DRIVE, &floppy->flags)) {
-		pkt_xfer_routine = &idefloppy_transfer_pc1;	/* wait */
+	if (test_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags)) {
+		/* wait */
+		pkt_xfer_routine = &idefloppy_transfer_pc1;
 	} else {
-		pkt_xfer_routine = &idefloppy_transfer_pc;	/* immediate */
+		/* immediate */
+		pkt_xfer_routine = &idefloppy_transfer_pc;
 	}
 	
-	if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
-		ide_set_handler (drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL);
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
+	if (test_bit(IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
+		ide_set_handler(drive,
+				pkt_xfer_routine,
+				IDEFLOPPY_WAIT_CMD,
+				NULL);
+		/* Issue the packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return ide_started;
 	} else {
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
+		/* Issue the packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return (*pkt_xfer_routine) (drive);
 	}
 }
@@ -1177,24 +1145,25 @@
 	printk (KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_end_request(1, HWGROUP(drive));
+	idefloppy_do_end_request(drive, 1);
 	return;
 }
 
 static void idefloppy_create_prevent_cmd (idefloppy_pc_t *pc, int prevent)
 {
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "ide-floppy: creating prevent removal command, prevent = %d\n", prevent);
+	printk(KERN_INFO "ide-floppy: creating prevent removal command, "
+		"prevent = %d\n", prevent);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_PREVENT_REMOVAL_CMD;
 	pc->c[4] = prevent;
 }
 
 static void idefloppy_create_read_capacity_cmd (idefloppy_pc_t *pc)
 {
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_READ_CAPACITY_CMD;
 	pc->c[7] = 255;
 	pc->c[8] = 255;
@@ -1204,13 +1173,13 @@
 static void idefloppy_create_format_unit_cmd (idefloppy_pc_t *pc, int b, int l,
 					      int flags)
 {
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_FORMAT_UNIT_CMD;
 	pc->c[1] = 0x17;
 
 	memset(pc->buffer, 0, 12);
 	pc->buffer[1] = 0xA2;
-	/* Default format list header, byte 1: FOV/DCRT/IMM bits set */
+	/* Default format list header, u8 1: FOV/DCRT/IMM bits set */
 
 	if (flags & 1)				/* Verify bit on... */
 		pc->buffer[1] ^= 0x20;		/* ... turn off DCRT bit */
@@ -1225,11 +1194,11 @@
 /*
  *	A mode sense command is used to "sense" floppy parameters.
  */
-static void idefloppy_create_mode_sense_cmd (idefloppy_pc_t *pc, byte page_code, byte type)
+static void idefloppy_create_mode_sense_cmd (idefloppy_pc_t *pc, u8 page_code, u8 type)
 {
-	unsigned short length = sizeof (idefloppy_mode_parameter_header_t);
+	u16 length = sizeof(idefloppy_mode_parameter_header_t);
 	
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_MODE_SENSE_CMD;
 	pc->c[1] = 0;
 	pc->c[2] = page_code + (type << 6);
@@ -1242,15 +1211,16 @@
 			length += 32;
 			break;
 		default:
-			printk (KERN_ERR "ide-floppy: unsupported page code in create_mode_sense_cmd\n");
+			printk(KERN_ERR "ide-floppy: unsupported page code "
+				"in create_mode_sense_cmd\n");
 	}
-	put_unaligned (htons (length), (unsigned short *) &pc->c[7]);
+	put_unaligned(htons(length), (u16 *) &pc->c[7]);
 	pc->request_transfer = length;
 }
 
 static void idefloppy_create_start_stop_cmd (idefloppy_pc_t *pc, int start)
 {
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_START_STOP_CMD;
 	pc->c[4] = start;
 }
@@ -1267,28 +1237,29 @@
 	int blocks = rq->nr_sectors / floppy->bs_factor;
 	
 #if IDEFLOPPY_DEBUG_LOG
-	printk ("create_rw1%d_cmd: block == %d, blocks == %d\n",
-		2 * test_bit (IDEFLOPPY_USE_READ12, &floppy->flags), block, blocks);
+	printk("create_rw1%d_cmd: block == %d, blocks == %d\n",
+		2 * test_bit(IDEFLOPPY_USE_READ12, &floppy->flags),
+		block, blocks);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_init_pc (pc);
-	if (test_bit (IDEFLOPPY_USE_READ12, &floppy->flags)) {
+	idefloppy_init_pc(pc);
+	if (test_bit(IDEFLOPPY_USE_READ12, &floppy->flags)) {
 		pc->c[0] = rq->cmd == READ ? IDEFLOPPY_READ12_CMD : IDEFLOPPY_WRITE12_CMD;
-		put_unaligned (htonl (blocks), (unsigned int *) &pc->c[6]);
+		put_unaligned(htonl(blocks), (unsigned int *) &pc->c[6]);
 	} else {
 		pc->c[0] = rq->cmd == READ ? IDEFLOPPY_READ10_CMD : IDEFLOPPY_WRITE10_CMD;
-		put_unaligned (htons (blocks), (unsigned short *) &pc->c[7]);
+		put_unaligned(htons(blocks), (u16 *) &pc->c[7]);
 	}
-	put_unaligned (htonl (block), (unsigned int *) &pc->c[2]);
+	put_unaligned(htonl(block), (unsigned int *) &pc->c[2]);
 	pc->callback = &idefloppy_rw_callback;
 	pc->rq = rq;
 	pc->b_data = rq->buffer;
 	pc->b_count = rq->cmd == READ ? 0 : rq->bh->b_size;
 	if (rq->cmd == WRITE)
-		set_bit (PC_WRITING, &pc->flags);
+		set_bit(PC_WRITING, &pc->flags);
 	pc->buffer = NULL;
 	pc->request_transfer = pc->buffer_size = blocks * floppy->block_size;
-	set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+	set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 }
 
 /*
@@ -1300,40 +1271,49 @@
 	idefloppy_pc_t *pc;
 
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
-	printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+	printk(KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",
+		rq->rq_status, (unsigned int) rq->rq_dev, rq->cmd, rq->errors);
+	printk(KERN_INFO "sector: %ld, nr_sectors: %ld, "
+			"current_nr_sectors: %ld\n", rq->sector,
+			rq->nr_sectors, rq->current_nr_sectors);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
 	if (rq->errors >= ERROR_MAX) {
 		if (floppy->failed_pc != NULL)
-			printk (KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
-				drive->name, floppy->failed_pc->c[0], floppy->sense_key, floppy->asc, floppy->ascq);
+			printk(KERN_ERR "ide-floppy: %s: I/O error, pc = %2x,"
+					" key = %2x, asc = %2x, ascq = %2x\n",
+				drive->name, floppy->failed_pc->c[0],
+				floppy->sense_key, floppy->asc, floppy->ascq);
 		else
-			printk (KERN_ERR "ide-floppy: %s: I/O error\n", drive->name);
-		idefloppy_end_request (0, HWGROUP(drive));
+			printk(KERN_ERR "ide-floppy: %s: I/O error\n",
+				drive->name);
+		idefloppy_do_end_request(drive, 0);
 		return ide_stopped;
 	}
 	switch (rq->cmd) {
 		case READ:
 		case WRITE:
-			if (rq->sector % floppy->bs_factor || rq->nr_sectors % floppy->bs_factor) {
-				printk ("%s: unsupported r/w request size\n", drive->name);
-				idefloppy_end_request (0, HWGROUP(drive));
+			if (rq->sector % floppy->bs_factor ||
+			    rq->nr_sectors % floppy->bs_factor) {
+				printk("%s: unsupported r/w request size\n",
+					drive->name);
+				idefloppy_do_end_request(drive, 0);
 				return ide_stopped;
 			}
-			pc = idefloppy_next_pc_storage (drive);
-			idefloppy_create_rw_cmd (floppy, pc, rq, block);
+			pc = idefloppy_next_pc_storage(drive);
+			idefloppy_create_rw_cmd(floppy, pc, rq, block);
 			break;
 		case IDEFLOPPY_PC_RQ:
 			pc = (idefloppy_pc_t *) rq->buffer;
 			break;
 		default:
-			printk (KERN_ERR "ide-floppy: unsupported command %x in request queue\n", rq->cmd);
-			idefloppy_end_request (0,HWGROUP (drive));
+			printk(KERN_ERR "ide-floppy: unsupported command %x"
+				" in request queue\n", rq->cmd);
+			idefloppy_do_end_request(drive, 0);
 			return ide_stopped;
 	}
 	pc->rq = rq;
-	return idefloppy_issue_pc (drive, pc);
+	return idefloppy_issue_pc(drive, pc);
 }
 
 /*
@@ -1344,10 +1324,10 @@
 {
 	struct request rq;
 
-	ide_init_drive_cmd (&rq);
+	ide_init_drive_cmd(&rq);
 	rq.buffer = (char *) pc;
 	rq.cmd = IDEFLOPPY_PC_RQ;
-	return ide_do_drive_cmd (drive, &rq, ide_wait);
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
 /*
@@ -1362,23 +1342,26 @@
 	idefloppy_flexible_disk_page_t *page;
 	int capacity, lba_capacity;
 
-	idefloppy_create_mode_sense_cmd (&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE, MODE_SENSE_CURRENT);
-	if (idefloppy_queue_pc_tail (drive,&pc)) {
-		printk (KERN_ERR "ide-floppy: Can't get flexible disk page parameters\n");
+	idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE, MODE_SENSE_CURRENT);
+	if (idefloppy_queue_pc_tail(drive,&pc)) {
+		printk(KERN_ERR "ide-floppy: Can't get flexible disk "
+			"page parameters\n");
 		return 1;
 	}
 	header = (idefloppy_mode_parameter_header_t *) pc.buffer;
 	floppy->wp = header->wp;
 	page = (idefloppy_flexible_disk_page_t *) (header + 1);
 
-	page->transfer_rate = ntohs (page->transfer_rate);
-	page->sector_size = ntohs (page->sector_size);
-	page->cyls = ntohs (page->cyls);
-	page->rpm = ntohs (page->rpm);
+	page->transfer_rate = ntohs(page->transfer_rate);
+	page->sector_size = ntohs(page->sector_size);
+	page->cyls = ntohs(page->cyls);
+	page->rpm = ntohs(page->rpm);
 	capacity = page->cyls * page->heads * page->sectors * page->sector_size;
 	if (memcmp (page, &floppy->flexible_disk_page, sizeof (idefloppy_flexible_disk_page_t)))
-		printk (KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, %d sector size, %d rpm\n",
-			drive->name, capacity / 1024, page->cyls, page->heads, page->sectors,
+		printk(KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, "
+				"%d sector size, %d rpm\n",
+			drive->name, capacity / 1024, page->cyls,
+			page->heads, page->sectors,
 			page->transfer_rate / 8, page->sector_size, page->rpm);
 
 	floppy->flexible_disk_page = *page;
@@ -1387,8 +1370,8 @@
 	drive->bios_sect = page->sectors;
 	lba_capacity = floppy->blocks * floppy->block_size;
 	if (capacity < lba_capacity) {
-		printk (KERN_NOTICE "%s: The disk reports a capacity of %d bytes, "
-			"but the drive only handles %d\n",
+		printk(KERN_NOTICE "%s: The disk reports a capacity of %d "
+			"bytes, but the drive only handles %d\n",
 			drive->name, lba_capacity, capacity);
 		floppy->blocks = floppy->block_size ? capacity / floppy->block_size : 0;
 	}
@@ -1402,18 +1385,18 @@
 	idefloppy_mode_parameter_header_t *header;
 	idefloppy_capabilities_page_t *page;
 
-	floppy->srfp=0;
-	idefloppy_create_mode_sense_cmd (&pc, IDEFLOPPY_CAPABILITIES_PAGE,
+	floppy->srfp = 0;
+	idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_CAPABILITIES_PAGE,
 						 MODE_SENSE_CURRENT);
 
 	set_bit(PC_SUPPRESS_ERROR, &pc.flags);
-	if (idefloppy_queue_pc_tail (drive,&pc)) {
+	if (idefloppy_queue_pc_tail(drive,&pc)) {
 		return 1;
 	}
 
 	header = (idefloppy_mode_parameter_header_t *) pc.buffer;
 	page= (idefloppy_capabilities_page_t *)(header+1);
-	floppy->srfp=page->srfp;
+	floppy->srfp = page->srfp;
 	return (0);
 }
 
@@ -1434,58 +1417,76 @@
 	floppy->blocks = floppy->bs_factor = 0;
 	drive->part[0].nr_sects = 0;
 
-	idefloppy_create_read_capacity_cmd (&pc);
-	if (idefloppy_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-floppy: Can't get floppy parameters\n");
+	idefloppy_create_read_capacity_cmd(&pc);
+	if (idefloppy_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
 		return 1;
 	}
 	header = (idefloppy_capacity_header_t *) pc.buffer;
-	descriptors = header->length / sizeof (idefloppy_capacity_descriptor_t);
+	descriptors = header->length / sizeof(idefloppy_capacity_descriptor_t);
 	descriptor = (idefloppy_capacity_descriptor_t *) (header + 1);
 
 	for (i = 0; i < descriptors; i++, descriptor++) {
-                blocks = descriptor->blocks = ntohl (descriptor->blocks);
-                length = descriptor->length = ntohs (descriptor->length);
+		blocks = descriptor->blocks = ntohl(descriptor->blocks);
+		length = descriptor->length = ntohs(descriptor->length);
 
 		if (!i) 
 		{
-          	switch (descriptor->dc) {
-                case CAPACITY_UNFORMATTED: /* Clik! drive returns this instead of CAPACITY_CURRENT */
-                        if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags))
-                                break; /* If it is not a clik drive, break out (maintains previous driver behaviour) */
-                case CAPACITY_CURRENT: /* Normal Zip/LS-120 disks */
-                        if (memcmp (descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t)))
-                                printk (KERN_INFO "%s: %dkB, %d blocks, %d sector size\n", drive->name, blocks * length / 1024, blocks, length);
-                        floppy->capacity = *descriptor;
-                        if (!length || length % 512)
-                                printk (KERN_NOTICE "%s: %d bytes block size not supported\n", drive->name, length);
-                        else {
+		switch (descriptor->dc) {
+		/* Clik! drive returns this instead of CAPACITY_CURRENT */
+		case CAPACITY_UNFORMATTED:
+			if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags))
+                                /*
+				 * If it is not a clik drive, break out
+				 * (maintains previous driver behaviour)
+				 */
+				break;
+		case CAPACITY_CURRENT:
+			/* Normal Zip/LS-120 disks */
+			if (memcmp(descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t)))
+				printk(KERN_INFO "%s: %dkB, %d blocks, %d "
+					"sector size\n", drive->name,
+					blocks * length / 1024, blocks, length);
+			floppy->capacity = *descriptor;
+			if (!length || length % 512) {
+				printk(KERN_NOTICE "%s: %d bytes block size "
+					"not supported\n", drive->name, length);
+			} else {
                                 floppy->blocks = blocks;
                                 floppy->block_size = length;
                                 if ((floppy->bs_factor = length / 512) != 1)
-                                        printk (KERN_NOTICE "%s: warning: non 512 bytes block size not fully supported\n", drive->name);
+                                        printk(KERN_NOTICE "%s: warning: non "
+						"512 bytes block size not "
+						"fully supported\n",
+						drive->name);
                                 rc = 0;
-                        }
-                        break;
-                case CAPACITY_NO_CARTRIDGE:
-                        /* This is a KERN_ERR so it appears on screen for the user to see */
-                        printk (KERN_ERR "%s: No disk in drive\n", drive->name);
-                                        break;
-                case CAPACITY_INVALID:
-                        printk (KERN_ERR "%s: Invalid capacity for disk in drive\n", drive->name);
-                                        break;
+			}
+			break;
+		case CAPACITY_NO_CARTRIDGE:
+			/*
+			 * This is a KERN_ERR so it appears on screen
+			 * for the user to see
+			 */
+			printk(KERN_ERR "%s: No disk in drive\n", drive->name);
+			break;
+		case CAPACITY_INVALID:
+			printk(KERN_ERR "%s: Invalid capacity for disk "
+				"in drive\n", drive->name);
+			break;
 		}
 		}
 		if (!i) {
-		IDEFLOPPY_DEBUG( "Descriptor 0 Code: %d\n", descriptor->dc);
+			IDEFLOPPY_DEBUG( "Descriptor 0 Code: %d\n",
+				descriptor->dc);
 		}
-		IDEFLOPPY_DEBUG( "Descriptor %d: %dkB, %d blocks, %d sector size\n", i, blocks * length / 1024, blocks, length);
+		IDEFLOPPY_DEBUG( "Descriptor %d: %dkB, %d blocks, %d "
+			"sector size\n", i, blocks * length / 1024, blocks,
+			length);
 	}
 
 	/* Clik! disk does not support get_flexible_disk_page */
-        if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags))
-	{
-		(void) idefloppy_get_flexible_disk_page (drive);
+        if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
+		(void) idefloppy_get_flexible_disk_page(drive);
 	}
 
 	drive->part[0].nr_sects = floppy->blocks * floppy->bs_factor;
@@ -1532,18 +1533,18 @@
 	if (u_array_size <= 0)
 		return (-EINVAL);
 
-	idefloppy_create_read_capacity_cmd (&pc);
-	if (idefloppy_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-floppy: Can't get floppy parameters\n");
+	idefloppy_create_read_capacity_cmd(&pc);
+	if (idefloppy_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
                 return (-EIO);
         }
         header = (idefloppy_capacity_header_t *) pc.buffer;
         descriptors = header->length /
-		sizeof (idefloppy_capacity_descriptor_t);
+		sizeof(idefloppy_capacity_descriptor_t);
 	descriptor = (idefloppy_capacity_descriptor_t *) (header + 1);
 
-	u_index=0;
-	argp=arg+1;
+	u_index = 0;
+	argp = arg + 1;
 
 	/*
 	** We always skip the first capacity descriptor.  That's the
@@ -1551,18 +1552,17 @@
 	** the formattable capacities.
 	*/
 
-	for (i=0; i<descriptors; i++, descriptor++)
-	{
+	for (i=0; i<descriptors; i++, descriptor++) {
 		if (u_index >= u_array_size)
 			break;	/* User-supplied buffer too small */
 		if (i == 0)
 			continue;	/* Skip the first descriptor */
 
-		blocks = ntohl (descriptor->blocks);
-		length = ntohs (descriptor->length);
+		blocks = ntohl(descriptor->blocks);
+		length = ntohs(descriptor->length);
 
 		if (put_user(blocks, argp))
-			return (-EFAULT);
+			return(-EFAULT);
 		++argp;
 
 		if (put_user(length, argp))
@@ -1603,19 +1603,19 @@
 	int flags;
 	idefloppy_pc_t pc;
 
-	if (get_user(blocks, arg)
-	    || get_user(length, arg+1)
-	    || get_user(flags, arg+2))
-	{
+	if (get_user(blocks, arg) ||
+	    get_user(length, arg+1) ||
+	    get_user(flags, arg+2)) {
 		return (-EFAULT);
 	}
 
-	(void) idefloppy_get_capability_page (drive);	/* Get the SFRP bit */
+	/* Get the SFRP bit */
+	(void) idefloppy_get_capability_page(drive);
 	idefloppy_create_format_unit_cmd(&pc, blocks, length, flags);
-	if (idefloppy_queue_pc_tail (drive, &pc))
-	{
+	if (idefloppy_queue_pc_tail(drive, &pc)) {
                 return (-EIO);
-        }
+	}
+
 	return (0);
 }
 
@@ -1636,35 +1636,30 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	idefloppy_pc_t pc;
-	int progress_indication=0x10000;
+	int progress_indication = 0x10000;
 
-	if (floppy->srfp)
-	{
+	if (floppy->srfp) {
 		idefloppy_create_request_sense_cmd(&pc);
-		if (idefloppy_queue_pc_tail (drive, &pc))
-		{
+		if (idefloppy_queue_pc_tail(drive, &pc)) {
 			return (-EIO);
 		}
 
-		if (floppy->sense_key == 2 && floppy->asc == 4 &&
-		    floppy->ascq == 4)
-		{
-			progress_indication=floppy->progress_indication;
+		if (floppy->sense_key == 2 &&
+		    floppy->asc == 4 &&
+		    floppy->ascq == 4) {
+			progress_indication = floppy->progress_indication;
 		}
 		/* Else assume format_unit has finished, and we're
 		** at 0x10000 */
-	}
-	else
-	{
-		idefloppy_status_reg_t status;
+	} else {
+		atapi_status_t status;
 		unsigned long flags;
 
-		__save_flags(flags);
-		__cli();
-		status.all=GET_STAT();
-		__restore_flags(flags);
+		local_irq_save(flags);
+		status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+		local_irq_restore(flags);
 
-		progress_indication= !status.b.dsc ? 0:0x10000;
+		progress_indication = !status.b.dsc ? 0 : 0x10000;
 	}
 	if (put_user(progress_indication, arg))
 		return (-EFAULT);
@@ -1694,12 +1689,12 @@
 
 		/* The IOMEGA Clik! Drive doesn't support this command - no room for an eject mechanism */
                 if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
-			idefloppy_create_prevent_cmd (&pc, prevent);
-			(void) idefloppy_queue_pc_tail (drive, &pc);
+			idefloppy_create_prevent_cmd(&pc, prevent);
+			(void) idefloppy_queue_pc_tail(drive, &pc);
 		}
 		if (cmd == CDROMEJECT) {
-			idefloppy_create_start_stop_cmd (&pc, 2);
-			(void) idefloppy_queue_pc_tail (drive, &pc);
+			idefloppy_create_start_stop_cmd(&pc, 2);
+			(void) idefloppy_queue_pc_tail(drive, &pc);
 		}
 		return 0;
 	case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED:
@@ -1715,16 +1710,13 @@
 		{
 			idefloppy_floppy_t *floppy = drive->driver_data;
 
-			if (drive->usage > 1)
-			{
+			if (drive->usage > 1) {
 				/* Don't format if someone is using the disk */
 
 				clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS,
 					  &floppy->flags);
 				return -EBUSY;
-			}
-			else
-			{
+			} else {
 				int rc;
 
 				set_bit(IDEFLOPPY_FORMAT_IN_PROGRESS,
@@ -1763,7 +1755,7 @@
 	idefloppy_pc_t pc;
 	
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "Reached idefloppy_open\n");
+	printk(KERN_INFO "Reached idefloppy_open\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
 	MOD_INC_USE_COUNT;
@@ -1773,8 +1765,8 @@
 
 		idefloppy_create_test_unit_ready_cmd(&pc);
 		if (idefloppy_queue_pc_tail(drive, &pc)) {
-			idefloppy_create_start_stop_cmd (&pc, 1);
-			(void) idefloppy_queue_pc_tail (drive, &pc);
+			idefloppy_create_start_stop_cmd(&pc, 1);
+			(void) idefloppy_queue_pc_tail(drive, &pc);
 		}
 
 		if (idefloppy_get_capacity (drive)
@@ -1795,16 +1787,14 @@
 			MOD_DEC_USE_COUNT;
 			return -EROFS;
 		}		
-		set_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
+		set_bit(IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
 		/* IOMEGA Clik! drives do not support lock/unlock commands */
                 if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
-			idefloppy_create_prevent_cmd (&pc, 1);
-			(void) idefloppy_queue_pc_tail (drive, &pc);
+			idefloppy_create_prevent_cmd(&pc, 1);
+			(void) idefloppy_queue_pc_tail(drive, &pc);
 		}
 		check_disk_change(inode->i_rdev);
-	}
-	else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags))
-	{
+	} else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags)) {
 		drive->usage--;
 		MOD_DEC_USE_COUNT;
 		return -EBUSY;
@@ -1823,12 +1813,12 @@
 	if (!drive->usage) {
 		idefloppy_floppy_t *floppy = drive->driver_data;
 
-		invalidate_bdev (inode->i_bdev, 0);
+		invalidate_bdev(inode->i_bdev, 0);
 
 		/* IOMEGA Clik! drives do not support lock/unlock commands */
                 if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
-			idefloppy_create_prevent_cmd (&pc, 0);
-			(void) idefloppy_queue_pc_tail (drive, &pc);
+			idefloppy_create_prevent_cmd(&pc, 0);
+			(void) idefloppy_queue_pc_tail(drive, &pc);
 		}
 
 		clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
@@ -1843,7 +1833,7 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	
-	return test_and_clear_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
+	return test_and_clear_bit(IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
 }
 
 /*
@@ -1875,109 +1865,114 @@
 {
 	struct idefloppy_id_gcw gcw;
 #if IDEFLOPPY_DEBUG_INFO
-	unsigned short mask,i;
+	u16 mask,i;
 	char buffer[80];
 #endif /* IDEFLOPPY_DEBUG_INFO */
 
-	*((unsigned short *) &gcw) = id->config;
+	*((u16 *) &gcw) = id->config;
 
 #ifdef CONFIG_PPC
 	/* kludge for Apple PowerBook internal zip */
-	if ((gcw.device_type == 5) && !strstr(id->model, "CD-ROM")
-	    && strstr(id->model, "ZIP"))
+	if ((gcw.device_type == 5) &&
+	    !strstr(id->model, "CD-ROM") &&
+	    strstr(id->model, "ZIP"))
 		gcw.device_type = 0;			
 #endif
 
 #if IDEFLOPPY_DEBUG_INFO
-	printk (KERN_INFO "Dumping ATAPI Identify Device floppy parameters\n");
+	printk(KERN_INFO "Dumping ATAPI Identify Device floppy parameters\n");
 	switch (gcw.protocol) {
-		case 0: case 1: sprintf (buffer, "ATA");break;
-		case 2:	sprintf (buffer, "ATAPI");break;
-		case 3: sprintf (buffer, "Reserved (Unknown to ide-floppy)");break;
+		case 0: case 1: sprintf(buffer, "ATA");break;
+		case 2:	sprintf(buffer, "ATAPI");break;
+		case 3: sprintf(buffer, "Reserved (Unknown to ide-floppy)");break;
 	}
-	printk (KERN_INFO "Protocol Type: %s\n", buffer);
+	printk(KERN_INFO "Protocol Type: %s\n", buffer);
 	switch (gcw.device_type) {
-		case 0: sprintf (buffer, "Direct-access Device");break;
-		case 1: sprintf (buffer, "Streaming Tape Device");break;
+		case 0: sprintf(buffer, "Direct-access Device");break;
+		case 1: sprintf(buffer, "Streaming Tape Device");break;
 		case 2: case 3: case 4: sprintf (buffer, "Reserved");break;
-		case 5: sprintf (buffer, "CD-ROM Device");break;
-		case 6: sprintf (buffer, "Reserved");
-		case 7: sprintf (buffer, "Optical memory Device");break;
-		case 0x1f: sprintf (buffer, "Unknown or no Device type");break;
-		default: sprintf (buffer, "Reserved");
+		case 5: sprintf(buffer, "CD-ROM Device");break;
+		case 6: sprintf(buffer, "Reserved");
+		case 7: sprintf(buffer, "Optical memory Device");break;
+		case 0x1f: sprintf(buffer, "Unknown or no Device type");break;
+		default: sprintf(buffer, "Reserved");
 	}
-	printk (KERN_INFO "Device Type: %x - %s\n", gcw.device_type, buffer);
-	printk (KERN_INFO "Removable: %s\n",gcw.removable ? "Yes":"No");	
+	printk(KERN_INFO "Device Type: %x - %s\n", gcw.device_type, buffer);
+	printk(KERN_INFO "Removable: %s\n",gcw.removable ? "Yes":"No");	
 	switch (gcw.drq_type) {
-		case 0: sprintf (buffer, "Microprocessor DRQ");break;
-		case 1: sprintf (buffer, "Interrupt DRQ");break;
-		case 2: sprintf (buffer, "Accelerated DRQ");break;
-		case 3: sprintf (buffer, "Reserved");break;
+		case 0: sprintf(buffer, "Microprocessor DRQ");break;
+		case 1: sprintf(buffer, "Interrupt DRQ");break;
+		case 2: sprintf(buffer, "Accelerated DRQ");break;
+		case 3: sprintf(buffer, "Reserved");break;
 	}
-	printk (KERN_INFO "Command Packet DRQ Type: %s\n", buffer);
+	printk(KERN_INFO "Command Packet DRQ Type: %s\n", buffer);
 	switch (gcw.packet_size) {
-		case 0: sprintf (buffer, "12 bytes");break;
-		case 1: sprintf (buffer, "16 bytes");break;
-		default: sprintf (buffer, "Reserved");break;
-	}
-	printk (KERN_INFO "Command Packet Size: %s\n", buffer);
-	printk (KERN_INFO "Model: %.40s\n",id->model);
-	printk (KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev);
-	printk (KERN_INFO "Serial Number: %.20s\n",id->serial_no);
-	printk (KERN_INFO "Write buffer size(?): %d bytes\n",id->buf_size*512);
-	printk (KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
-	printk (KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
-	printk (KERN_INFO "IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
-	printk (KERN_INFO "IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
-	printk (KERN_INFO "ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
-	printk (KERN_INFO "PIO Cycle Timing Category: %d\n",id->tPIO);
-	printk (KERN_INFO "DMA Cycle Timing Category: %d\n",id->tDMA);
-	printk (KERN_INFO "Single Word DMA supported modes:\n");
+		case 0: sprintf(buffer, "12 bytes");break;
+		case 1: sprintf(buffer, "16 bytes");break;
+		default: sprintf(buffer, "Reserved");break;
+	}
+	printk(KERN_INFO "Command Packet Size: %s\n", buffer);
+	printk(KERN_INFO "Model: %.40s\n",id->model);
+	printk(KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev);
+	printk(KERN_INFO "Serial Number: %.20s\n",id->serial_no);
+	printk(KERN_INFO "Write buffer size(?): %d bytes\n",id->buf_size*512);
+	printk(KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
+	printk(KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
+	printk(KERN_INFO "IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
+	printk(KERN_INFO "IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
+	printk(KERN_INFO "ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
+	printk(KERN_INFO "PIO Cycle Timing Category: %d\n",id->tPIO);
+	printk(KERN_INFO "DMA Cycle Timing Category: %d\n",id->tDMA);
+	printk(KERN_INFO "Single Word DMA supported modes:\n");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_1word & mask)
-			printk (KERN_INFO "   Mode %d%s\n", i, (id->dma_1word & (mask << 8)) ? " (active)" : "");
+			printk(KERN_INFO "   Mode %d%s\n", i,
+			(id->dma_1word & (mask << 8)) ? " (active)" : "");
 	}
-	printk (KERN_INFO "Multi Word DMA supported modes:\n");
+	printk(KERN_INFO "Multi Word DMA supported modes:\n");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_mword & mask)
-			printk (KERN_INFO "   Mode %d%s\n", i, (id->dma_mword & (mask << 8)) ? " (active)" : "");
+			printk(KERN_INFO "   Mode %d%s\n", i,
+			(id->dma_mword & (mask << 8)) ? " (active)" : "");
 	}
 	if (id->field_valid & 0x0002) {
-		printk (KERN_INFO "Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None");
+		printk(KERN_INFO "Enhanced PIO Modes: %s\n",
+			id->eide_pio_modes & 1 ? "Mode 3":"None");
 		if (id->eide_dma_min == 0)
-			sprintf (buffer, "Not supported");
+			sprintf(buffer, "Not supported");
 		else
-			sprintf (buffer, "%d ns",id->eide_dma_min);
-		printk (KERN_INFO "Minimum Multi-word DMA cycle per word: %s\n", buffer);
+			sprintf(buffer, "%d ns",id->eide_dma_min);
+		printk(KERN_INFO "Minimum Multi-word DMA cycle per word: %s\n", buffer);
 		if (id->eide_dma_time == 0)
-			sprintf (buffer, "Not supported");
+			sprintf(buffer, "Not supported");
 		else
-			sprintf (buffer, "%d ns",id->eide_dma_time);
-		printk (KERN_INFO "Manufacturer\'s Recommended Multi-word cycle: %s\n", buffer);
+			sprintf(buffer, "%d ns",id->eide_dma_time);
+		printk(KERN_INFO "Manufacturer\'s Recommended Multi-word cycle: %s\n", buffer);
 		if (id->eide_pio == 0)
-			sprintf (buffer, "Not supported");
+			sprintf(buffer, "Not supported");
 		else
-			sprintf (buffer, "%d ns",id->eide_pio);
-		printk (KERN_INFO "Minimum PIO cycle without IORDY: %s\n", buffer);
+			sprintf(buffer, "%d ns",id->eide_pio);
+		printk(KERN_INFO "Minimum PIO cycle without IORDY: %s\n",
+			buffer);
 		if (id->eide_pio_iordy == 0)
-			sprintf (buffer, "Not supported");
+			sprintf(buffer, "Not supported");
 		else
-			sprintf (buffer, "%d ns",id->eide_pio_iordy);
-		printk (KERN_INFO "Minimum PIO cycle with IORDY: %s\n", buffer);
+			sprintf(buffer, "%d ns",id->eide_pio_iordy);
+		printk(KERN_INFO "Minimum PIO cycle with IORDY: %s\n", buffer);
 	} else
-		printk (KERN_INFO "According to the device, fields 64-70 are not valid.\n");
+		printk(KERN_INFO "According to the device, fields 64-70 are not valid.\n");
 #endif /* IDEFLOPPY_DEBUG_INFO */
 
 	if (gcw.protocol != 2)
-		printk (KERN_ERR "ide-floppy: Protocol is not ATAPI\n");
+		printk(KERN_ERR "ide-floppy: Protocol is not ATAPI\n");
 	else if (gcw.device_type != 0)
-		printk (KERN_ERR "ide-floppy: Device type is not set to floppy\n");
+		printk(KERN_ERR "ide-floppy: Device type is not set to floppy\n");
 	else if (!gcw.removable)
-		printk (KERN_ERR "ide-floppy: The removable flag is not set\n");
+		printk(KERN_ERR "ide-floppy: The removable flag is not set\n");
 	else if (gcw.drq_type == 3) {
-		printk (KERN_ERR "ide-floppy: Sorry, DRQ type %d not supported\n", gcw.drq_type);
+		printk(KERN_ERR "ide-floppy: Sorry, DRQ type %d not supported\n", gcw.drq_type);
 	} else if (gcw.packet_size != 0) {
-		printk (KERN_ERR "ide-floppy: Packet size is not 12 bytes long\n");
+		printk(KERN_ERR "ide-floppy: Packet size is not 12 bytes long\n");
 	} else
 		return 1;
 	return 0;
@@ -1999,7 +1994,6 @@
 	ide_add_setting(drive,	"file_readahead",	SETTING_RW,					BLKFRAGET,		BLKFRASET,		TYPE_INTA,	0,	INT_MAX,			1,	1024,	&max_readahead[major][minor],	NULL);
 	ide_add_setting(drive,	"max_kb_per_request",	SETTING_RW,					BLKSECTGET,		BLKSECTSET,		TYPE_INTA,	1,	255,				1,	2,	&max_sectors[major][minor],	NULL);
 	ide_add_setting(drive,	"ticks",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&floppy->ticks,		NULL);
-
 }
 
 /*
@@ -2011,14 +2005,14 @@
 	int major = HWIF(drive)->major, i;
 	int minor = drive->select.b.unit << PARTN_BITS;
 
-	*((unsigned short *) &gcw) = drive->id->config;
+	*((u16 *) &gcw) = drive->id->config;
 	drive->driver_data = floppy;
 	drive->ready_stat = 0;
-	memset (floppy, 0, sizeof (idefloppy_floppy_t));
+	memset(floppy, 0, sizeof(idefloppy_floppy_t));
 	floppy->drive = drive;
 	floppy->pc = floppy->pc_stack;
 	if (gcw.drq_type == 1)
-		set_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags);
+		set_bit(IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags);
 	/*
 	 *	We used to check revisions here. At this point however
 	 *	I'm giving up. Just assume they are all broken, its easier.
@@ -2030,8 +2024,7 @@
 	 *	we'll leave the limitation below for the 2.2.x tree.
 	 */
 
-	if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0)
-	{
+	if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0) {
 		set_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags);
 		/* This value will be visible in the /proc/ide/hdx/settings */
 		floppy->ticks = IDEFLOPPY_TICKS_DELAY;
@@ -2044,15 +2037,14 @@
 	*      above fix.  It makes nasty clicking noises without
 	*      it, so please don't remove this.
 	*/
-	if (strncmp(drive->id->model, "IOMEGA Clik!", 11) == 0) 
-	{
+	if (strncmp(drive->id->model, "IOMEGA Clik!", 11) == 0) {
 		for (i = 0; i < 1 << PARTN_BITS; i++)
 			max_sectors[major][minor + i] = 64;
 		set_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags);
 	}
 
 
-	(void) idefloppy_get_capacity (drive);
+	(void) idefloppy_get_capacity(drive);
 	idefloppy_add_settings(drive);
 	for (i = 0; i < MAX_DRIVES; ++i) {
 		ide_hwif_t *hwif = HWIF(drive);
@@ -2069,10 +2061,11 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	if (ide_unregister_subdriver (drive))
+	if (ide_unregister_subdriver(drive))
 		return 1;
+
 	drive->driver_data = NULL;
-	kfree (floppy);
+	kfree(floppy);
 	return 0;
 }
 
@@ -2089,7 +2082,8 @@
 
 #endif	/* CONFIG_PROC_FS */
 
-int idefloppy_reinit(ide_drive_t *drive);
+int idefloppy_init (void);
+int idefloppy_attach(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -2099,13 +2093,21 @@
 	version:		IDEFLOPPY_VERSION,
 	media:			ide_floppy,
 	busy:			0,
+#ifdef CONFIG_IDEDMA_ONLYDISK
+	supports_dma:		0,
+#else
 	supports_dma:		1,
+#endif
 	supports_dsc_overlap:	0,
 	cleanup:		idefloppy_cleanup,
 	standby:		NULL,
+	suspend:		NULL,
+	resume:			NULL,
 	flushcache:		NULL,
 	do_request:		idefloppy_do_request,
-	end_request:		idefloppy_end_request,
+	end_request:		idefloppy_do_end_request,
+	sense:			NULL,
+	error:			NULL,
 	ioctl:			idefloppy_ioctl,
 	open:			idefloppy_open,
 	release:		idefloppy_release,
@@ -2115,12 +2117,12 @@
 	capacity:		idefloppy_capacity,
 	special:		NULL,
 	proc:			idefloppy_proc,
-	reinit:			idefloppy_reinit,
+	init:			idefloppy_init,
+	attach:			idefloppy_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 };
 
-int idefloppy_init (void);
 static ide_module_t idefloppy_module = {
 	IDE_DRIVER_MODULE,
 	idefloppy_init,
@@ -2128,38 +2130,45 @@
 	NULL
 };
 
-int idefloppy_reinit (ide_drive_t *drive)
+int idefloppy_attach (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy;
-	int failed = 0;
+	int ret = 0;
 
 	MOD_INC_USE_COUNT;
-	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) {
-		if (!idefloppy_identify_device (drive, drive->id)) {
-			printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name);
-			continue;
-		}
-		if (drive->scsi) {
-			printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name);
-			continue;
-		}
-		if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
-			printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
-			continue;
-		}
-		if (ide_register_subdriver (drive, &idefloppy_driver, IDE_SUBDRIVER_VERSION)) {
-			printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
-			kfree (floppy);
-			continue;
-		}
-		DRIVER(drive)->busy++;
-		idefloppy_setup (drive, floppy);
-		DRIVER(drive)->busy--;
-		failed--;
-	}
-	ide_register_module(&idefloppy_module);
+	if (!idefloppy_identify_device(drive, drive->id)) {
+		printk(KERN_ERR "ide-floppy: %s: not supported by this "
+			"version of ide-floppy\n", drive->name);
+			ret = 1;
+			goto bye_game_over;
+	}
+	if (drive->scsi) {
+		printk("ide-floppy: passing drive %s to ide-scsi "
+			"emulation.\n", drive->name);
+		ret = 1;
+		goto bye_game_over;
+	}
+	if ((floppy = (idefloppy_floppy_t *) kmalloc(sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
+		printk(KERN_ERR "ide-floppy: %s: Can't allocate a floppy "
+			"structure\n", drive->name);
+		ret = 1;
+		goto bye_game_over;
+	}
+	if (ide_register_subdriver(drive,
+			&idefloppy_driver, IDE_SUBDRIVER_VERSION)) {
+		printk(KERN_ERR "ide-floppy: %s: Failed to register the "
+			"driver with ide.c\n", drive->name);
+		kfree(floppy);
+		ret = 1;
+		goto bye_game_over;
+	}
+	DRIVER(drive)->busy++;
+	idefloppy_setup(drive, floppy);
+	DRIVER(drive)->busy--;
+
+bye_game_over:
 	MOD_DEC_USE_COUNT;
-	return 0;
+	return ret;
 }
 
 MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
@@ -2169,9 +2178,11 @@
 	ide_drive_t *drive;
 	int failed = 0;
 
-	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, &idefloppy_driver, failed)) != NULL) {
-		if (idefloppy_cleanup (drive)) {
-			printk ("%s: cleanup_module() called while still busy\n", drive->name);
+	while ((drive = ide_scan_devices(ide_floppy, idefloppy_driver.name,
+			&idefloppy_driver, failed)) != NULL) {
+		if (idefloppy_cleanup(drive)) {
+			printk("%s: cleanup_module() called while still "
+				"busy\n", drive->name);
 			failed++;
 		}
 		/* We must remove proc entries defined in this module.
@@ -2184,40 +2195,47 @@
 	ide_unregister_module(&idefloppy_module);
 }
 
-/*
- *	idefloppy_init will register the driver for each floppy.
- */
 int idefloppy_init (void)
 {
+#ifdef CLASSIC_BUILTINS_METHOD
 	ide_drive_t *drive;
 	idefloppy_floppy_t *floppy;
 	int failed = 0;
 
 	printk("ide-floppy driver " IDEFLOPPY_VERSION "\n");
+#endif /* CLASSIC_BUILTINS_METHOD */
 	MOD_INC_USE_COUNT;
-	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) {
-		if (!idefloppy_identify_device (drive, drive->id)) {
-			printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name);
+#ifdef CLASSIC_BUILTINS_METHOD
+	while ((drive = ide_scan_devices(ide_floppy,
+			idefloppy_driver.name, NULL, failed++)) != NULL) {
+		if (!idefloppy_identify_device(drive, drive->id)) {
+			printk(KERN_ERR "ide-floppy: %s: not supported by "
+				"this version of ide-floppy\n", drive->name);
 			continue;
 		}
 		if (drive->scsi) {
-			printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name);
-			continue;
-		}
-		if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
-			printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
+			printk("ide-floppy: passing drive %s to ide-scsi "
+				"emulation.\n", drive->name);
 			continue;
 		}
-		if (ide_register_subdriver (drive, &idefloppy_driver, IDE_SUBDRIVER_VERSION)) {
-			printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
-			kfree (floppy);
+		if ((floppy = (idefloppy_floppy_t *) kmalloc(sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
+			printk(KERN_ERR "ide-floppy: %s: Can't allocate a "
+				"floppy structure\n", drive->name);
 			continue;
 		}
+		if (ide_register_subdriver(drive,
+				&idefloppy_driver, IDE_SUBDRIVER_VERSION)) {
+			printk(KERN_ERR "ide-floppy: %s: Failed to register "
+				"the driver with ide.c\n", drive->name);
+			kfree(floppy);
+                        continue;
+                }
 		DRIVER(drive)->busy++;
-		idefloppy_setup (drive, floppy);
+		idefloppy_setup(drive, floppy);
 		DRIVER(drive)->busy--;
 		failed--;
 	}
+#endif /* CLASSIC_BUILTINS_METHOD */
 	ide_register_module(&idefloppy_module);
 	MOD_DEC_USE_COUNT;
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-geometry.c linux-2.4.21/drivers/ide/ide-geometry.c
--- linux-2.4.20/drivers/ide/ide-geometry.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-geometry.c	2002-12-18 18:58:01.000000000 +0000
@@ -6,8 +6,6 @@
 #include <linux/mc146818rtc.h>
 #include <asm/io.h>
 
-#ifdef CONFIG_BLK_DEV_IDE
-
 /*
  * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc
  * controller that is BIOS compatible with ST-506, and thus showing up in our
@@ -25,13 +23,11 @@
  * If a drive is not actually on the primary interface, then these parameters
  * will be ignored.  This results in the user having to supply the logical
  * drive geometry as a boot parameter for each drive not on the primary i/f.
- */
-/*
+ *
  * The only "perfect" way to handle this would be to modify the setup.[cS] code
  * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info
  * for us during initialization.  I have the necessary docs -- any takers?  -ml
- */
-/*
+ *
  * I did this, but it doesn't work - there is no reasonable way to find the
  * correspondence between the BIOS numbering of the disks and the Linux
  * numbering. -aeb
@@ -51,14 +47,13 @@
 {
 #ifdef __i386__
 	extern struct drive_info_struct drive_info;
-	byte cmos_disks, *BIOS = (byte *) &drive_info;
+	u8 cmos_disks, *BIOS = (u8 *) &drive_info;
 	int unit;
 	unsigned long flags;
 
-#ifdef CONFIG_BLK_DEV_PDC4030
 	if (hwif->chipset == ide_pdc4030 && hwif->channel != 0)
 		return;
-#endif /* CONFIG_BLK_DEV_PDC4030 */
+
 	spin_lock_irqsave(&rtc_lock, flags);
 	cmos_disks = CMOS_READ(0x12);
 	spin_unlock_irqrestore(&rtc_lock, flags);
@@ -68,7 +63,7 @@
 
 		if ((cmos_disks & (0xf0 >> (unit*4)))
 		   && !drive->present && !drive->nobios) {
-			unsigned short cyl = *(unsigned short *)BIOS;
+			u16 cyl = *(u16 *)BIOS;
 			unsigned char head = *(BIOS+2);
 			unsigned char sect = *(BIOS+14);
 			if (cyl > 0 && head > 0 && sect > 0 && sect < 64) {
@@ -86,10 +81,7 @@
 	}
 #endif
 }
-#endif /* CONFIG_BLK_DEV_IDE */
-
 
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 
 extern ide_drive_t * get_info_ptr(kdev_t);
 extern unsigned long current_capacity (ide_drive_t *);
@@ -98,10 +90,11 @@
  * If heads is nonzero: find a translation with this many heads and S=63.
  * Otherwise: find out how OnTrack Disk Manager would translate the disk.
  */
-static void
-ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) {
-	static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
-	const byte *headp = dm_head_vals;
+
+static void ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) 
+{
+	static const u8 dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
+	const u8 *headp = dm_head_vals;
 	unsigned long total;
 
 	/*
@@ -153,6 +146,7 @@
  * an IDE disk drive, or if a geometry was "forced" on the commandline.
  * Returns 1 if the geometry translation was successful.
  */
+
 int ide_xlate_1024 (kdev_t i_rdev, int xparm, int ptheads, const char *msg)
 {
 	ide_drive_t *drive;
@@ -217,8 +211,7 @@
 	drive->part[0].nr_sects = current_capacity(drive);
 
 	if (ret)
-		printk("%s%s [%d/%d/%d]", msg, msg1,
+		printk(KERN_INFO "%s%s [%d/%d/%d]", msg, msg1,
 		       drive->bios_cyl, drive->bios_head, drive->bios_sect);
 	return ret;
 }
-#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-io.c linux-2.4.21/drivers/ide/ide-io.c
--- linux-2.4.20/drivers/ide/ide-io.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-io.c	2002-12-18 18:58:03.000000000 +0000
@@ -0,0 +1,1334 @@
+/*
+ *	IDE I/O functions
+ *
+ *	Basic PIO and command management functionality.
+ *
+ * This code was split off from ide.c. See ide.c for history and original
+ * copyrights.
+ *
+ * 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, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open non patent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ */
+ 
+ 
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/blkpg.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/completion.h>
+#include <linux/reboot.h>
+#include <linux/cdrom.h>
+#include <linux/seq_file.h>
+#include <linux/kmod.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+#include "ide_modes.h"
+
+#if (DISK_RECOVERY_TIME > 0)
+
+Error So the User Has To Fix the Compilation And Stop Hacking Port 0x43
+Does anyone ever use this anyway ??
+
+/*
+ * For really screwy hardware (hey, at least it *can* be used with Linux)
+ * we can enforce a minimum delay time between successive operations.
+ */
+static unsigned long read_timer (ide_hwif_t *hwif)
+{
+	unsigned long t, flags;
+	int i;
+	
+	/* FIXME this is completely unsafe! */
+	local_irq_save(flags);
+	t = jiffies * 11932;
+	outb_p(0, 0x43);
+	i = inb_p(0x40);
+	i |= inb_p(0x40) << 8;
+	local_irq_restore(flags);
+	return (t - i);
+}
+#endif /* DISK_RECOVERY_TIME */
+
+static inline void set_recovery_timer (ide_hwif_t *hwif)
+{
+#if (DISK_RECOVERY_TIME > 0)
+	hwif->last_time = read_timer(hwif);
+#endif /* DISK_RECOVERY_TIME */
+}
+
+/*
+ *	ide_end_request		-	complete an IDE I/O
+ *	@drive: IDE device for the I/O
+ *	@uptodate: 
+ *
+ *	This is our end_request wrapper function. We complete the I/O
+ *	update random number input and dequeue the request.
+ */
+ 
+int ide_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		add_blkdev_randomness(MAJOR(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return ret;
+}
+
+EXPORT_SYMBOL(ide_end_request);
+
+/**
+ *	ide_end_drive_cmd	-	end an explicit drive command
+ *	@drive: command 
+ *	@stat: status bits
+ *	@err: error bits
+ *
+ *	Clean up after success/failure of an explicit drive command.
+ *	These get thrown onto the queue so they are synchronized with
+ *	real I/O operations on the drive.
+ *
+ *	In LBA48 mode we have to read the register set twice to get
+ *	all the extra information out.
+ */
+ 
+void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long flags;
+	struct request *rq;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	switch(rq->cmd) {
+		case IDE_DRIVE_CMD:
+		{
+			u8 *args = (u8 *) rq->buffer;
+			if (rq->errors == 0)
+				rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+
+			if (args) {
+				args[0] = stat;
+				args[1] = err;
+				args[2] = hwif->INB(IDE_NSECTOR_REG);
+			}
+			break;
+		}
+		case IDE_DRIVE_TASK:
+		{
+			u8 *args = (u8 *) rq->buffer;
+			if (rq->errors == 0)
+				rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+
+			if (args) {
+				args[0] = stat;
+				args[1] = err;
+				args[2] = hwif->INB(IDE_NSECTOR_REG);
+				args[3] = hwif->INB(IDE_SECTOR_REG);
+				args[4] = hwif->INB(IDE_LCYL_REG);
+				args[5] = hwif->INB(IDE_HCYL_REG);
+				args[6] = hwif->INB(IDE_SELECT_REG);
+			}
+			break;
+		}
+		case IDE_DRIVE_TASKFILE:
+		{
+			ide_task_t *args = (ide_task_t *) rq->special;
+			if (rq->errors == 0)
+				rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+				
+			if (args) {
+				if (args->tf_in_flags.b.data) {
+					u16 data			= hwif->INW(IDE_DATA_REG);
+					args->tfRegister[IDE_DATA_OFFSET]	= (data) & 0xFF;
+					args->hobRegister[IDE_DATA_OFFSET_HOB]	= (data >> 8) & 0xFF;
+				}
+				args->tfRegister[IDE_ERROR_OFFSET]   = err;
+				args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG);
+				args->tfRegister[IDE_SECTOR_OFFSET]  = hwif->INB(IDE_SECTOR_REG);
+				args->tfRegister[IDE_LCYL_OFFSET]    = hwif->INB(IDE_LCYL_REG);
+				args->tfRegister[IDE_HCYL_OFFSET]    = hwif->INB(IDE_HCYL_REG);
+				args->tfRegister[IDE_SELECT_OFFSET]  = hwif->INB(IDE_SELECT_REG);
+				args->tfRegister[IDE_STATUS_OFFSET]  = stat;
+
+				if (drive->addressing == 1) {
+					hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
+					args->hobRegister[IDE_FEATURE_OFFSET_HOB] = hwif->INB(IDE_FEATURE_REG);
+					args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = hwif->INB(IDE_NSECTOR_REG);
+					args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = hwif->INB(IDE_SECTOR_REG);
+					args->hobRegister[IDE_LCYL_OFFSET_HOB]    = hwif->INB(IDE_LCYL_REG);
+					args->hobRegister[IDE_HCYL_OFFSET_HOB]    = hwif->INB(IDE_HCYL_REG);
+				}
+			}
+			break;
+		}
+		default:
+			break;
+	}
+	spin_lock_irqsave(&io_request_lock, flags);
+	blkdev_dequeue_request(rq);
+	HWGROUP(drive)->rq = NULL;
+	end_that_request_last(rq);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+EXPORT_SYMBOL(ide_end_drive_cmd);
+
+/**
+ *	try_to_flush_leftover_data	-	flush junk
+ *	@drive: drive to flush
+ *
+ *	try_to_flush_leftover_data() is invoked in response to a drive
+ *	unexpectedly having its DRQ_STAT bit set.  As an alternative to
+ *	resetting the drive, this routine tries to clear the condition
+ *	by read a sector's worth of data from the drive.  Of course,
+ *	this may not help if the drive is *waiting* for data from *us*.
+ */
+void try_to_flush_leftover_data (ide_drive_t *drive)
+{
+	int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
+
+	if (drive->media != ide_disk)
+		return;
+	while (i > 0) {
+		u32 buffer[16];
+		u32 wcount = (i > 16) ? 16 : i;
+
+		i -= wcount;
+		HWIF(drive)->ata_input_data(drive, buffer, wcount);
+	}
+}
+
+EXPORT_SYMBOL(try_to_flush_leftover_data);
+
+/*
+ * FIXME Add an ATAPI error
+ */
+
+/**
+ *	ide_error	-	handle an error on the IDE
+ *	@drive: drive the error occurred on
+ *	@msg: message to report
+ *	@stat: status bits
+ *
+ *	ide_error() takes action based on the error returned by the drive.
+ *	For normal I/O that may well include retries. We deal with
+ *	both new-style (taskfile) and old style command handling here.
+ *	In the case of taskfile command handling there is work left to
+ *	do
+ */
+ 
+ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, u8 stat)
+{
+	ide_hwif_t *hwif;
+	struct request *rq;
+	u8 err;
+
+	err = ide_dump_status(drive, msg, stat);
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+
+	hwif = HWIF(drive);
+	/* retry only "normal" I/O: */
+	if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) {
+		rq->errors = 1;
+		ide_end_drive_cmd(drive, stat, err);
+		return ide_stopped;
+	}
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		rq->errors = 1;
+		ide_end_drive_cmd(drive, stat, err);
+//		ide_end_taskfile(drive, stat, err);
+		return ide_stopped;
+	}
+
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
+		 /* other bits are useless when BUSY */
+		rq->errors |= ERROR_RESET;
+	} else {
+		if (drive->media != ide_disk)
+			goto media_out;
+
+		if (stat & ERR_STAT) {
+			/* err has different meaning on cdrom and tape */
+			if (err == ABRT_ERR) {
+				if (drive->select.b.lba &&
+				    (hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY))
+					/* some newer drives don't
+					 * support WIN_SPECIFY
+					 */
+					return ide_stopped;
+			} else if ((err & BAD_CRC) == BAD_CRC) {
+				drive->crc_count++;
+				/* UDMA crc error -- just retry the operation */
+			} else if (err & (BBD_ERR | ECC_ERR)) {
+				/* retries won't help these */
+				rq->errors = ERROR_MAX;
+			} else if (err & TRK0_ERR) {
+				/* help it find track zero */
+				rq->errors |= ERROR_RECAL;
+			}
+		}
+media_out:
+		if ((stat & DRQ_STAT) && rq->cmd != WRITE)
+			try_to_flush_leftover_data(drive);
+	}
+	if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) {
+		/* force an abort */
+		hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
+	}
+	if (rq->errors >= ERROR_MAX) {
+		if (drive->driver != NULL)
+			DRIVER(drive)->end_request(drive, 0);
+		else
+	 		ide_end_request(drive, 0);
+	} else {
+		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+			++rq->errors;
+			return ide_do_reset(drive);
+		}
+		if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
+			drive->special.b.recalibrate = 1;
+		++rq->errors;
+	}
+	return ide_stopped;
+}
+
+EXPORT_SYMBOL(ide_error);
+
+/**
+ *	ide_cmd		-	issue a simple drive command
+ *	@drive: drive the command is for
+ *	@cmd: command byte
+ *	@nsect: sector byte
+ *	@handler: handler for the command completion
+ *
+ *	Issue a simple drive command with interrupts.
+ *	The drive must be selected beforehand.
+ */
+
+void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, ide_handler_t *handler)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, handler, WAIT_CMD, NULL);
+	if (IDE_CONTROL_REG)
+		hwif->OUTB(drive->ctl,IDE_CONTROL_REG);	/* clear nIEN */
+	SELECT_MASK(drive,0);
+	hwif->OUTB(nsect,IDE_NSECTOR_REG);
+	hwif->OUTB(cmd,IDE_COMMAND_REG);
+}
+
+EXPORT_SYMBOL(ide_cmd);
+
+/**
+ *	drive_cmd_intr		- 	drive command completion interrupt
+ *	@drive: drive the completion interrupt occurred on
+ *
+ *	drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
+ *	We do any neccessary daya reading and then wait for the drive to
+ *	go non busy. At that point we may read the error data and complete
+ *	the request
+ */
+ 
+ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
+{
+	struct request *rq = HWGROUP(drive)->rq;
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 *args = (u8 *) rq->buffer;
+	u8 stat = hwif->INB(IDE_STATUS_REG);
+	int retries = 10;
+
+	local_irq_enable();
+	if ((stat & DRQ_STAT) && args && args[3]) {
+		u8 io_32bit = drive->io_32bit;
+		drive->io_32bit = 0;
+		hwif->ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
+		drive->io_32bit = io_32bit;
+		while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+			udelay(100);
+	}
+
+	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
+		return DRIVER(drive)->error(drive, "drive_cmd", stat);
+		/* calls ide_end_drive_cmd */
+	ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
+	return ide_stopped;
+}
+
+EXPORT_SYMBOL(drive_cmd_intr);
+
+/**
+ *	do_special		-	issue some special commands
+ *	@drive: drive the command is for
+ *
+ *	do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
+ *	commands to a drive.  It used to do much more, but has been scaled
+ *	back.
+ */
+
+ide_startstop_t do_special (ide_drive_t *drive)
+{
+	special_t *s = &drive->special;
+
+#ifdef DEBUG
+	printk("%s: do_special: 0x%02x\n", drive->name, s->all);
+#endif
+	if (s->b.set_tune) {
+		s->b.set_tune = 0;
+		if (HWIF(drive)->tuneproc != NULL)
+			HWIF(drive)->tuneproc(drive, drive->tune_req);
+	} else if (drive->driver != NULL) {
+		return DRIVER(drive)->special(drive);
+	} else if (s->all) {
+		printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, s->all);
+		s->all = 0;
+	}
+	return ide_stopped;
+}
+
+EXPORT_SYMBOL(do_special);
+
+/**
+ *	execute_drive_command	-	issue special drive command
+ *	@drive: the drive to issue th command on
+ *	@rq: the request structure holding the command
+ *
+ *	execute_drive_cmd() issues a special drive command,  usually 
+ *	initiated by ioctl() from the external hdparm program. The
+ *	command can be a drive command, drive task or taskfile 
+ *	operation. Weirdly you can call it with NULL to wait for
+ *	all commands to finish. Don't do this as that is due to change
+ */
+
+ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+ 	switch(rq->cmd) {
+ 		case IDE_DRIVE_TASKFILE:
+ 		{
+ 			ide_task_t *args = rq->special;
+ 
+ 			if (!(args)) break;
+ 
+			if (args->tf_out_flags.all != 0) 
+				return flagged_taskfile(drive, args);
+			return do_rw_taskfile(drive, args);
+ 		}
+ 		case IDE_DRIVE_TASK:
+ 		{
+ 			u8 *args = rq->buffer;
+ 			u8 sel;
+ 
+ 			if (!(args)) break;
+#ifdef DEBUG
+ 			printk("%s: DRIVE_TASK_CMD ", drive->name);
+ 			printk("cmd=0x%02x ", args[0]);
+ 			printk("fr=0x%02x ", args[1]);
+ 			printk("ns=0x%02x ", args[2]);
+ 			printk("sc=0x%02x ", args[3]);
+ 			printk("lcyl=0x%02x ", args[4]);
+ 			printk("hcyl=0x%02x ", args[5]);
+ 			printk("sel=0x%02x\n", args[6]);
+#endif
+ 			hwif->OUTB(args[1], IDE_FEATURE_REG);
+ 			hwif->OUTB(args[3], IDE_SECTOR_REG);
+ 			hwif->OUTB(args[4], IDE_LCYL_REG);
+ 			hwif->OUTB(args[5], IDE_HCYL_REG);
+ 			sel = (args[6] & ~0x10);
+ 			if (drive->select.b.unit)
+ 				sel |= 0x10;
+ 			hwif->OUTB(sel, IDE_SELECT_REG);
+ 			ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
+ 			return ide_started;
+ 		}
+ 		case IDE_DRIVE_CMD:
+ 		{
+ 			u8 *args = rq->buffer;
+ 
+ 			if (!(args)) break;
+#ifdef DEBUG
+ 			printk("%s: DRIVE_CMD ", drive->name);
+ 			printk("cmd=0x%02x ", args[0]);
+ 			printk("sc=0x%02x ", args[1]);
+ 			printk("fr=0x%02x ", args[2]);
+ 			printk("xx=0x%02x\n", args[3]);
+#endif
+ 			if (args[0] == WIN_SMART) {
+ 				hwif->OUTB(0x4f, IDE_LCYL_REG);
+ 				hwif->OUTB(0xc2, IDE_HCYL_REG);
+ 				hwif->OUTB(args[2],IDE_FEATURE_REG);
+ 				hwif->OUTB(args[1],IDE_SECTOR_REG);
+ 				ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
+ 				return ide_started;
+ 			}
+ 			hwif->OUTB(args[2],IDE_FEATURE_REG);
+ 			ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
+ 			return ide_started;
+ 		}
+ 		default:
+ 			break;
+ 	}
+ 	/*
+ 	 * NULL is actually a valid way of waiting for
+ 	 * all current requests to be flushed from the queue.
+ 	 */
+#ifdef DEBUG
+ 	printk("%s: DRIVE_CMD (null)\n", drive->name);
+#endif
+ 	ide_end_drive_cmd(drive,
+			hwif->INB(IDE_STATUS_REG),
+			hwif->INB(IDE_ERROR_REG));
+ 	return ide_stopped;
+}
+
+EXPORT_SYMBOL(execute_drive_cmd);
+
+/**
+ *	start_request	-	start of I/O and command issuing for IDE
+ *
+ *	start_request() initiates handling of a new I/O request. It
+ *	accepts commands and I/O (read/write) requests. It also does
+ *	the final remapping for weird stuff like EZDrive. Once 
+ *	device mapper can work sector level the EZDrive stuff can go away
+ *
+ *	FIXME: this function needs a rename
+ */
+ 
+ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
+{
+	ide_startstop_t startstop;
+	unsigned long block, blockend;
+	unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS;
+	ide_hwif_t *hwif = HWIF(drive);
+
+#ifdef DEBUG
+	printk("%s: start_request: current=0x%08lx\n",
+		hwif->name, (unsigned long) rq);
+#endif
+
+	/* bail early if we've exceeded max_failures */
+	if (drive->max_failures && (drive->failures > drive->max_failures)) {
+		goto kill_rq;
+	}
+
+	/*
+	 * bail early if we've sent a device to sleep, however how to wake
+	 * this needs to be a masked flag.  FIXME for proper operations.
+	 */
+	if (drive->suspend_reset) {
+		goto kill_rq;
+	}
+
+	if (unit >= MAX_DRIVES) {
+		printk(KERN_ERR "%s: bad device number: %s\n",
+			hwif->name, kdevname(rq->rq_dev));
+		goto kill_rq;
+	}
+#ifdef DEBUG
+	if (rq->bh && !buffer_locked(rq->bh)) {
+		printk(KERN_ERR "%s: block not locked\n", drive->name);
+		goto kill_rq;
+	}
+#endif
+	block    = rq->sector;
+	blockend = block + rq->nr_sectors;
+
+	if (blk_fs_request(rq) &&
+	    (drive->media == ide_disk || drive->media == ide_floppy)) {
+		if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) {
+			printk(KERN_ERR "%s%c: bad access: block=%ld, count=%ld\n", drive->name,
+			 (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors);
+			goto kill_rq;
+		}
+		block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0;
+	}
+	/* Yecch - this will shift the entire interval,
+	   possibly killing some innocent following sector */
+	if (block == 0 && drive->remap_0_to_1 == 1)
+		block = 1;  /* redirect MBR access to EZ-Drive partn table */
+
+#if (DISK_RECOVERY_TIME > 0)
+	while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
+#endif
+
+	SELECT_DRIVE(drive);
+	if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
+		printk(KERN_ERR "%s: drive not ready for command\n", drive->name);
+		return startstop;
+	}
+	if (!drive->special.all) {
+		switch(rq->cmd) {
+			case IDE_DRIVE_CMD:
+			case IDE_DRIVE_TASK:
+				return execute_drive_cmd(drive, rq);
+			case IDE_DRIVE_TASKFILE:
+				return execute_drive_cmd(drive, rq);
+			default:
+				break;
+		}
+		if (drive->driver != NULL) {
+			return (DRIVER(drive)->do_request(drive, rq, block));
+		}
+		printk(KERN_WARNING "%s: media type %d not supported\n", drive->name, drive->media);
+		goto kill_rq;
+	}
+	return do_special(drive);
+kill_rq:
+	if (drive->driver != NULL)
+		DRIVER(drive)->end_request(drive, 0);
+	else
+		ide_end_request(drive, 0);
+	return ide_stopped;
+}
+
+EXPORT_SYMBOL(start_request);
+
+int restart_request (ide_drive_t *drive, struct request *rq)
+{
+	(void) start_request(drive, rq);
+	return 0;
+}
+
+EXPORT_SYMBOL(restart_request);
+
+/**
+ *	ide_stall_queue		-	pause an IDE device
+ *	@drive: drive to stall
+ *	@timeout: time to stall for (jiffies)
+ *
+ *	ide_stall_queue() can be used by a drive to give excess bandwidth back
+ *	to the hwgroup by sleeping for timeout jiffies.
+ */
+ 
+void ide_stall_queue (ide_drive_t *drive, unsigned long timeout)
+{
+	if (timeout > WAIT_WORSTCASE)
+		timeout = WAIT_WORSTCASE;
+	drive->sleep = timeout + jiffies;
+}
+
+EXPORT_SYMBOL(ide_stall_queue);
+
+#define WAKEUP(drive)	((drive)->service_start + 2 * (drive)->service_time)
+
+/**
+ *	choose_drive		-	select a drive to service
+ *	@hwgroup: hardware group to select on
+ *
+ *	choose_drive() selects the next drive which will be serviced.
+ *	This is neccessary because the IDE layer can't issue commands
+ *	to both drives on the same cable, unlike SCSI.
+ */
+ 
+static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup)
+{
+	ide_drive_t *drive, *best;
+
+repeat:	
+	best = NULL;
+	drive = hwgroup->drive;
+	do {
+		if (!blk_queue_empty(&drive->queue) && (!drive->sleep || time_after_eq(jiffies, drive->sleep))) {
+			if (!best
+			 || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep)))
+			 || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive))))
+			{
+				if (!blk_queue_plugged(&drive->queue))
+					best = drive;
+			}
+		}
+	} while ((drive = drive->next) != hwgroup->drive);
+	if (best && best->nice1 && !best->sleep && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) {
+		long t = (signed long)(WAKEUP(best) - jiffies);
+		if (t >= WAIT_MIN_SLEEP) {
+		/*
+		 * We *may* have some time to spare, but first let's see if
+		 * someone can potentially benefit from our nice mood today..
+		 */
+			drive = best->next;
+			do {
+				if (!drive->sleep
+				 && 0 < (signed long)(WAKEUP(drive) - (jiffies - best->service_time))
+				 && 0 < (signed long)((jiffies + t) - WAKEUP(drive)))
+				{
+					ide_stall_queue(best, IDE_MIN(t, 10 * WAIT_MIN_SLEEP));
+					goto repeat;
+				}
+			} while ((drive = drive->next) != best);
+		}
+	}
+	return best;
+}
+
+/*
+ * Issue a new request to a drive from hwgroup
+ * Caller must have already done spin_lock_irqsave(&io_request_lock, ..);
+ *
+ * A hwgroup is a serialized group of IDE interfaces.  Usually there is
+ * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640)
+ * may have both interfaces in a single hwgroup to "serialize" access.
+ * Or possibly multiple ISA interfaces can share a common IRQ by being grouped
+ * together into one hwgroup for serialized access.
+ *
+ * Note also that several hwgroups can end up sharing a single IRQ,
+ * possibly along with many other devices.  This is especially common in
+ * PCI-based systems with off-board IDE controller cards.
+ *
+ * The IDE driver uses the single global io_request_lock spinlock to protect
+ * access to the request queues, and to protect the hwgroup->busy flag.
+ *
+ * The first thread into the driver for a particular hwgroup sets the
+ * hwgroup->busy flag to indicate that this hwgroup is now active,
+ * and then initiates processing of the top request from the request queue.
+ *
+ * Other threads attempting entry notice the busy setting, and will simply
+ * queue their new requests and exit immediately.  Note that hwgroup->busy
+ * remains set even when the driver is merely awaiting the next interrupt.
+ * Thus, the meaning is "this hwgroup is busy processing a request".
+ *
+ * When processing of a request completes, the completing thread or IRQ-handler
+ * will start the next request from the queue.  If no more work remains,
+ * the driver will clear the hwgroup->busy flag and exit.
+ *
+ * The io_request_lock (spinlock) is used to protect all access to the
+ * hwgroup->busy flag, but is otherwise not needed for most processing in
+ * the driver.  This makes the driver much more friendlier to shared IRQs
+ * than previous designs, while remaining 100% (?) SMP safe and capable.
+ */
+/* --BenH: made non-static as ide-pmac.c uses it to kick the hwgroup back
+ *         into life on wakeup from machine sleep.
+ */ 
+void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
+{
+	ide_drive_t	*drive;
+	ide_hwif_t	*hwif;
+	struct request	*rq;
+	ide_startstop_t	startstop;
+
+	/* for atari only: POSSIBLY BROKEN HERE(?) */
+	ide_get_lock(&ide_intr_lock, ide_intr, hwgroup);
+
+	/* necessary paranoia: ensure IRQs are masked on local CPU */
+	local_irq_disable();
+
+	while (!hwgroup->busy) {
+		hwgroup->busy = 1;
+		drive = choose_drive(hwgroup);
+		if (drive == NULL) {
+			unsigned long sleep = 0;
+			hwgroup->rq = NULL;
+			drive = hwgroup->drive;
+			do {
+				if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep)))
+					sleep = drive->sleep;
+			} while ((drive = drive->next) != hwgroup->drive);
+			if (sleep) {
+		/*
+		 * Take a short snooze, and then wake up this hwgroup again.
+		 * This gives other hwgroups on the same a chance to
+		 * play fairly with us, just in case there are big differences
+		 * in relative throughputs.. don't want to hog the cpu too much.
+		 */
+				if (time_before(sleep, jiffies + WAIT_MIN_SLEEP))
+					sleep = jiffies + WAIT_MIN_SLEEP;
+#if 1
+				if (timer_pending(&hwgroup->timer))
+					printk(KERN_ERR "ide_set_handler: timer already active\n");
+#endif
+				/* so that ide_timer_expiry knows what to do */
+				hwgroup->sleeping = 1;
+				mod_timer(&hwgroup->timer, sleep);
+				/* we purposely leave hwgroup->busy==1
+				 * while sleeping */
+			} else {
+				/* Ugly, but how can we sleep for the lock
+				 * otherwise? perhaps from tq_disk?
+				 */
+
+				/* for atari only */
+				ide_release_lock(&ide_intr_lock);
+				hwgroup->busy = 0;
+			}
+			/* no more work for this hwgroup (for now) */
+			return;
+		}
+		hwif = HWIF(drive);
+		if (hwgroup->hwif->sharing_irq &&
+		    hwif != hwgroup->hwif &&
+		    hwif->io_ports[IDE_CONTROL_OFFSET]) {
+			/* set nIEN for previous hwif */
+			SELECT_INTERRUPT(drive);
+		}
+		hwgroup->hwif = hwif;
+		hwgroup->drive = drive;
+		drive->sleep = 0;
+		drive->service_start = jiffies;
+
+		/* paranoia */
+		if (blk_queue_plugged(&drive->queue))
+			printk(KERN_ERR "%s: Huh? nuking plugged queue\n", drive->name);
+
+		rq = blkdev_entry_next_request(&drive->queue.queue_head);
+		hwgroup->rq = rq;
+		/*
+		 * Some systems have trouble with IDE IRQs arriving while
+		 * the driver is still setting things up.  So, here we disable
+		 * the IRQ used by this interface while the request is being started.
+		 * This may look bad at first, but pretty much the same thing
+		 * happens anyway when any interrupt comes in, IDE or otherwise
+		 *  -- the kernel masks the IRQ while it is being handled.
+		 */
+		if (masked_irq && hwif->irq != masked_irq)
+			disable_irq_nosync(hwif->irq);
+		spin_unlock(&io_request_lock);
+		local_irq_enable();
+			/* allow other IRQs while we start this request */
+		startstop = start_request(drive, rq);
+		spin_lock_irq(&io_request_lock);
+		if (masked_irq && hwif->irq != masked_irq)
+			enable_irq(hwif->irq);
+		if (startstop == ide_stopped)
+			hwgroup->busy = 0;
+	}
+}
+
+EXPORT_SYMBOL(ide_do_request);
+
+/*
+ * ide_get_queue() returns the queue which corresponds to a given device.
+ */
+request_queue_t *ide_get_queue (kdev_t dev)
+{
+	ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[MAJOR(dev)].data;
+
+	return &hwif->drives[DEVICE_NR(dev) & 1].queue;
+}
+
+EXPORT_SYMBOL(ide_get_queue);
+
+/*
+ * Passes the stuff to ide_do_request
+ */
+void do_ide_request(request_queue_t *q)
+{
+	ide_do_request(q->queuedata, 0);
+}
+
+/*
+ * un-busy the hwgroup etc, and clear any pending DMA status. we want to
+ * retry the current request in pio mode instead of risking tossing it
+ * all away
+ */
+void ide_dma_timeout_retry(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct request *rq;
+
+	/*
+	 * end current dma transaction
+	 */
+	(void) hwif->ide_dma_end(drive);
+
+	/*
+	 * complain a little, later we might remove some of this verbosity
+	 */
+	printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
+	(void) hwif->ide_dma_timeout(drive);
+
+	/*
+	 * disable dma for now, but remember that we did so because of
+	 * a timeout -- we'll reenable after we finish this next request
+	 * (or rather the first chunk of it) in pio.
+	 */
+	drive->retry_pio++;
+	drive->state = DMA_PIO_RETRY;
+	(void) hwif->ide_dma_off_quietly(drive);
+
+	/*
+	 * un-busy drive etc (hwgroup->busy is cleared on return) and
+	 * make sure request is sane
+	 */
+	rq = HWGROUP(drive)->rq;
+	HWGROUP(drive)->rq = NULL;
+
+	rq->errors = 0;
+	rq->sector = rq->bh->b_rsector;
+	rq->current_nr_sectors = rq->bh->b_size >> 9;
+	rq->hard_cur_sectors = rq->current_nr_sectors;
+	rq->buffer = rq->bh->b_data;
+}
+
+EXPORT_SYMBOL(ide_dma_timeout_retry);
+
+/**
+ *	ide_timer_expiry	-	handle lack of an IDE interrupt
+ *	@data: timer callback magic (hwgroup)
+ *
+ *	An IDE command has timed out before the expected drive return
+ *	occurred. At this point we attempt to clean up the current
+ *	mess. If the current handler includes an expiry handler then
+ *	we invoke the expiry handler, and providing it is happy the
+ *	work is done. If that fails we apply generic recovery rules
+ *	invoking the handler and checking the drive DMA status. We
+ *	have an excessively incestuous relationship with the DMA
+ *	logic that wants cleaning up.
+ */
+ 
+void ide_timer_expiry (unsigned long data)
+{
+	ide_hwgroup_t	*hwgroup = (ide_hwgroup_t *) data;
+	ide_handler_t	*handler;
+	ide_expiry_t	*expiry;
+ 	unsigned long	flags;
+	unsigned long	wait;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	del_timer(&hwgroup->timer);
+
+	if ((handler = hwgroup->handler) == NULL) {
+		/*
+		 * Either a marginal timeout occurred
+		 * (got the interrupt just as timer expired),
+		 * or we were "sleeping" to give other devices a chance.
+		 * Either way, we don't really want to complain about anything.
+		 */
+		if (hwgroup->sleeping) {
+			hwgroup->sleeping = 0;
+			hwgroup->busy = 0;
+		}
+	} else {
+		ide_drive_t *drive = hwgroup->drive;
+		if (!drive) {
+			printk(KERN_ERR "ide_timer_expiry: hwgroup->drive was NULL\n");
+			hwgroup->handler = NULL;
+		} else {
+			ide_hwif_t *hwif;
+			ide_startstop_t startstop = ide_stopped;
+			if (!hwgroup->busy) {
+				hwgroup->busy = 1;	/* paranoia */
+				printk(KERN_ERR "%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name);
+			}
+			if ((expiry = hwgroup->expiry) != NULL) {
+				/* continue */
+				if ((wait = expiry(drive)) != 0) {
+					/* reset timer */
+					hwgroup->timer.expires  = jiffies + wait;
+					add_timer(&hwgroup->timer);
+					spin_unlock_irqrestore(&io_request_lock, flags);
+					return;
+				}
+			}
+			hwgroup->handler = NULL;
+			/*
+			 * We need to simulate a real interrupt when invoking
+			 * the handler() function, which means we need to
+			 * globally mask the specific IRQ:
+			 */
+			spin_unlock(&io_request_lock);
+			hwif  = HWIF(drive);
+#if DISABLE_IRQ_NOSYNC
+			disable_irq_nosync(hwif->irq);
+#else
+			/* disable_irq_nosync ?? */
+			disable_irq(hwif->irq);
+#endif /* DISABLE_IRQ_NOSYNC */
+
+			/* local CPU only,
+			 * as if we were handling an interrupt */
+			local_irq_disable();
+			if (hwgroup->poll_timeout != 0) {
+				startstop = handler(drive);
+			} else if (drive_is_ready(drive)) {
+				if (drive->waiting_for_dma)
+					(void) hwgroup->hwif->ide_dma_lostirq(drive);
+				(void)ide_ack_intr(hwif);
+				printk(KERN_ERR "%s: lost interrupt\n", drive->name);
+				startstop = handler(drive);
+			} else {
+				if (drive->waiting_for_dma) {
+					startstop = ide_stopped;
+					ide_dma_timeout_retry(drive);
+				} else
+					startstop = DRIVER(drive)->error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG));
+			}
+			set_recovery_timer(hwif);
+			drive->service_time = jiffies - drive->service_start;
+			enable_irq(hwif->irq);
+			spin_lock_irq(&io_request_lock);
+			if (startstop == ide_stopped)
+				hwgroup->busy = 0;
+		}
+	}
+	ide_do_request(hwgroup, 0);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+EXPORT_SYMBOL(ide_timer_expiry);
+
+/**
+ *	unexpected_intr		-	handle an unexpected IDE interrupt
+ *	@irq: interrupt line
+ *	@hwgroup: hwgroup being processed
+ *
+ *	There's nothing really useful we can do with an unexpected interrupt,
+ *	other than reading the status register (to clear it), and logging it.
+ *	There should be no way that an irq can happen before we're ready for it,
+ *	so we needn't worry much about losing an "important" interrupt here.
+ *
+ *	On laptops (and "green" PCs), an unexpected interrupt occurs whenever
+ *	the drive enters "idle", "standby", or "sleep" mode, so if the status
+ *	looks "good", we just ignore the interrupt completely.
+ *
+ *	This routine assumes __cli() is in effect when called.
+ *
+ *	If an unexpected interrupt happens on irq15 while we are handling irq14
+ *	and if the two interfaces are "serialized" (CMD640), then it looks like
+ *	we could screw up by interfering with a new request being set up for 
+ *	irq15.
+ *
+ *	In reality, this is a non-issue.  The new command is not sent unless 
+ *	the drive is ready to accept one, in which case we know the drive is
+ *	not trying to interrupt us.  And ide_set_handler() is always invoked
+ *	before completing the issuance of any new drive command, so we will not
+ *	be accidentally invoked as a result of any valid command completion
+ *	interrupt.
+ *
+ *	Note that we must walk the entire hwgroup here. We know which hwif
+ *	is doing the current command, but we don't know which hwif burped
+ *	mysteriously.
+ */
+ 
+static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
+{
+	u8 stat;
+	ide_hwif_t *hwif = hwgroup->hwif;
+
+	/*
+	 * handle the unexpected interrupt
+	 */
+	do {
+		if (hwif->irq == irq) {
+			stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+			if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
+				/* Try to not flood the console with msgs */
+				static unsigned long last_msgtime, count;
+				++count;
+				if (time_after(jiffies, last_msgtime + HZ)) {
+					last_msgtime = jiffies;
+					printk(KERN_ERR "%s%s: unexpected interrupt, "
+						"status=0x%02x, count=%ld\n",
+						hwif->name,
+						(hwif->next==hwgroup->hwif) ? "" : "(?)", stat, count);
+				}
+			}
+		}
+	} while ((hwif = hwif->next) != hwgroup->hwif);
+}
+
+/**
+ *	ide_intr	-	default IDE interrupt handler
+ *	@irq: interrupt number
+ *	@dev_id: hwif group
+ *	@regs: unused weirdness from the kernel irq layer
+ *
+ *	This is the default IRQ handler for the IDE layer. You should
+ *	not need to override it. If you do be aware it is subtle in
+ *	places
+ *
+ *	hwgroup->hwif is the interface in the group currently performing
+ *	a command. hwgroup->drive is the drive and hwgroup->handler is
+ *	the IRQ handler to call. As we issue a command the handlers
+ *	step through multiple states, reassigning the handler to the
+ *	next step in the process. Unlike a smart SCSI controller IDE
+ *	expects the main processor to sequence the various transfer
+ *	stages. We also manage a poll timer to catch up with most
+ *	timeout situations. There are still a few where the handlers
+ *	don't ever decide to give up.
+ *
+ *	The handler eventually returns ide_stopped to indicate the
+ *	request completed. At this point we issue the next request
+ *	on the hwgroup and the process begins again.
+ */
+ 
+void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;
+	ide_hwif_t *hwif;
+	ide_drive_t *drive;
+	ide_handler_t *handler;
+	ide_startstop_t startstop;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	hwif = hwgroup->hwif;
+
+	if (!ide_ack_intr(hwif)) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+
+	if ((handler = hwgroup->handler) == NULL ||
+	    hwgroup->poll_timeout != 0) {
+		/*
+		 * Not expecting an interrupt from this drive.
+		 * That means this could be:
+		 *	(1) an interrupt from another PCI device
+		 *	sharing the same PCI INT# as us.
+		 * or	(2) a drive just entered sleep or standby mode,
+		 *	and is interrupting to let us know.
+		 * or	(3) a spurious interrupt of unknown origin.
+		 *
+		 * For PCI, we cannot tell the difference,
+		 * so in that case we just ignore it and hope it goes away.
+		 */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+		if (hwif->pci_dev && !hwif->pci_dev->vendor)
+#endif	/* CONFIG_BLK_DEV_IDEPCI */
+		{
+			/*
+			 * Probably not a shared PCI interrupt,
+			 * so we can safely try to do something about it:
+			 */
+			unexpected_intr(irq, hwgroup);
+#ifdef CONFIG_BLK_DEV_IDEPCI
+		} else {
+			/*
+			 * Whack the status register, just in case
+			 * we have a leftover pending IRQ.
+			 */
+			(void) hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+		}
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+	drive = hwgroup->drive;
+	if (!drive) {
+		/*
+		 * This should NEVER happen, and there isn't much
+		 * we could do about it here.
+		 */
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+	if (!drive_is_ready(drive)) {
+		/*
+		 * This happens regularly when we share a PCI IRQ with
+		 * another device.  Unfortunately, it can also happen
+		 * with some buggy drives that trigger the IRQ before
+		 * their status register is up to date.  Hopefully we have
+		 * enough advance overhead that the latter isn't a problem.
+		 */
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+	if (!hwgroup->busy) {
+		hwgroup->busy = 1;	/* paranoia */
+		printk(KERN_ERR "%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name);
+	}
+	hwgroup->handler = NULL;
+	del_timer(&hwgroup->timer);
+	spin_unlock(&io_request_lock);
+
+	if (drive->unmask)
+		local_irq_enable();
+
+	/* service this interrupt, may set handler for next interrupt */
+	startstop = handler(drive);
+	spin_lock_irq(&io_request_lock);
+
+	/*
+	 * Note that handler() may have set things up for another
+	 * interrupt to occur soon, but it cannot happen until
+	 * we exit from this routine, because it will be the
+	 * same irq as is currently being serviced here, and Linux
+	 * won't allow another of the same (on any CPU) until we return.
+	 */
+	set_recovery_timer(HWIF(drive));
+	drive->service_time = jiffies - drive->service_start;
+	if (startstop == ide_stopped) {
+		if (hwgroup->handler == NULL) {	/* paranoia */
+			hwgroup->busy = 0;
+			ide_do_request(hwgroup, hwif->irq);
+		} else {
+			printk(KERN_ERR "%s: ide_intr: huh? expected NULL handler "
+				"on exit\n", drive->name);
+		}
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+EXPORT_SYMBOL(ide_intr);
+
+/*
+ * get_info_ptr() returns the (ide_drive_t *) for a given device number.
+ * It returns NULL if the given device number does not match any present drives.
+ */
+ide_drive_t *get_info_ptr (kdev_t i_rdev)
+{
+	int		major = MAJOR(i_rdev);
+	unsigned int	h;
+
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		ide_hwif_t  *hwif = &ide_hwifs[h];
+		if (hwif->present && major == hwif->major) {
+			unsigned unit = DEVICE_NR(i_rdev);
+			if (unit < MAX_DRIVES) {
+				ide_drive_t *drive = &hwif->drives[unit];
+				if (drive->present)
+					return drive;
+			}
+			break;
+		}
+	}
+	return NULL;
+}
+
+EXPORT_SYMBOL(get_info_ptr);
+
+/**
+ *	ide_init_drive_cmd	-	initialize a drive command request
+ *	@rq: request object
+ *
+ *	Initialize a request before we fill it in and send it down to
+ *	ide_do_drive_cmd. Commands must be set up by this function. Right
+ *	now it doesn't do a lot, but if that changes abusers will have a
+ *	nasty suprise.
+ */
+
+void ide_init_drive_cmd (struct request *rq)
+{
+	memset(rq, 0, sizeof(*rq));
+	rq->cmd = IDE_DRIVE_CMD;
+}
+
+EXPORT_SYMBOL(ide_init_drive_cmd);
+
+/**
+ *	ide_do_drive_cmd	-	issue IDE special command
+ *	@drive: device to issue command
+ *	@rq: request to issue
+ *	@action: action for processing
+ *
+ *	This function issues a special IDE device request
+ *	onto the request queue.
+ *
+ *	If action is ide_wait, then the rq is queued at the end of the
+ *	request queue, and the function sleeps until it has been processed.
+ *	This is for use when invoked from an ioctl handler.
+ *
+ *	If action is ide_preempt, then the rq is queued at the head of
+ *	the request queue, displacing the currently-being-processed
+ *	request and this function returns immediately without waiting
+ *	for the new rq to be completed.  This is VERY DANGEROUS, and is
+ *	intended for careful use by the ATAPI tape/cdrom driver code.
+ *
+ *	If action is ide_next, then the rq is queued immediately after
+ *	the currently-being-processed-request (if any), and the function
+ *	returns without waiting for the new rq to be completed.  As above,
+ *	This is VERY DANGEROUS, and is intended for careful use by the
+ *	ATAPI tape/cdrom driver code.
+ *
+ *	If action is ide_end, then the rq is queued at the end of the
+ *	request queue, and the function returns immediately without waiting
+ *	for the new rq to be completed. This is again intended for careful
+ *	use by the ATAPI tape/cdrom driver code.
+ */
+ 
+int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action)
+{
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	unsigned int major = HWIF(drive)->major;
+	request_queue_t *q = &drive->queue;
+	struct list_head *queue_head = &q->queue_head;
+	DECLARE_COMPLETION(wait);
+
+#ifdef CONFIG_BLK_DEV_PDC4030
+	if (HWIF(drive)->chipset == ide_pdc4030 && rq->buffer != NULL)
+		return -ENOSYS;  /* special drive cmds not supported */
+#endif
+	rq->errors = 0;
+	rq->rq_status = RQ_ACTIVE;
+	rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);
+	if (action == ide_wait)
+		rq->waiting = &wait;
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (blk_queue_empty(q) || action == ide_preempt) {
+		if (action == ide_preempt)
+			hwgroup->rq = NULL;
+	} else {
+		if (action == ide_wait || action == ide_end) {
+			queue_head = queue_head->prev;
+		} else
+			queue_head = queue_head->next;
+	}
+	list_add(&rq->queue, queue_head);
+	ide_do_request(hwgroup, 0);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	if (action == ide_wait) {
+		/* wait for it to be serviced */
+		wait_for_completion(&wait);
+		/* return -EIO if errors */
+		return rq->errors ? -EIO : 0;
+	}
+	return 0;
+
+}
+
+EXPORT_SYMBOL(ide_do_drive_cmd);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-iops.c linux-2.4.21/drivers/ide/ide-iops.c
--- linux-2.4.20/drivers/ide/ide-iops.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-iops.c	2002-12-18 18:58:09.000000000 +0000
@@ -0,0 +1,1232 @@
+/*
+ * linux/drivers/ide/ide-iops.c	Version 0.33	April 11, 2002
+ *
+ *  Copyright (C) 2000-2002	Andre Hedrick <andre@linux-ide.org>
+ *
+ *
+ */
+
+#include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/blkpg.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+
+static u8 ide_inb (unsigned long port)
+{
+	return (u8) inb(port);
+}
+
+static u16 ide_inw (unsigned long port)
+{
+	return (u16) inw(port);
+}
+
+static void ide_insw (unsigned long port, void *addr, u32 count)
+{
+	return insw(port, addr, count);
+}
+
+static u32 ide_inl (unsigned long port)
+{
+	return (u32) inl(port);
+}
+
+static void ide_insl (unsigned long port, void *addr, u32 count)
+{
+	insl(port, addr, count);
+}
+
+static void ide_outb (u8 addr, unsigned long port)
+{
+	outb(addr, port);
+}
+
+static void ide_outw (u16 addr, unsigned long port)
+{
+	outw(addr, port);
+}
+
+static void ide_outsw (unsigned long port, void *addr, u32 count)
+{
+	outsw(port, addr, count);
+}
+
+static void ide_outl (u32 addr, unsigned long port)
+{
+	outl(addr, port);
+}
+
+static void ide_outsl (unsigned long port, void *addr, u32 count)
+{
+	return outsl(port, addr, count);
+}
+
+void default_hwif_iops (ide_hwif_t *hwif)
+{
+	hwif->OUTB	= ide_outb;
+	hwif->OUTW	= ide_outw;
+	hwif->OUTL	= ide_outl;
+	hwif->OUTSW	= ide_outsw;
+	hwif->OUTSL	= ide_outsl;
+	hwif->INB	= ide_inb;
+	hwif->INW	= ide_inw;
+	hwif->INL	= ide_inl;
+	hwif->INSW	= ide_insw;
+	hwif->INSL	= ide_insl;
+}
+
+EXPORT_SYMBOL(default_hwif_iops);
+
+static u8 ide_mm_inb (unsigned long port)
+{
+	return (u8) readb(port);
+}
+
+static u16 ide_mm_inw (unsigned long port)
+{
+	return (u16) readw(port);
+}
+
+static void ide_mm_insw (unsigned long port, void *addr, u32 count)
+{
+	__ide_mm_insw(port, addr, count);
+}
+
+static u32 ide_mm_inl (unsigned long port)
+{
+	return (u32) readl(port);
+}
+
+static void ide_mm_insl (unsigned long port, void *addr, u32 count)
+{
+	__ide_mm_insl(port, addr, count);
+}
+
+static void ide_mm_outb (u8 value, unsigned long port)
+{
+	writeb(value, port);
+}
+
+static void ide_mm_outw (u16 value, unsigned long port)
+{
+	writew(value, port);
+}
+
+static void ide_mm_outsw (unsigned long port, void *addr, u32 count)
+{
+	__ide_mm_outsw(port, addr, count);
+}
+
+static void ide_mm_outl (u32 value, unsigned long port)
+{
+	writel(value, port);
+}
+
+static void ide_mm_outsl (unsigned long port, void *addr, u32 count)
+{
+	__ide_mm_outsl(port, addr, count);
+}
+
+void default_hwif_mmiops (ide_hwif_t *hwif)
+{
+	hwif->OUTB	= ide_mm_outb;
+	hwif->OUTW	= ide_mm_outw;
+	hwif->OUTL	= ide_mm_outl;
+	hwif->OUTSW	= ide_mm_outsw;
+	hwif->OUTSL	= ide_mm_outsl;
+	hwif->INB	= ide_mm_inb;
+	hwif->INW	= ide_mm_inw;
+	hwif->INL	= ide_mm_inl;
+	hwif->INSW	= ide_mm_insw;
+	hwif->INSL	= ide_mm_insl;
+}
+
+EXPORT_SYMBOL(default_hwif_mmiops);
+
+void default_hwif_transport (ide_hwif_t *hwif)
+{
+	hwif->ata_input_data		= ata_input_data;
+	hwif->ata_output_data		= ata_output_data;
+	hwif->atapi_input_bytes		= atapi_input_bytes;
+	hwif->atapi_output_bytes	= atapi_output_bytes;
+}
+
+EXPORT_SYMBOL(default_hwif_transport);
+
+u32 read_24 (ide_drive_t *drive)
+{
+	u8 hcyl = HWIF(drive)->INB(IDE_HCYL_REG);
+	u8 lcyl = HWIF(drive)->INB(IDE_LCYL_REG);
+	u8 sect = HWIF(drive)->INB(IDE_SECTOR_REG);
+	return (hcyl<<16)|(lcyl<<8)|sect;
+}
+
+EXPORT_SYMBOL(read_24);
+
+void SELECT_DRIVE (ide_drive_t *drive)
+{
+	if (HWIF(drive)->selectproc)
+		HWIF(drive)->selectproc(drive);
+	HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);
+}
+
+EXPORT_SYMBOL(SELECT_DRIVE);
+
+void SELECT_INTERRUPT (ide_drive_t *drive)
+{
+	if (HWIF(drive)->intrproc)
+		HWIF(drive)->intrproc(drive);
+	else
+		HWIF(drive)->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+}
+
+EXPORT_SYMBOL(SELECT_INTERRUPT);
+
+void SELECT_MASK (ide_drive_t *drive, int mask)
+{
+	if (HWIF(drive)->maskproc)
+		HWIF(drive)->maskproc(drive, mask);
+}
+
+EXPORT_SYMBOL(SELECT_MASK);
+
+void QUIRK_LIST (ide_drive_t *drive)
+{
+	if (HWIF(drive)->quirkproc)
+		drive->quirk_list = HWIF(drive)->quirkproc(drive);
+}
+
+EXPORT_SYMBOL(QUIRK_LIST);
+
+/*
+ * Some localbus EIDE interfaces require a special access sequence
+ * when using 32-bit I/O instructions to transfer data.  We call this
+ * the "vlb_sync" sequence, which consists of three successive reads
+ * of the sector count register location, with interrupts disabled
+ * to ensure that the reads all happen together.
+ */
+void ata_vlb_sync (ide_drive_t *drive, ide_ioreg_t port)
+{
+	(void) HWIF(drive)->INB(port);
+	(void) HWIF(drive)->INB(port);
+	(void) HWIF(drive)->INB(port);
+}
+
+EXPORT_SYMBOL(ata_vlb_sync);
+
+/*
+ * This is used for most PIO data transfers *from* the IDE interface
+ */
+void ata_input_data (ide_drive_t *drive, void *buffer, u32 wcount)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 io_32bit		= drive->io_32bit;
+
+	if (io_32bit) {
+		if (io_32bit & 2) {
+			unsigned long flags;
+			local_irq_save(flags);
+			ata_vlb_sync(drive, IDE_NSECTOR_REG);
+			hwif->INSL(IDE_DATA_REG, buffer, wcount);
+			local_irq_restore(flags);
+		} else
+			hwif->INSL(IDE_DATA_REG, buffer, wcount);
+	} else {
+		hwif->INSW(IDE_DATA_REG, buffer, wcount<<1);
+	}
+}
+
+EXPORT_SYMBOL(ata_input_data);
+
+/*
+ * This is used for most PIO data transfers *to* the IDE interface
+ */
+void ata_output_data (ide_drive_t *drive, void *buffer, u32 wcount)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 io_32bit		= drive->io_32bit;
+
+	if (io_32bit) {
+		if (io_32bit & 2) {
+			unsigned long flags;
+			local_irq_save(flags);
+			ata_vlb_sync(drive, IDE_NSECTOR_REG);
+			hwif->OUTSL(IDE_DATA_REG, buffer, wcount);
+			local_irq_restore(flags);
+		} else
+			hwif->OUTSL(IDE_DATA_REG, buffer, wcount);
+	} else {
+		hwif->OUTSW(IDE_DATA_REG, buffer, wcount<<1);
+	}
+}
+
+EXPORT_SYMBOL(ata_output_data);
+
+/*
+ * The following routines are mainly used by the ATAPI drivers.
+ *
+ * These routines will round up any request for an odd number of bytes,
+ * so if an odd bytecount is specified, be sure that there's at least one
+ * extra byte allocated for the buffer.
+ */
+
+void atapi_input_bytes (ide_drive_t *drive, void *buffer, u32 bytecount)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	++bytecount;
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+	if (MACH_IS_ATARI || MACH_IS_Q40) {
+		/* Atari has a byte-swapped IDE interface */
+		insw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
+		return;
+	}
+#endif /* CONFIG_ATARI */
+	hwif->ata_input_data(drive, buffer, bytecount / 4);
+	if ((bytecount & 0x03) >= 2)
+		hwif->INSW(IDE_DATA_REG, ((u8 *)buffer)+(bytecount & ~0x03), 1);
+}
+
+EXPORT_SYMBOL(atapi_input_bytes);
+
+void atapi_output_bytes (ide_drive_t *drive, void *buffer, u32 bytecount)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	++bytecount;
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+	if (MACH_IS_ATARI || MACH_IS_Q40) {
+		/* Atari has a byte-swapped IDE interface */
+		outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
+		return;
+	}
+#endif /* CONFIG_ATARI */
+	hwif->ata_output_data(drive, buffer, bytecount / 4);
+	if ((bytecount & 0x03) >= 2)
+		hwif->OUTSW(IDE_DATA_REG, ((u8*)buffer)+(bytecount & ~0x03), 1);
+}
+
+EXPORT_SYMBOL(atapi_output_bytes);
+
+/*
+ * Beginning of Taskfile OPCODE Library and feature sets.
+ */
+void ide_fix_driveid (struct hd_driveid *id)
+{
+#ifndef __LITTLE_ENDIAN
+# ifdef __BIG_ENDIAN
+	int i;
+	u16 *stringcast;
+
+	id->config         = __le16_to_cpu(id->config);
+	id->cyls           = __le16_to_cpu(id->cyls);
+	id->reserved2      = __le16_to_cpu(id->reserved2);
+	id->heads          = __le16_to_cpu(id->heads);
+	id->track_bytes    = __le16_to_cpu(id->track_bytes);
+	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
+	id->sectors        = __le16_to_cpu(id->sectors);
+	id->vendor0        = __le16_to_cpu(id->vendor0);
+	id->vendor1        = __le16_to_cpu(id->vendor1);
+	id->vendor2        = __le16_to_cpu(id->vendor2);
+	stringcast = (u16 *)&id->serial_no[0];
+	for (i = 0; i < (20/2); i++)
+		stringcast[i] = __le16_to_cpu(stringcast[i]);
+	id->buf_type       = __le16_to_cpu(id->buf_type);
+	id->buf_size       = __le16_to_cpu(id->buf_size);
+	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
+	stringcast = (u16 *)&id->fw_rev[0];
+	for (i = 0; i < (8/2); i++)
+		stringcast[i] = __le16_to_cpu(stringcast[i]);
+	stringcast = (u16 *)&id->model[0];
+	for (i = 0; i < (40/2); i++)
+		stringcast[i] = __le16_to_cpu(stringcast[i]);
+	id->dword_io       = __le16_to_cpu(id->dword_io);
+	id->reserved50     = __le16_to_cpu(id->reserved50);
+	id->field_valid    = __le16_to_cpu(id->field_valid);
+	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
+	id->cur_heads      = __le16_to_cpu(id->cur_heads);
+	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
+	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
+	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
+	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
+	id->dma_1word      = __le16_to_cpu(id->dma_1word);
+	id->dma_mword      = __le16_to_cpu(id->dma_mword);
+	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
+	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
+	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
+	id->eide_pio       = __le16_to_cpu(id->eide_pio);
+	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
+	for (i = 0; i < 2; ++i)
+		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
+	for (i = 0; i < 4; ++i)
+		id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
+	id->queue_depth    = __le16_to_cpu(id->queue_depth);
+	for (i = 0; i < 4; ++i)
+		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
+	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
+	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
+	id->command_set_1  = __le16_to_cpu(id->command_set_1);
+	id->command_set_2  = __le16_to_cpu(id->command_set_2);
+	id->cfsse          = __le16_to_cpu(id->cfsse);
+	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
+	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
+	id->csf_default    = __le16_to_cpu(id->csf_default);
+	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
+	id->trseuc         = __le16_to_cpu(id->trseuc);
+	id->trsEuc         = __le16_to_cpu(id->trsEuc);
+	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
+	id->mprc           = __le16_to_cpu(id->mprc);
+	id->hw_config      = __le16_to_cpu(id->hw_config);
+	id->acoustic       = __le16_to_cpu(id->acoustic);
+	id->msrqs          = __le16_to_cpu(id->msrqs);
+	id->sxfert         = __le16_to_cpu(id->sxfert);
+	id->sal            = __le16_to_cpu(id->sal);
+	id->spg            = __le32_to_cpu(id->spg);
+	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
+	for (i = 0; i < 22; i++)
+		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
+	id->last_lun       = __le16_to_cpu(id->last_lun);
+	id->word127        = __le16_to_cpu(id->word127);
+	id->dlf            = __le16_to_cpu(id->dlf);
+	id->csfo           = __le16_to_cpu(id->csfo);
+	for (i = 0; i < 26; i++)
+		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
+	id->word156        = __le16_to_cpu(id->word156);
+	for (i = 0; i < 3; i++)
+		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
+	id->cfa_power      = __le16_to_cpu(id->cfa_power);
+	for (i = 0; i < 14; i++)
+		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
+	for (i = 0; i < 31; i++)
+		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
+	for (i = 0; i < 48; i++)
+		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
+	id->integrity_word  = __le16_to_cpu(id->integrity_word);
+# else
+#  error "Please fix <asm/byteorder.h>"
+# endif
+#endif
+}
+
+EXPORT_SYMBOL(ide_fix_driveid);
+
+void ide_fixstring (u8 *s, const int bytecount, const int byteswap)
+{
+	u8 *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */
+
+	if (byteswap) {
+		/* convert from big-endian to host byte order */
+		for (p = end ; p != s;) {
+			unsigned short *pp = (unsigned short *) (p -= 2);
+			*pp = ntohs(*pp);
+		}
+	}
+	/* strip leading blanks */
+	while (s != end && *s == ' ')
+		++s;
+	/* compress internal blanks and strip trailing blanks */
+	while (s != end && *s) {
+		if (*s++ != ' ' || (s != end && *s && *s != ' '))
+			*p++ = *(s-1);
+	}
+	/* wipe out trailing garbage */
+	while (p != end)
+		*p++ = '\0';
+}
+
+EXPORT_SYMBOL(ide_fixstring);
+
+/*
+ * Needed for PCI irq sharing
+ */
+int drive_is_ready (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= 0;
+
+	if (drive->waiting_for_dma)
+		return hwif->ide_dma_test_irq(drive);
+
+#if 0
+	/* need to guarantee 400ns since last command was issued */
+	udelay(1);
+#endif
+
+#ifdef CONFIG_IDEPCI_SHARE_IRQ
+	/*
+	 * We do a passive status test under shared PCI interrupts on
+	 * cards that truly share the ATA side interrupt, but may also share
+	 * an interrupt with another pci card/device.  We make no assumptions
+	 * about possible isa-pnp and pci-pnp issues yet.
+	 */
+	if (IDE_CONTROL_REG)
+		stat = hwif->INB(IDE_ALTSTATUS_REG);
+	else
+#endif /* CONFIG_IDEPCI_SHARE_IRQ */
+		/* Note: this may clear a pending IRQ!! */
+		stat = hwif->INB(IDE_STATUS_REG);
+
+	if (stat & BUSY_STAT)
+		/* drive busy:  definitely not interrupting */
+		return 0;
+
+	/* drive ready: *might* be interrupting */
+	return 1;
+}
+
+EXPORT_SYMBOL(drive_is_ready);
+
+/*
+ * Global for All, and taken from ide-pmac.c. Can be called
+ * with spinlock held & IRQs disabled, so don't schedule !
+ */
+int wait_for_ready (ide_drive_t *drive, int timeout)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= 0;
+
+	while(--timeout) {
+		stat = hwif->INB(IDE_STATUS_REG);
+		if (!(stat & BUSY_STAT)) {
+			if (drive->ready_stat == 0)
+				break;
+			else if ((stat & drive->ready_stat)||(stat & ERR_STAT))
+				break;
+		}
+		mdelay(1);
+	}
+	if ((stat & ERR_STAT) || timeout <= 0) {
+		if (stat & ERR_STAT) {
+			printk(KERN_ERR "%s: wait_for_ready, "
+				"error status: %x\n", drive->name, stat);
+		}
+		return 1;
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL(wait_for_ready);
+
+/*
+ * This routine busy-waits for the drive status to be not "busy".
+ * It then checks the status for all of the "good" bits and none
+ * of the "bad" bits, and if all is okay it returns 0.  All other
+ * cases return 1 after invoking ide_error() -- caller should just return.
+ *
+ * This routine should get fixed to not hog the cpu during extra long waits..
+ * That could be done by busy-waiting for the first jiffy or two, and then
+ * setting a timer to wake up at half second intervals thereafter,
+ * until timeout is achieved, before timing out.
+ */
+int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 stat;
+	int i;
+	unsigned long flags;
+ 
+	/* bail early if we've exceeded max_failures */
+	if (drive->max_failures && (drive->failures > drive->max_failures)) {
+		*startstop = ide_stopped;
+		return 1;
+	}
+
+	udelay(1);	/* spec allows drive 400ns to assert "BUSY" */
+	if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+		local_irq_set(flags);
+		timeout += jiffies;
+		while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+			if (time_after(jiffies, timeout)) {
+				local_irq_restore(flags);
+				*startstop = DRIVER(drive)->error(drive, "status timeout", stat);
+				return 1;
+			}
+		}
+		local_irq_restore(flags);
+	}
+	/*
+	 * Allow status to settle, then read it again.
+	 * A few rare drives vastly violate the 400ns spec here,
+	 * so we'll wait up to 10usec for a "good" status
+	 * rather than expensively fail things immediately.
+	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
+	 */
+	for (i = 0; i < 10; i++) {
+		udelay(1);
+		if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad))
+			return 0;
+	}
+	*startstop = DRIVER(drive)->error(drive, "status error", stat);
+	return 1;
+}
+
+EXPORT_SYMBOL(ide_wait_stat);
+
+/*
+ *  All hosts that use the 80c ribbon must use!
+ *  The name is derived from upper byte of word 93 and the 80c ribbon.
+ */
+u8 eighty_ninty_three (ide_drive_t *drive)
+{
+#if 0
+	if (!HWIF(drive)->udma_four)
+		return 0;
+
+	if (drive->id->major_rev_num) {
+		int hssbd = 0;
+		int i;
+		/*
+		 * Determime highest Supported SPEC
+		 */
+		for (i=1; i<=15; i++)
+			if (drive->id->major_rev_num & (1<<i))
+				hssbd++;
+
+		switch (hssbd) {
+			case 7:
+			case 6:
+			case 5:
+		/* ATA-4 and older do not support above Ultra 33 */
+			default:
+				return 0;
+		}
+	}
+
+	return ((u8) (
+#ifndef CONFIG_IDEDMA_IVB
+		(drive->id->hw_config & 0x4000) &&
+#endif /* CONFIG_IDEDMA_IVB */
+		 (drive->id->hw_config & 0x6000)) ? 1 : 0);
+
+#else
+
+	return ((u8) ((HWIF(drive)->udma_four) &&
+#ifndef CONFIG_IDEDMA_IVB
+			(drive->id->hw_config & 0x4000) &&
+#endif /* CONFIG_IDEDMA_IVB */
+			(drive->id->hw_config & 0x6000)) ? 1 : 0);
+#endif
+}
+
+EXPORT_SYMBOL(eighty_ninty_three);
+
+int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
+{
+	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+	    (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
+	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
+#ifndef CONFIG_IDEDMA_IVB
+		if ((drive->id->hw_config & 0x6000) == 0) {
+#else /* !CONFIG_IDEDMA_IVB */
+		if (((drive->id->hw_config & 0x2000) == 0) ||
+		    ((drive->id->hw_config & 0x4000) == 0)) {
+#endif /* CONFIG_IDEDMA_IVB */
+			printk("%s: Speed warnings UDMA 3/4/5 is not "
+				"functional.\n", drive->name);
+			return 1;
+		}
+		if (!HWIF(drive)->udma_four) {
+			printk("%s: Speed warnings UDMA 3/4/5 is not "
+				"functional.\n",
+				HWIF(drive)->name);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL(ide_ata66_check);
+
+/*
+ * Backside of HDIO_DRIVE_CMD call of SETFEATURES_XFER.
+ * 1 : Safe to update drive->id DMA registers.
+ * 0 : OOPs not allowed.
+ */
+int set_transfer (ide_drive_t *drive, ide_task_t *args)
+{
+	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+	    (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) &&
+	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) &&
+	    (drive->id->dma_ultra ||
+	     drive->id->dma_mword ||
+	     drive->id->dma_1word))
+		return 1;
+
+	return 0;
+}
+
+EXPORT_SYMBOL(set_transfer);
+
+u8 ide_auto_reduce_xfer (ide_drive_t *drive)
+{
+	if (!drive->crc_count)
+		return drive->current_speed;
+	drive->crc_count = 0;
+
+	switch(drive->current_speed) {
+		case XFER_UDMA_7:	return XFER_UDMA_6;
+		case XFER_UDMA_6:	return XFER_UDMA_5;
+		case XFER_UDMA_5:	return XFER_UDMA_4;
+		case XFER_UDMA_4:	return XFER_UDMA_3;
+		case XFER_UDMA_3:	return XFER_UDMA_2;
+		case XFER_UDMA_2:	return XFER_UDMA_1;
+		case XFER_UDMA_1:	return XFER_UDMA_0;
+			/*
+			 * OOPS we do not goto non Ultra DMA modes
+			 * without iCRC's available we force
+			 * the system to PIO and make the user
+			 * invoke the ATA-1 ATA-2 DMA modes.
+			 */
+		case XFER_UDMA_0:
+		default:		return XFER_PIO_4;
+	}
+}
+
+EXPORT_SYMBOL(ide_auto_reduce_xfer);
+
+/*
+ * Update the 
+ */
+int ide_driveid_update (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id;
+#if 0
+	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
+	if (!id)
+		return 0;
+
+	taskfile_lib_get_identify(drive, (char *)&id);
+
+	ide_fix_driveid(id);
+	if (id) {
+		drive->id->dma_ultra = id->dma_ultra;
+		drive->id->dma_mword = id->dma_mword;
+		drive->id->dma_1word = id->dma_1word;
+		/* anything more ? */
+		kfree(id);
+	}
+	return 1;
+#else
+	/*
+	 * Re-read drive->id for possible DMA mode
+	 * change (copied from ide-probe.c)
+	 */
+	unsigned long timeout, flags;
+
+	SELECT_MASK(drive, 1);
+	if (IDE_CONTROL_REG)
+		hwif->OUTB(drive->ctl,IDE_CONTROL_REG);
+	ide_delay_50ms();
+	hwif->OUTB(WIN_IDENTIFY, IDE_COMMAND_REG);
+	timeout = jiffies + WAIT_WORSTCASE;
+	do {
+		if (time_after(jiffies, timeout)) {
+			SELECT_MASK(drive, 0);
+			return 0;	/* drive timed-out */
+		}
+		ide_delay_50ms();	/* give drive a breather */
+	} while (hwif->INB(IDE_ALTSTATUS_REG) & BUSY_STAT);
+	ide_delay_50ms();	/* wait for IRQ and DRQ_STAT */
+	if (!OK_STAT(hwif->INB(IDE_STATUS_REG),DRQ_STAT,BAD_R_STAT)) {
+		SELECT_MASK(drive, 0);
+		printk("%s: CHECK for good STATUS\n", drive->name);
+		return 0;
+	}
+	local_irq_save(flags);
+	SELECT_MASK(drive, 0);
+	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
+	if (!id) {
+		local_irq_restore(flags);
+		return 0;
+	}
+	ata_input_data(drive, id, SECTOR_WORDS);
+	(void) hwif->INB(IDE_STATUS_REG);	/* clear drive IRQ */
+	local_irq_enable();
+	local_irq_restore(flags);
+	ide_fix_driveid(id);
+	if (id) {
+		drive->id->dma_ultra = id->dma_ultra;
+		drive->id->dma_mword = id->dma_mword;
+		drive->id->dma_1word = id->dma_1word;
+		/* anything more ? */
+		kfree(id);
+	}
+
+	return 1;
+#endif
+}
+
+EXPORT_SYMBOL(ide_driveid_update);
+
+/*
+ * Similar to ide_wait_stat(), except it never calls ide_error internally.
+ * This is a kludge to handle the new ide_config_drive_speed() function,
+ * and should not otherwise be used anywhere.  Eventually, the tuneproc's
+ * should be updated to return ide_startstop_t, in which case we can get
+ * rid of this abomination again.  :)   -ml
+ *
+ * It is gone..........
+ *
+ * const char *msg == consider adding for verbose errors.
+ */
+int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	int	i, error	= 1;
+	u8 stat;
+
+//	while (HWGROUP(drive)->busy)
+//		ide_delay_50ms();
+
+#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+	hwif->ide_dma_host_off(drive);
+#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+
+	/*
+	 * Don't use ide_wait_cmd here - it will
+	 * attempt to set_geometry and recalibrate,
+	 * but for some reason these don't work at
+	 * this point (lost interrupt).
+	 */
+        /*
+         * Select the drive, and issue the SETFEATURES command
+         */
+	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
+	udelay(1);
+	SELECT_DRIVE(drive);
+	SELECT_MASK(drive, 0);
+	udelay(1);
+	if (IDE_CONTROL_REG)
+		hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
+	hwif->OUTB(speed, IDE_NSECTOR_REG);
+	hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
+	hwif->OUTB(WIN_SETFEATURES, IDE_COMMAND_REG);
+	if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	udelay(1);
+	/*
+	 * Wait for drive to become non-BUSY
+	 */
+	if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+		unsigned long flags, timeout;
+		local_irq_set(flags);
+		timeout = jiffies + WAIT_CMD;
+		while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+			if (time_after(jiffies, timeout))
+				break;
+		}
+		local_irq_restore(flags);
+	}
+
+	/*
+	 * Allow status to settle, then read it again.
+	 * A few rare drives vastly violate the 400ns spec here,
+	 * so we'll wait up to 10usec for a "good" status
+	 * rather than expensively fail things immediately.
+	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
+	 */
+	for (i = 0; i < 10; i++) {
+		udelay(1);
+		if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
+			error = 0;
+			break;
+		}
+	}
+
+	SELECT_MASK(drive, 0);
+
+	enable_irq(hwif->irq);
+
+	if (error) {
+		(void) ide_dump_status(drive, "set_drive_speed_status", stat);
+		return error;
+	}
+
+	drive->id->dma_ultra &= ~0xFF00;
+	drive->id->dma_mword &= ~0x0F00;
+	drive->id->dma_1word &= ~0x0F00;
+
+#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+	if (speed >= XFER_SW_DMA_0)
+		hwif->ide_dma_host_on(drive);
+	else
+		hwif->ide_dma_off(drive);
+#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+
+	switch(speed) {
+		case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
+		case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
+		case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
+		case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
+		case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
+		case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
+		case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
+		case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
+		case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
+		case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
+		case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
+		case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
+		case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
+		case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
+		default: break;
+	}
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+	drive->current_speed = speed;
+	return error;
+}
+
+EXPORT_SYMBOL(ide_config_drive_speed);
+
+
+/*
+ * This should get invoked any time we exit the driver to
+ * wait for an interrupt response from a drive.  handler() points
+ * at the appropriate code to handle the next interrupt, and a
+ * timer is started to prevent us from waiting forever in case
+ * something goes wrong (see the ide_timer_expiry() handler later on).
+ */
+void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
+		      unsigned int timeout, ide_expiry_t *expiry)
+{
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (hwgroup->handler != NULL) {
+		printk("%s: ide_set_handler: handler not null; "
+			"old=%p, new=%p\n",
+			drive->name, hwgroup->handler, handler);
+	}
+	hwgroup->handler	= handler;
+	hwgroup->expiry		= expiry;
+	hwgroup->timer.expires	= jiffies + timeout;
+	add_timer(&hwgroup->timer);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+EXPORT_SYMBOL(ide_set_handler);
+
+
+/* needed below */
+ide_startstop_t do_reset1 (ide_drive_t *, int);
+
+/*
+ * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
+ * during an atapi drive reset operation. If the drive has not yet responded,
+ * and we have not yet hit our maximum waiting time, then the timer is restarted
+ * for another 50ms.
+ */
+static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat;
+
+	SELECT_DRIVE(drive);
+	udelay (10);
+
+	if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {
+		printk("%s: ATAPI reset complete\n", drive->name);
+	} else {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
+			ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
+			/* continue polling */
+			return ide_started;
+		}
+		/* end of polling */
+		hwgroup->poll_timeout = 0;
+		printk("%s: ATAPI reset timed-out, status=0x%02x\n",
+				drive->name, stat);
+		/* do it the old fashioned way */
+		return do_reset1(drive, 1);
+	}
+	/* done polling */
+	hwgroup->poll_timeout = 0;
+	return ide_stopped;
+}
+
+/*
+ * reset_pollfunc() gets invoked to poll the interface for completion every 50ms
+ * during an ide reset operation. If the drives have not yet responded,
+ * and we have not yet hit our maximum waiting time, then the timer is restarted
+ * for another 50ms.
+ */
+static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 tmp;
+
+	if (hwif->reset_poll != NULL) {
+		if (hwif->reset_poll(drive)) {
+			printk(KERN_ERR "%s: host reset_poll failure for %s.\n",
+				hwif->name, drive->name);
+			return ide_stopped;
+		}
+	}
+
+	if (!OK_STAT(tmp = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
+			ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
+			/* continue polling */
+			return ide_started;
+		}
+		printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
+		drive->failures++;
+	} else  {
+		printk("%s: reset: ", hwif->name);
+		if ((tmp = hwif->INB(IDE_ERROR_REG)) == 1) {
+			printk("success\n");
+			drive->failures = 0;
+		} else {
+			drive->failures++;
+#if FANCY_STATUS_DUMPS
+			printk("master: ");
+			switch (tmp & 0x7f) {
+				case 1: printk("passed");
+					break;
+				case 2: printk("formatter device error");
+					break;
+				case 3: printk("sector buffer error");
+					break;
+				case 4: printk("ECC circuitry error");
+					break;
+				case 5: printk("controlling MPU error");
+					break;
+				default:printk("error (0x%02x?)", tmp);
+			}
+			if (tmp & 0x80)
+				printk("; slave: failed");
+			printk("\n");
+#else
+			printk("failed\n");
+#endif /* FANCY_STATUS_DUMPS */
+		}
+	}
+	hwgroup->poll_timeout = 0;	/* done polling */
+	return ide_stopped;
+}
+
+void check_dma_crc (ide_drive_t *drive)
+{
+	if (drive->crc_count) {
+		(void) HWIF(drive)->ide_dma_off_quietly(drive);
+		ide_set_xfer_rate(drive, ide_auto_reduce_xfer(drive));
+		if (drive->current_speed >= XFER_SW_DMA_0)
+			(void) HWIF(drive)->ide_dma_on(drive);
+	} else {
+		(void) HWIF(drive)->ide_dma_off(drive);
+	}
+}
+
+void pre_reset (ide_drive_t *drive)
+{
+	if (drive->driver != NULL)
+		DRIVER(drive)->pre_reset(drive);
+
+	if (!drive->keep_settings) {
+		if (drive->using_dma) {
+			check_dma_crc(drive);
+		} else {
+			drive->unmask = 0;
+			drive->io_32bit = 0;
+		}
+		return;
+	}
+	if (drive->using_dma)
+		check_dma_crc(drive);
+
+	if (HWIF(drive)->pre_reset != NULL)
+		HWIF(drive)->pre_reset(drive);
+
+}
+
+/*
+ * do_reset1() attempts to recover a confused drive by resetting it.
+ * Unfortunately, resetting a disk drive actually resets all devices on
+ * the same interface, so it can really be thought of as resetting the
+ * interface rather than resetting the drive.
+ *
+ * ATAPI devices have their own reset mechanism which allows them to be
+ * individually reset without clobbering other devices on the same interface.
+ *
+ * Unfortunately, the IDE interface does not generate an interrupt to let
+ * us know when the reset operation has finished, so we must poll for this.
+ * Equally poor, though, is the fact that this may a very long time to complete,
+ * (up to 30 seconds worstcase).  So, instead of busy-waiting here for it,
+ * we set a timer to poll at 50ms intervals.
+ */
+ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
+{
+	unsigned int unit;
+	unsigned long flags;
+	ide_hwif_t *hwif = HWIF(drive);
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+
+	local_irq_save(flags);
+
+	/* For an ATAPI device, first try an ATAPI SRST. */
+	if (drive->media != ide_disk && !do_not_try_atapi) {
+		pre_reset(drive);
+		SELECT_DRIVE(drive);
+		udelay (20);
+		hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
+		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
+		ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
+		local_irq_restore(flags);
+		return ide_started;
+	}
+
+	/*
+	 * First, reset any device state data we were maintaining
+	 * for any of the drives on this interface.
+	 */
+	for (unit = 0; unit < MAX_DRIVES; ++unit)
+		pre_reset(&hwif->drives[unit]);
+
+#if OK_TO_RESET_CONTROLLER
+	if (!IDE_CONTROL_REG) {
+		local_irq_restore(flags);
+		return ide_stopped;
+	}
+
+# if 0
+        {
+		u8 control = hwif->INB(IDE_CONTROL_REG);
+		control |= 0x04;
+		hwif->OUTB(control,IDE_CONTROL_REG);
+		udelay(30);
+		control &= 0xFB;
+		hwif->OUTB(control, IDE_CONTROL_REG);
+	}
+# else
+	/*
+	 * Note that we also set nIEN while resetting the device,
+	 * to mask unwanted interrupts from the interface during the reset.
+	 * However, due to the design of PC hardware, this will cause an
+	 * immediate interrupt due to the edge transition it produces.
+	 * This single interrupt gives us a "fast poll" for drives that
+	 * recover from reset very quickly, saving us the first 50ms wait time.
+	 */
+	/* set SRST and nIEN */
+	hwif->OUTB(drive->ctl|6,IDE_CONTROL_REG);
+	/* more than enough time */
+	udelay(10);
+	if (drive->quirk_list == 2) {
+		/* clear SRST and nIEN */
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	} else {
+		/* clear SRST, leave nIEN */
+		hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+	}
+	/* more than enough time */
+	udelay(10);
+	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
+# endif
+	/*
+	 * Some weird controller like resetting themselves to a strange
+	 * state when the disks are reset this way. At least, the Winbond
+	 * 553 documentation says that
+	 */
+	if (hwif->resetproc != NULL) {
+		hwif->resetproc(drive);
+
+# if 0
+		if (drive->failures) {
+			local_irq_restore(flags);
+			return ide_stopped;
+		}
+# endif
+	}
+
+#endif	/* OK_TO_RESET_CONTROLLER */
+
+	local_irq_restore(flags);
+	return ide_started;
+}
+
+#if 0
+/*
+ * ide_do_reset() is the entry point to the drive/interface reset code.
+ */
+ide_startstop_t ide_do_reset (ide_drive_t *drive)
+{
+	return do_reset1(drive, 0);
+}
+#else
+/*
+ * ide_do_reset() is the entry point to the drive/interface reset code.
+ */
+ide_startstop_t ide_do_reset (ide_drive_t *drive)
+{
+	ide_startstop_t start_stop = ide_started;
+# if 0
+        u8 tmp_dma	= drive->using_dma;
+        u8 cspeed	= drive->current_speed;
+	u8 unmask	= drive->unmask;
+# endif
+
+	if (HWGROUP(drive)->handler != NULL) {
+		unsigned long flags;
+		spin_lock_irqsave(&io_request_lock, flags);
+		HWGROUP(drive)->handler = NULL;
+		del_timer(&HWGROUP(drive)->timer);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+	}
+
+	start_stop = do_reset1(drive, 0);
+# if 0
+	/*
+	 * check for suspend-spindown flag,
+	 * to attempt a restart or spinup of device.
+	 */
+	if (drive->suspend_reset) {
+		/*
+		 * APM WAKE UP todo !!
+		 * int nogoodpower = 1;
+		 * while(nogoodpower) {
+		 * 	check_power1() or check_power2()
+		 * 	nogoodpower = 0;
+		 * }
+		 * HWIF(drive)->multiproc(drive);
+		 */
+# endif
+
+	return start_stop;
+}
+#endif
+
+EXPORT_SYMBOL(ide_do_reset);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-lib.c linux-2.4.21/drivers/ide/ide-lib.c
--- linux-2.4.20/drivers/ide/ide-lib.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-lib.c	2002-12-18 18:58:01.000000000 +0000
@@ -0,0 +1,439 @@
+#include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/blkpg.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+#include "ide_modes.h"
+
+/*
+ *	IDE library routines. These are plug in code that most 
+ *	drivers can use but occasionally may be weird enough
+ *	to want to do their own thing with
+ *
+ *	Add common non I/O op stuff here. Make sure it has proper
+ *	kernel-doc function headers or your patch will be rejected
+ */
+ 
+
+/**
+ *	ide_xfer_verbose	-	return IDE mode names
+ *	@xfer_rate: rate to name
+ *
+ *	Returns a constant string giving the name of the mode
+ *	requested.
+ */
+
+char *ide_xfer_verbose (u8 xfer_rate)
+{
+        switch(xfer_rate) {
+                case XFER_UDMA_7:	return("UDMA 7");
+                case XFER_UDMA_6:	return("UDMA 6");
+                case XFER_UDMA_5:	return("UDMA 5");
+                case XFER_UDMA_4:	return("UDMA 4");
+                case XFER_UDMA_3:	return("UDMA 3");
+                case XFER_UDMA_2:	return("UDMA 2");
+                case XFER_UDMA_1:	return("UDMA 1");
+                case XFER_UDMA_0:	return("UDMA 0");
+                case XFER_MW_DMA_2:	return("MW DMA 2");
+                case XFER_MW_DMA_1:	return("MW DMA 1");
+                case XFER_MW_DMA_0:	return("MW DMA 0");
+                case XFER_SW_DMA_2:	return("SW DMA 2");
+                case XFER_SW_DMA_1:	return("SW DMA 1");
+                case XFER_SW_DMA_0:	return("SW DMA 0");
+                case XFER_PIO_4:	return("PIO 4");
+                case XFER_PIO_3:	return("PIO 3");
+                case XFER_PIO_2:	return("PIO 2");
+                case XFER_PIO_1:	return("PIO 1");
+                case XFER_PIO_0:	return("PIO 0");
+                case XFER_PIO_SLOW:	return("PIO SLOW");
+                default:		return("XFER ERROR");
+        }
+}
+
+EXPORT_SYMBOL(ide_xfer_verbose);
+
+/**
+ *	ide_dma_speed	-	compute DMA speed
+ *	@drive: drive
+ *	@mode; intended mode
+ *
+ *	Checks the drive capabilities and returns the speed to use
+ *	for the transfer. Returns -1 if the requested mode is unknown
+ *	(eg PIO)
+ */
+ 
+u8 ide_dma_speed(ide_drive_t *drive, u8 mode)
+{
+	struct hd_driveid *id   = drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 speed = 0;
+
+	if (drive->media != ide_disk && hwif->atapi_dma == 0)
+		return 0;
+
+	switch(mode) {
+		case 0x04:
+			if ((id->dma_ultra & 0x0040) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_6; break; }
+		case 0x03:
+			if ((id->dma_ultra & 0x0020) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_5; break; }
+		case 0x02:
+			if ((id->dma_ultra & 0x0010) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_4; break; }
+			if ((id->dma_ultra & 0x0008) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_3; break; }
+		case 0x01:
+			if ((id->dma_ultra & 0x0004) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_2; break; }
+			if ((id->dma_ultra & 0x0002) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_1; break; }
+			if ((id->dma_ultra & 0x0001) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_0; break; }
+		case 0x00:
+			if ((id->dma_mword & 0x0004) &&
+			    (id->dma_mword & hwif->mwdma_mask))
+				{ speed = XFER_MW_DMA_2; break; }
+			if ((id->dma_mword & 0x0002) &&
+			    (id->dma_mword & hwif->mwdma_mask))
+				{ speed = XFER_MW_DMA_1; break; }
+			if ((id->dma_mword & 0x0001) &&
+			    (id->dma_mword & hwif->mwdma_mask))
+				{ speed = XFER_MW_DMA_0; break; }
+			if ((id->dma_1word & 0x0004) &&
+			    (id->dma_1word & hwif->swdma_mask))
+				{ speed = XFER_SW_DMA_2; break; }
+			if ((id->dma_1word & 0x0002) &&
+			    (id->dma_1word & hwif->swdma_mask))
+				{ speed = XFER_SW_DMA_1; break; }
+			if ((id->dma_1word & 0x0001) &&
+			    (id->dma_1word & hwif->swdma_mask))
+				{ speed = XFER_SW_DMA_0; break; }
+	}
+
+//	printk("%s: %s: mode 0x%02x, speed 0x%02x\n",
+//		__FUNCTION__, drive->name, mode, speed);
+
+	return speed;
+}
+
+EXPORT_SYMBOL(ide_dma_speed);
+
+
+/**
+ *	ide_rate_filter		-	return best speed for mode
+ *	@mode: modes available
+ *	@speed: desired speed
+ *
+ *	Given the available DMA/UDMA mode this function returns
+ *	the best available speed at or below the speed requested.
+ */
+
+u8 ide_rate_filter (u8 mode, u8 speed) 
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	static u8 speed_max[] = {
+		XFER_MW_DMA_2, XFER_UDMA_2, XFER_UDMA_4,
+		XFER_UDMA_5, XFER_UDMA_6
+	};
+
+//	printk("%s: mode 0x%02x, speed 0x%02x\n", __FUNCTION__, mode, speed);
+
+	/* So that we remember to update this if new modes appear */
+	if (mode > 4)
+		BUG();
+	return min(speed, speed_max[mode]);
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+	return min(speed, XFER_PIO_4);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+EXPORT_SYMBOL(ide_rate_filter);
+
+int ide_dma_enable (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	return ((int)	((((id->dma_ultra >> 8) & hwif->ultra_mask) ||
+			  ((id->dma_mword >> 8) & hwif->mwdma_mask) ||
+			  ((id->dma_1word >> 8) & hwif->swdma_mask)) ? 1 : 0));
+}
+
+EXPORT_SYMBOL(ide_dma_enable);
+
+const ide_pio_timings_t ide_pio_timings[6] = {
+	{ 70,	165,	600 },	/* PIO Mode 0 */
+	{ 50,	125,	383 },	/* PIO Mode 1 */
+	{ 30,	100,	240 },	/* PIO Mode 2 */
+	{ 30,	80,	180 },	/* PIO Mode 3 with IORDY */
+	{ 25,	70,	120 },	/* PIO Mode 4 with IORDY */
+	{ 20,	50,	100 }	/* PIO Mode 5 with IORDY (nonstandard) */
+};
+
+EXPORT_SYMBOL_GPL(ide_pio_timings);
+
+/*
+ * Black list. Some drives incorrectly report their maximal PIO mode,
+ * at least in respect to CMD640. Here we keep info on some known drives.
+ */
+static struct ide_pio_info {
+	const char	*name;
+	int		pio;
+} ide_pio_blacklist [] = {
+/*	{ "Conner Peripherals 1275MB - CFS1275A", 4 }, */
+	{ "Conner Peripherals 540MB - CFS540A", 3 },
+
+	{ "WDC AC2700",  3 },
+	{ "WDC AC2540",  3 },
+	{ "WDC AC2420",  3 },
+	{ "WDC AC2340",  3 },
+	{ "WDC AC2250",  0 },
+	{ "WDC AC2200",  0 },
+	{ "WDC AC21200", 4 },
+	{ "WDC AC2120",  0 },
+	{ "WDC AC2850",  3 },
+	{ "WDC AC1270",  3 },
+	{ "WDC AC1170",  1 },
+	{ "WDC AC1210",  1 },
+	{ "WDC AC280",   0 },
+/*	{ "WDC AC21000", 4 }, */
+	{ "WDC AC31000", 3 },
+	{ "WDC AC31200", 3 },
+/*	{ "WDC AC31600", 4 }, */
+
+	{ "Maxtor 7131 AT", 1 },
+	{ "Maxtor 7171 AT", 1 },
+	{ "Maxtor 7213 AT", 1 },
+	{ "Maxtor 7245 AT", 1 },
+	{ "Maxtor 7345 AT", 1 },
+	{ "Maxtor 7546 AT", 3 },
+	{ "Maxtor 7540 AV", 3 },
+
+	{ "SAMSUNG SHD-3121A", 1 },
+	{ "SAMSUNG SHD-3122A", 1 },
+	{ "SAMSUNG SHD-3172A", 1 },
+
+/*	{ "ST51080A", 4 },
+ *	{ "ST51270A", 4 },
+ *	{ "ST31220A", 4 },
+ *	{ "ST31640A", 4 },
+ *	{ "ST32140A", 4 },
+ *	{ "ST3780A",  4 },
+ */
+	{ "ST5660A",  3 },
+	{ "ST3660A",  3 },
+	{ "ST3630A",  3 },
+	{ "ST3655A",  3 },
+	{ "ST3391A",  3 },
+	{ "ST3390A",  1 },
+	{ "ST3600A",  1 },
+	{ "ST3290A",  0 },
+	{ "ST3144A",  0 },
+	{ "ST3491A",  1 },	/* reports 3, should be 1 or 2 (depending on */	
+				/* drive) according to Seagates FIND-ATA program */
+
+	{ "QUANTUM ELS127A", 0 },
+	{ "QUANTUM ELS170A", 0 },
+	{ "QUANTUM LPS240A", 0 },
+	{ "QUANTUM LPS210A", 3 },
+	{ "QUANTUM LPS270A", 3 },
+	{ "QUANTUM LPS365A", 3 },
+	{ "QUANTUM LPS540A", 3 },
+	{ "QUANTUM LIGHTNING 540A", 3 },
+	{ "QUANTUM LIGHTNING 730A", 3 },
+
+        { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */
+        { "QUANTUM FIREBALL_640", 3 }, 
+        { "QUANTUM FIREBALL_1080", 3 },
+        { "QUANTUM FIREBALL_1280", 3 },
+	{ NULL,	0 }
+};
+
+/**
+ *	ide_scan_pio_blacklist 	-	check for a blacklisted drive
+ *	@model: Drive model string
+ *
+ *	This routine searches the ide_pio_blacklist for an entry
+ *	matching the start/whole of the supplied model name.
+ *
+ *	Returns -1 if no match found.
+ *	Otherwise returns the recommended PIO mode from ide_pio_blacklist[].
+ */
+
+static int ide_scan_pio_blacklist (char *model)
+{
+	struct ide_pio_info *p;
+
+	for (p = ide_pio_blacklist; p->name != NULL; p++) {
+		if (strncmp(p->name, model, strlen(p->name)) == 0)
+			return p->pio;
+	}
+	return -1;
+}
+
+/**
+ *	ide_get_best_pio_mode	-	get PIO mode from drive
+ *	@driver: drive to consider
+ *	@mode_wanted: preferred mode
+ *	@max_mode: highest allowed
+ *	@d: pio data
+ *
+ *	This routine returns the recommended PIO settings for a given drive,
+ *	based on the drive->id information and the ide_pio_blacklist[].
+ *	This is used by most chipset support modules when "auto-tuning".
+ *
+ *	Drive PIO mode auto selection
+ */
+
+u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_pio_data_t *d)
+{
+	int pio_mode;
+	int cycle_time = 0;
+	int use_iordy = 0;
+	struct hd_driveid* id = drive->id;
+	int overridden  = 0;
+	int blacklisted = 0;
+
+	if (mode_wanted != 255) {
+		pio_mode = mode_wanted;
+	} else if (!drive->id) {
+		pio_mode = 0;
+	} else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
+		overridden = 1;
+		blacklisted = 1;
+		use_iordy = (pio_mode > 2);
+	} else {
+		pio_mode = id->tPIO;
+		if (pio_mode > 2) {	/* 2 is maximum allowed tPIO value */
+			pio_mode = 2;
+			overridden = 1;
+		}
+		if (id->field_valid & 2) {	  /* drive implements ATA2? */
+			if (id->capability & 8) { /* drive supports use_iordy? */
+				use_iordy = 1;
+				cycle_time = id->eide_pio_iordy;
+				if (id->eide_pio_modes & 7) {
+					overridden = 0;
+					if (id->eide_pio_modes & 4)
+						pio_mode = 5;
+					else if (id->eide_pio_modes & 2)
+						pio_mode = 4;
+					else
+						pio_mode = 3;
+				}
+			} else {
+				cycle_time = id->eide_pio;
+			}
+		}
+
+#if 0
+		if (drive->id->major_rev_num & 0x0004) printk("ATA-2 ");
+#endif
+
+		/*
+		 * Conservative "downgrade" for all pre-ATA2 drives
+		 */
+		if (pio_mode && pio_mode < 4) {
+			pio_mode--;
+			overridden = 1;
+#if 0
+			use_iordy = (pio_mode > 2);
+#endif
+			if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time)
+				cycle_time = 0; /* use standard timing */
+		}
+	}
+	if (pio_mode > max_mode) {
+		pio_mode = max_mode;
+		cycle_time = 0;
+	}
+	if (d) {
+		d->pio_mode = pio_mode;
+		d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time;
+		d->use_iordy = use_iordy;
+		d->overridden = overridden;
+		d->blacklisted = blacklisted;
+	}
+	return pio_mode;
+}
+
+EXPORT_SYMBOL_GPL(ide_get_best_pio_mode);
+
+/**
+ *	ide_toggle_bounce	-	handle bounce buffering
+ *	@drive: drive to update
+ *	@on: on/off boolean
+ *
+ *	Enable or disable bounce buffering for the device. Drives move
+ *	between PIO and DMA and that changes the rules we need.
+ */
+ 
+void ide_toggle_bounce(ide_drive_t *drive, int on)
+{
+	u64 addr = BLK_BOUNCE_HIGH;	/* dma64_addr_t */
+
+	if (on && drive->media == ide_disk) {
+		if (!PCI_DMA_BUS_IS_PHYS)
+			addr = BLK_BOUNCE_ANY;
+		else
+			addr = HWIF(drive)->pci_dev->dma_mask;
+	}
+
+	blk_queue_bounce_limit(&drive->queue, addr);
+}
+
+EXPORT_SYMBOL(ide_toggle_bounce);
+
+
+/**
+ *	ide_set_xfer_rate	-	set transfer rate
+ *	@drive: drive to set
+ *	@speed: speed to attempt to set
+ *	
+ *	General helper for setting the speed of an IDE device. This
+ *	function knows about user enforced limits from the configuration
+ *	which speedproc() does not.  High level drivers should never
+ *	invoke speedproc() directly.
+ */
+ 
+int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
+{
+#ifndef CONFIG_BLK_DEV_IDEDMA
+	rate = min(rate, (u8) XFER_PIO_4);
+#endif
+	if(HWIF(drive)->speedproc)
+		return HWIF(drive)->speedproc(drive, rate);
+	else
+		return -1;
+}
+
+EXPORT_SYMBOL_GPL(ide_set_xfer_rate);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-m8xx.c linux-2.4.21/drivers/ide/ide-m8xx.c
--- linux-2.4.20/drivers/ide/ide-m8xx.c	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-m8xx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,857 +0,0 @@
-/*
- *  linux/drivers/ide/ide-m8xx.c
- *
- *  Copyright (C) 2000, 2001 Wolfgang Denk, wd@denx.de
- *  Modified for direct IDE interface
- *	by Thomas Lange, thomas@corelatus.com
- *  Modified for direct IDE interface on 8xx without using the PCMCIA
- *  controller
- *	by Steven.Scholz@imc-berlin.de
- *  Moved out of arch/ppc/kernel/m8xx_setup.c, other minor cleanups
- *	by Mathew Locke <mattl@mvista.com>
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/major.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/blk.h>
-#include <linux/ioport.h>
-#include <linux/ide.h>
-#include <linux/bootmem.h>
-
-#include <asm/mpc8xx.h>
-#include <asm/mmu.h>
-#include <asm/processor.h>
-#include <asm/residual.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/ide.h>
-#include <asm/8xx_immap.h>
-#include <asm/machdep.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-static int identify  (volatile unsigned char *p);
-static void print_fixed (volatile unsigned char *p);
-static void print_funcid (int func);
-static int check_ide_device (unsigned long base);
-
-static void ide_interrupt_ack (void *dev);
-static void m8xx_ide_tuneproc(ide_drive_t *drive, byte pio);
-
-typedef	struct ide_ioport_desc {
-	unsigned long	base_off;		/* Offset to PCMCIA memory	*/
-	ide_ioreg_t	reg_off[IDE_NR_PORTS];	/* controller register offsets	*/
-	int		irq;			/* IRQ				*/
-} ide_ioport_desc_t;
-
-ide_ioport_desc_t ioport_dsc[MAX_HWIFS] = {
-#ifdef IDE0_BASE_OFFSET
-	{ IDE0_BASE_OFFSET,
-	    {
-		IDE0_DATA_REG_OFFSET,
-		IDE0_ERROR_REG_OFFSET,
-		IDE0_NSECTOR_REG_OFFSET,
-		IDE0_SECTOR_REG_OFFSET,
-		IDE0_LCYL_REG_OFFSET,
-		IDE0_HCYL_REG_OFFSET,
-		IDE0_SELECT_REG_OFFSET,
-		IDE0_STATUS_REG_OFFSET,
-		IDE0_CONTROL_REG_OFFSET,
-		IDE0_IRQ_REG_OFFSET,
-	    },
-	    IDE0_INTERRUPT,
-	},
-#ifdef IDE1_BASE_OFFSET
-	{ IDE1_BASE_OFFSET,
-	    {
-		IDE1_DATA_REG_OFFSET,
-		IDE1_ERROR_REG_OFFSET,
-		IDE1_NSECTOR_REG_OFFSET,
-		IDE1_SECTOR_REG_OFFSET,
-		IDE1_LCYL_REG_OFFSET,
-		IDE1_HCYL_REG_OFFSET,
-		IDE1_SELECT_REG_OFFSET,
-		IDE1_STATUS_REG_OFFSET,
-		IDE1_CONTROL_REG_OFFSET,
-		IDE1_IRQ_REG_OFFSET,
-	    },
-	    IDE1_INTERRUPT,
-	},
-#endif /* IDE1_BASE_OFFSET */
-#endif	/* IDE0_BASE_OFFSET */
-};
-
-ide_pio_timings_t ide_pio_clocks[6];
-int hold_time[6] =  {30, 20, 15, 10, 10, 10 };   /* PIO Mode 5 with IORDY (nonstandard) */
-
-/*
- * Warning: only 1 (ONE) PCMCIA slot supported here,
- * which must be correctly initialized by the firmware (PPCBoot).
- */
-static int _slot_ = -1;			/* will be read from PCMCIA registers   */
-
-/* Make clock cycles and always round up */
-#define PCMCIA_MK_CLKS( t, T ) (( (t) * ((T)/1000000) + 999U ) / 1000U )
-
-
-
-/*
- * IDE stuff.
- */
-static int
-m8xx_ide_default_irq(ide_ioreg_t base)
-{
-#ifdef CONFIG_BLK_DEV_MPC8xx_IDE
-	if (base >= MAX_HWIFS)
-		return 0;
-
-	printk("[%d] m8xx_ide_default_irq %d\n",__LINE__,ioport_dsc[base].irq);
-	
-	return (ioport_dsc[base].irq);
-#else
-        return 9;
-#endif
-}
-
-static ide_ioreg_t
-m8xx_ide_default_io_base(int index)
-{
-        return index;
-}
-
-#define M8XX_PCMCIA_CD2(slot)      (0x10000000 >> (slot << 4))
-#define M8XX_PCMCIA_CD1(slot)      (0x08000000 >> (slot << 4))
-
-/*
- * The TQM850L hardware has two pins swapped! Grrrrgh!
- */
-#ifdef	CONFIG_TQM850L
-#define __MY_PCMCIA_GCRX_CXRESET	PCMCIA_GCRX_CXOE
-#define __MY_PCMCIA_GCRX_CXOE		PCMCIA_GCRX_CXRESET
-#else
-#define __MY_PCMCIA_GCRX_CXRESET	PCMCIA_GCRX_CXRESET
-#define __MY_PCMCIA_GCRX_CXOE		PCMCIA_GCRX_CXOE
-#endif
-
-#if defined(CONFIG_BLK_DEV_MPC8xx_IDE) && defined(CONFIG_IDE_8xx_PCCARD)
-#define PCMCIA_SCHLVL IDE0_INTERRUPT	/* Status Change Interrupt Level	*/
-static int pcmcia_schlvl = PCMCIA_SCHLVL;
-#endif
-
-/*
- * See include/linux/ide.h for definition of hw_regs_t (p, base)
- */
-
-/*
- * m8xx_ide_init_hwif_ports for a direct IDE interface _using_
- */
-#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
-static void
-m8xx_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, 
-		ide_ioreg_t ctrl_port, int *irq)
-{
-	ide_ioreg_t *p = hw->io_ports;
-	int i;
-
-	typedef struct {
-		ulong br;
-		ulong or;
-	} pcmcia_win_t;
-	volatile pcmcia_win_t *win;
-	volatile pcmconf8xx_t *pcmp;
-
-	uint *pgcrx;
-	u32 pcmcia_phy_base;
-	u32 pcmcia_phy_end;
-	static unsigned long pcmcia_base = 0;
-	unsigned long base;
-
-	*p = 0;
-	if (irq)
-		*irq = 0;
-
-	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
-
-	if (!pcmcia_base) {
-                /*
-                 * Read out PCMCIA registers. Since the reset values
-                 * are undefined, we sure hope that they have been
-                 * set up by firmware
-		 */
-
-		/* Scan all registers for valid settings */
-		pcmcia_phy_base = 0xFFFFFFFF;
-		pcmcia_phy_end = 0;
-		/* br0 is start of brX and orX regs */
-		win = (pcmcia_win_t *) \
-			(&(((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0));
-		for (i = 0; i < 8; i++) {
-			if (win->or & 1) {	/* This bank is marked as valid */
-				if (win->br < pcmcia_phy_base) {
-					pcmcia_phy_base = win->br;
-				}
-				if ((win->br + PCMCIA_MEM_SIZE) > pcmcia_phy_end) {
-					pcmcia_phy_end  = win->br + PCMCIA_MEM_SIZE;
-				}
-				/* Check which slot that has been defined */
-				_slot_ = (win->or >> 2) & 1;
-
-			}					/* Valid bank */
-			win++;
-		}						/* for */
-
-		printk ("PCMCIA slot %c: phys mem %08x...%08x (size %08x)\n",
-			'A' + _slot_,
-			pcmcia_phy_base, pcmcia_phy_end,
-			pcmcia_phy_end - pcmcia_phy_base);
-
-		pcmcia_base=(unsigned long)ioremap(pcmcia_phy_base,
-						   pcmcia_phy_end-pcmcia_phy_base);
-
-#ifdef DEBUG
-		printk ("PCMCIA virt base: %08lx\n", pcmcia_base);
-#endif
-		/* Compute clock cycles for PIO timings */
-		for (i=0; i<6; ++i) {
-			bd_t	*binfo = (bd_t *)__res;
-
-			hold_time[i]   =
-				PCMCIA_MK_CLKS (hold_time[i],
-						binfo->bi_busfreq);
-			ide_pio_clocks[i].setup_time  =
-				PCMCIA_MK_CLKS (ide_pio_timings[i].setup_time,
-						binfo->bi_busfreq);
-			ide_pio_clocks[i].active_time =
-				PCMCIA_MK_CLKS (ide_pio_timings[i].active_time,
-						binfo->bi_busfreq);
-			ide_pio_clocks[i].cycle_time  =
-				PCMCIA_MK_CLKS (ide_pio_timings[i].cycle_time,
-						binfo->bi_busfreq);
-#if 0
-			printk ("PIO mode %d timings: %d/%d/%d => %d/%d/%d\n",
-				i,
-				ide_pio_clocks[i].setup_time,
-				ide_pio_clocks[i].active_time,
-				ide_pio_clocks[i].hold_time,
-				ide_pio_clocks[i].cycle_time,
-				ide_pio_timings[i].setup_time,
-				ide_pio_timings[i].active_time,
-				ide_pio_timings[i].hold_time,
-				ide_pio_timings[i].cycle_time);
-#endif
-		}
-	}
-
-	if (data_port >= MAX_HWIFS)
-		return;
-
-	if (_slot_ == -1) {
-		printk ("PCMCIA slot has not been defined! Using A as default\n");
-		_slot_ = 0;
-	}
-
-#ifdef CONFIG_IDE_8xx_PCCARD
-
-#ifdef DEBUG
-	printk ("PIPR = 0x%08X  slot %c ==> mask = 0x%X\n",
-		pcmp->pcmc_pipr,
-		'A' + _slot_,
-		M8XX_PCMCIA_CD1(_slot_) | M8XX_PCMCIA_CD2(_slot_) );
-#endif /* DEBUG */
-
-	if (pcmp->pcmc_pipr & (M8XX_PCMCIA_CD1(_slot_)|M8XX_PCMCIA_CD2(_slot_))) {
-		printk ("No card in slot %c: PIPR=%08x\n",
-			'A' + _slot_, (u32) pcmp->pcmc_pipr);
-		return;		/* No card in slot */
-	}
-
-	check_ide_device (pcmcia_base);
-
-#endif	/* CONFIG_IDE_8xx_PCCARD */
-
-	base = pcmcia_base + ioport_dsc[data_port].base_off;
-#ifdef DEBUG
-	printk ("base: %08x + %08x = %08x\n",
-			pcmcia_base, ioport_dsc[data_port].base_off, base);
-#endif
-
-	for (i = 0; i < IDE_NR_PORTS; ++i) {
-#ifdef DEBUG
-		printk ("port[%d]: %08x + %08x = %08x\n",
-			i,
-			base,
-			ioport_dsc[data_port].reg_off[i],
-			i, base + ioport_dsc[data_port].reg_off[i]);
-#endif
-	 	*p++ = base + ioport_dsc[data_port].reg_off[i];
-	}
-
-	if (irq) {
-#ifdef CONFIG_IDE_8xx_PCCARD
-		unsigned int reg;
-
-		*irq = ioport_dsc[data_port].irq;
-		if (_slot_)
-			pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcrb;
-		else
-			pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcra;
-
-		reg = *pgcrx;
-		reg |= mk_int_int_mask (pcmcia_schlvl) << 24;
-		reg |= mk_int_int_mask (pcmcia_schlvl) << 16;
-		*pgcrx = reg;
-#else	/* direct connected IDE drive, i.e. external IRQ, not the PCMCIA irq */
-		*irq = ioport_dsc[data_port].irq;
-#endif	/* CONFIG_IDE_8xx_PCCARD */
-	}
-
-	/* register routine to tune PIO mode */
-	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
-
-	hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
-	/* Enable Harddisk Interrupt,
-	 * and make it edge sensitive
-	 */
-	/* (11-18) Set edge detect for irq, no wakeup from low power mode */
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |=
-					(0x80000000 >> ioport_dsc[data_port].irq);
-
-#ifdef CONFIG_IDE_8xx_PCCARD
-	/* Make sure we dont get garbage irq */
-	((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pscr = 0xFFFF;
-
-	/* Enable falling edge irq */
-	pcmp->pcmc_per = 0x100000 >> (16 * _slot_);
-#endif	/* CONFIG_IDE_8xx_PCCARD */
-}	/* m8xx_ide_init_hwif_ports() using 8xx internal PCMCIA interface */
-#endif /* CONFIG_IDE_8xx_PCCARD || CONFIG_IDE_8xx_DIRECT */
-
-/*
- * m8xx_ide_init_hwif_ports for a direct IDE interface _not_ using
- * MPC8xx's internal PCMCIA interface
- */
-#if defined(CONFIG_IDE_EXT_DIRECT)
-void m8xx_ide_init_hwif_ports (hw_regs_t *hw,
-	ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
-{
-	ide_ioreg_t *p = hw->io_ports;
-	int i;
-
-	u32 ide_phy_base;
-	u32 ide_phy_end;
-	static unsigned long ide_base = 0;
-	unsigned long base;
-
-	*p = 0;
-	if (irq)
-		*irq = 0;
-
-	if (!ide_base) {
-
-		/* TODO:
-		 * - add code to read ORx, BRx
-		 */
-		ide_phy_base = CFG_ATA_BASE_ADDR;
-		ide_phy_end  = CFG_ATA_BASE_ADDR + 0x200;
-
-		printk ("IDE phys mem : %08x...%08x (size %08x)\n",
-			ide_phy_base, ide_phy_end,
-			ide_phy_end - ide_phy_base);
-		
-		ide_base=(unsigned long)ioremap(ide_phy_base,
-						ide_phy_end-ide_phy_base);
-
-#ifdef DEBUG
-		printk ("IDE virt base: %08lx\n", ide_base);
-#endif
-	}
-
-	if (data_port >= MAX_HWIFS)
-		return;
-
-	base = ide_base + ioport_dsc[data_port].base_off;
-#ifdef DEBUG
-	printk ("base: %08x + %08x = %08x\n",
-		ide_base, ioport_dsc[data_port].base_off, base);
-#endif
-
-	for (i = 0; i < IDE_NR_PORTS; ++i) {
-#ifdef DEBUG
-		printk ("port[%d]: %08x + %08x = %08x\n",
-			i,
-			base,
-			ioport_dsc[data_port].reg_off[i],
-			i, base + ioport_dsc[data_port].reg_off[i]);
-#endif
-	 	*p++ = base + ioport_dsc[data_port].reg_off[i];
-	}
-
-	if (irq) {
-		/* direct connected IDE drive, i.e. external IRQ */
-		*irq = ioport_dsc[data_port].irq;
-	}
-
-	/* register routine to tune PIO mode */
-	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
-
-	hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
-	/* Enable Harddisk Interrupt,
-	 * and make it edge sensitive
-	 */
-	/* (11-18) Set edge detect for irq, no wakeup from low power mode */
-	((immap_t *) IMAP_ADDR)->im_siu_conf.sc_siel |=
-			(0x80000000 >> ioport_dsc[data_port].irq);
-}	/* m8xx_ide_init_hwif_ports() for CONFIG_IDE_8xx_DIRECT */ 
-
-#endif	/* CONFIG_IDE_8xx_DIRECT */
-
-
-/* -------------------------------------------------------------------- */
-
-
-/* PCMCIA Timing */
-#ifndef	PCMCIA_SHT
-#define PCMCIA_SHT(t)	((t & 0x0F)<<16)	/* Strobe Hold  Time 	*/
-#define PCMCIA_SST(t)	((t & 0x0F)<<12)	/* Strobe Setup Time	*/
-#define PCMCIA_SL(t) ((t==32) ? 0 : ((t & 0x1F)<<7)) /* Strobe Length	*/
-#endif
-
-
-/* Calculate PIO timings */
-static void
-m8xx_ide_tuneproc(ide_drive_t *drive, byte pio)
-{
-	ide_pio_data_t d;
-#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
-	volatile pcmconf8xx_t	*pcmp;
-	ulong timing, mask, reg;
-#endif
-
-	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
-
-#if 1
-	printk("%s[%d] %s: best PIO mode: %d\n",
-		__FILE__,__LINE__,__FUNCTION__, pio);
-#endif
-
-#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
-	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
-
-	mask = ~(PCMCIA_SHT(0xFF) | PCMCIA_SST(0xFF) | PCMCIA_SL(0xFF));
-
-	timing  = PCMCIA_SHT(hold_time[pio]  )
-		| PCMCIA_SST(ide_pio_clocks[pio].setup_time )
-		| PCMCIA_SL (ide_pio_clocks[pio].active_time)
-		;
-
-#if 1
-	printk ("Setting timing bits 0x%08lx in PCMCIA controller\n", timing);
-#endif
-	if ((reg = pcmp->pcmc_por0 & mask) != 0)
-		pcmp->pcmc_por0 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por1 & mask) != 0)
-		pcmp->pcmc_por1 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por2 & mask) != 0)
-		pcmp->pcmc_por2 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por3 & mask) != 0)
-		pcmp->pcmc_por3 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por4 & mask) != 0)
-		pcmp->pcmc_por4 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por5 & mask) != 0)
-		pcmp->pcmc_por5 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por6 & mask) != 0)
-		pcmp->pcmc_por6 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por7 & mask) != 0)
-		pcmp->pcmc_por7 = reg | timing;
-
-#elif defined(CONFIG_IDE_EXT_DIRECT)
-
-	printk("%s[%d] %s: not implemented yet!\n",
-		__FILE__,__LINE__,__FUNCTION__);
-#endif /* defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_PCMCIA */
-}
-
-static void
-ide_interrupt_ack (void *dev)
-{
-#ifdef CONFIG_IDE_8xx_PCCARD
-	u_int pscr, pipr;
-
-#if (PCMCIA_SOCKETS_NO == 2)
-	u_int _slot_;
-#endif
-
-	/* get interrupt sources */
-
-	pscr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr;
-	pipr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr;
-
-	/*
-	 * report only if both card detect signals are the same
-	 * not too nice done,
-	 * we depend on that CD2 is the bit to the left of CD1...
-	 */
-
-	if(_slot_==-1){
-	  printk("PCMCIA slot has not been defined! Using A as default\n");
-	  _slot_=0;
-	}
-
-	if(((pipr & M8XX_PCMCIA_CD2(_slot_)) >> 1) ^
-	   (pipr & M8XX_PCMCIA_CD1(_slot_))         ) {
-	  printk ("card detect interrupt\n");
-	}
-	/* clear the interrupt sources */
-	((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = pscr;
-
-#else /* ! CONFIG_IDE_8xx_PCCARD */
-	/*
-	 * Only CONFIG_IDE_8xx_PCCARD is using the interrupt of the
-	 * MPC8xx's PCMCIA controller, so there is nothing to be done here
-	 * for CONFIG_IDE_8xx_DIRECT and CONFIG_IDE_EXT_DIRECT.
-	 * The interrupt is handled somewhere else.	-- Steven
-	 */
-#endif /* CONFIG_IDE_8xx_PCCARD */
-}
-
-
-
-/*
- * CIS Tupel codes
- */
-#define CISTPL_NULL		0x00
-#define CISTPL_DEVICE		0x01
-#define CISTPL_LONGLINK_CB	0x02
-#define CISTPL_INDIRECT		0x03
-#define CISTPL_CONFIG_CB	0x04
-#define CISTPL_CFTABLE_ENTRY_CB 0x05
-#define CISTPL_LONGLINK_MFC	0x06
-#define CISTPL_BAR		0x07
-#define CISTPL_PWR_MGMNT	0x08
-#define CISTPL_EXTDEVICE	0x09
-#define CISTPL_CHECKSUM		0x10
-#define CISTPL_LONGLINK_A	0x11
-#define CISTPL_LONGLINK_C	0x12
-#define CISTPL_LINKTARGET	0x13
-#define CISTPL_NO_LINK		0x14
-#define CISTPL_VERS_1		0x15
-#define CISTPL_ALTSTR		0x16
-#define CISTPL_DEVICE_A		0x17
-#define CISTPL_JEDEC_C		0x18
-#define CISTPL_JEDEC_A		0x19
-#define CISTPL_CONFIG		0x1a
-#define CISTPL_CFTABLE_ENTRY	0x1b
-#define CISTPL_DEVICE_OC	0x1c
-#define CISTPL_DEVICE_OA	0x1d
-#define CISTPL_DEVICE_GEO	0x1e
-#define CISTPL_DEVICE_GEO_A	0x1f
-#define CISTPL_MANFID		0x20
-#define CISTPL_FUNCID		0x21
-#define CISTPL_FUNCE		0x22
-#define CISTPL_SWIL		0x23
-#define CISTPL_END		0xff
-
-/*
- * CIS Function ID codes
- */
-#define CISTPL_FUNCID_MULTI	0x00
-#define CISTPL_FUNCID_MEMORY	0x01
-#define CISTPL_FUNCID_SERIAL	0x02
-#define CISTPL_FUNCID_PARALLEL	0x03
-#define CISTPL_FUNCID_FIXED	0x04
-#define CISTPL_FUNCID_VIDEO	0x05
-#define CISTPL_FUNCID_NETWORK	0x06
-#define CISTPL_FUNCID_AIMS	0x07
-#define CISTPL_FUNCID_SCSI	0x08
-
-/*
- * Fixed Disk FUNCE codes
- */
-#define CISTPL_IDE_INTERFACE	0x01
-
-#define CISTPL_FUNCE_IDE_IFACE	0x01
-#define CISTPL_FUNCE_IDE_MASTER	0x02
-#define CISTPL_FUNCE_IDE_SLAVE	0x03
-
-/* First feature byte */
-#define CISTPL_IDE_SILICON	0x04
-#define CISTPL_IDE_UNIQUE	0x08
-#define CISTPL_IDE_DUAL		0x10
-
-/* Second feature byte */
-#define CISTPL_IDE_HAS_SLEEP	0x01
-#define CISTPL_IDE_HAS_STANDBY	0x02
-#define CISTPL_IDE_HAS_IDLE	0x04
-#define CISTPL_IDE_LOW_POWER	0x08
-#define CISTPL_IDE_REG_INHIBIT	0x10
-#define CISTPL_IDE_HAS_INDEX	0x20
-#define CISTPL_IDE_IOIS16	0x40
-
-
-/* -------------------------------------------------------------------- */
-
-
-#define	MAX_TUPEL_SZ	512
-#define MAX_FEATURES	4
-
-static int check_ide_device (unsigned long base)
-{
-	volatile unsigned char *ident = NULL;
-	volatile unsigned char *feature_p[MAX_FEATURES];
-	volatile unsigned char *p, *start;
-	int n_features = 0;
-	unsigned char func_id = ~0;
-	unsigned char code, len;
-	unsigned short config_base = 0;
-	int found = 0;
-	int i;
-
-#ifdef DEBUG
-	printk ("PCMCIA MEM: %08lX\n", base);
-#endif
-	start = p = (volatile unsigned char *) base;
-
-	while ((p - start) < MAX_TUPEL_SZ) {
-
-		code = *p; p += 2;
-
-		if (code == 0xFF) { /* End of chain */
-			break;
-		}
-
-		len = *p; p += 2;
-#ifdef	DEBUG_PCMCIA
-		{ volatile unsigned char *q = p;
-			printk ("\nTuple code %02x  length %d\n\tData:",
-				code, len);
-
-			for (i = 0; i < len; ++i) {
-				printk (" %02x", *q);
-				q+= 2;
-			}
-		}
-#endif	/* DEBUG_PCMCIA */
-		switch (code) {
-		case CISTPL_VERS_1:
-			ident = p + 4;
-			break;
-		case CISTPL_FUNCID:
-			func_id = *p;
-			break;
-		case CISTPL_FUNCE:
-			if (n_features < MAX_FEATURES)
-				feature_p[n_features++] = p;
-			break;
-		case CISTPL_CONFIG:
-			config_base = (*(p+6) << 8) + (*(p+4));
-		default:
-			break;
-		}
-		p += 2 * len;
-	}
-
-	found = identify (ident);
-
-	if (func_id != ((unsigned char)~0)) {
-		print_funcid (func_id);
-
-		if (func_id == CISTPL_FUNCID_FIXED)
-			found = 1;
-		else
-			return (1);	/* no disk drive */
-	}
-
-	for (i=0; i<n_features; ++i) {
-		print_fixed (feature_p[i]);
-	}
-
-	if (!found) {
-		printk ("unknown card type\n");
-		return (1);
-	}
-
-	/* set level mode irq and I/O mapped device in config reg*/
-	*((unsigned char *)(base + config_base)) = 0x41;
-
-	return (0);
-}
-
-/* ------------------------------------------------------------------------- */
-
-static void print_funcid (int func)
-{
-	switch (func) {
-	case CISTPL_FUNCID_MULTI:
-		printk (" Multi-Function");
-		break;
-	case CISTPL_FUNCID_MEMORY:
-		printk (" Memory");
-		break;
-	case CISTPL_FUNCID_SERIAL:
-		printk (" Serial Port");
-		break;
-	case CISTPL_FUNCID_PARALLEL:
-		printk (" Parallel Port");
-		break;
-	case CISTPL_FUNCID_FIXED:
-		printk (" Fixed Disk");
-		break;
-	case CISTPL_FUNCID_VIDEO:
-		printk (" Video Adapter");
-		break;
-	case CISTPL_FUNCID_NETWORK:
-		printk (" Network Adapter");
-		break;
-	case CISTPL_FUNCID_AIMS:
-		printk (" AIMS Card");
-		break;
-	case CISTPL_FUNCID_SCSI:
-		printk (" SCSI Adapter");
-		break;
-	default:
-		printk (" Unknown");
-		break;
-	}
-	printk (" Card\n");
-}
-
-/* ------------------------------------------------------------------------- */
-
-static void print_fixed (volatile unsigned char *p)
-{
-	if (p == NULL)
-		return;
-
-	switch (*p) {
-	case CISTPL_FUNCE_IDE_IFACE:
-	    {   unsigned char iface = *(p+2);
-
-		printk ((iface == CISTPL_IDE_INTERFACE) ? " IDE" : " unknown");
-		printk (" interface ");
-		break;
-	    }
-	case CISTPL_FUNCE_IDE_MASTER:
-	case CISTPL_FUNCE_IDE_SLAVE:
-	    {   unsigned char f1 = *(p+2);
-		unsigned char f2 = *(p+4);
-
-		printk ((f1 & CISTPL_IDE_SILICON) ? " [silicon]" : " [rotating]");
-
-		if (f1 & CISTPL_IDE_UNIQUE)
-			printk (" [unique]");
-
-		printk ((f1 & CISTPL_IDE_DUAL) ? " [dual]" : " [single]");
-
-		if (f2 & CISTPL_IDE_HAS_SLEEP)
-			printk (" [sleep]");
-
-		if (f2 & CISTPL_IDE_HAS_STANDBY)
-			printk (" [standby]");
-
-		if (f2 & CISTPL_IDE_HAS_IDLE)
-			printk (" [idle]");
-
-		if (f2 & CISTPL_IDE_LOW_POWER)
-			printk (" [low power]");
-
-		if (f2 & CISTPL_IDE_REG_INHIBIT)
-			printk (" [reg inhibit]");
-
-		if (f2 & CISTPL_IDE_HAS_INDEX)
-			printk (" [index]");
-
-		if (f2 & CISTPL_IDE_IOIS16)
-			printk (" [IOis16]");
-
-		break;
-	    }
-	}
-	printk ("\n");
-}
-
-/* ------------------------------------------------------------------------- */
-
-
-#define MAX_IDENT_CHARS		64
-#define	MAX_IDENT_FIELDS	4
-
-static unsigned char *known_cards[] = {
-	"ARGOSY PnPIDE D5",
-	NULL
-};
-
-static int identify  (volatile unsigned char *p)
-{
-	unsigned char id_str[MAX_IDENT_CHARS];
-	unsigned char data;
-	unsigned char *t;
-	unsigned char **card;
-	int i, done;
-
-	if (p == NULL)
-		return (0);	/* Don't know */
-
-	t = id_str;
-	done =0;
-
-	for (i=0; i<=4 && !done; ++i, p+=2) {
-		while ((data = *p) != '\0') {
-			if (data == 0xFF) {
-				done = 1;
-				break;
-			}
-			*t++ = data;
-			if (t == &id_str[MAX_IDENT_CHARS-1]) {
-				done = 1;
-				break;
-			}
-			p += 2;
-		}
-		if (!done)
-			*t++ = ' ';
-	}
-	*t = '\0';
-	while (--t > id_str) {
-		if (*t == ' ')
-			*t = '\0';
-		else
-			break;
-	}
-	printk ("Card ID: %s\n", id_str);
-
-	for (card=known_cards; *card; ++card) {
-		if (strcmp(*card, id_str) == 0) {	/* found! */
-			return (1);
-		}
-	}
-
-	return (0);	/* don't know */
-}
-
-void m8xx_ide_init(void)
-{
-	ppc_ide_md.default_irq          = m8xx_ide_default_irq;
-	ppc_ide_md.default_io_base      = m8xx_ide_default_io_base;
-	ppc_ide_md.ide_init_hwif        = m8xx_ide_init_hwif_ports;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-pci.c linux-2.4.21/drivers/ide/ide-pci.c
--- linux-2.4.20/drivers/ide/ide-pci.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-pci.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1016 +0,0 @@
-/*
- *  linux/drivers/ide/ide-pci.c		Version 1.05	June 9, 2000
- *
- *  Copyright (c) 1998-2000  Andre Hedrick <andre@linux-ide.org>
- *
- *  Copyright (c) 1995-1998  Mark Lord
- *  May be copied or modified under the terms of the GNU General Public License
- */
-
-/*
- *  This module provides support for automatic detection and
- *  configuration of all PCI IDE interfaces present in a system.  
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#define DEVID_PIIXa	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371FB_0})
-#define DEVID_PIIXb	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371FB_1})
-#define DEVID_MPIIX	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371MX})
-#define DEVID_PIIX3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371SB_1})
-#define DEVID_PIIX4	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371AB})
-#define DEVID_ICH0	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801AB_1})
-#define DEVID_PIIX4E2	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82443MX_1})
-#define DEVID_ICH	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801AA_1})
-#define DEVID_PIIX4U2	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82372FB_1})
-#define DEVID_PIIX4NX	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82451NX})
-#define DEVID_ICH2	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801BA_9})
-#define DEVID_ICH2M	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801BA_8})
-#define DEVID_ICH3M	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801CA_10})
-#define DEVID_ICH3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801CA_11})
-#define DEVID_ICH4	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801DB_11})
-#define DEVID_CICH	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801E_11})
-#define DEVID_VIA_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C561})
-#define DEVID_MR_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C576_1})
-#define DEVID_VP_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C586_1})
-#define DEVID_PDC20246	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246})
-#define DEVID_PDC20262	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262})
-#define DEVID_PDC20265	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265})
-#define DEVID_PDC20267	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267})
-#define DEVID_PDC20268  ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268})
-#define DEVID_PDC20270  ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270})
-#define DEVID_PDC20269	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269})
-#define DEVID_PDC20275	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275})
-#define DEVID_PDC20276	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276})
-#define DEVID_RZ1000	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1000})
-#define DEVID_RZ1001	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1001})
-#define DEVID_SAMURAI	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_SAMURAI_IDE})
-#define DEVID_CMD640	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_640})
-#define DEVID_CMD643	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_643})
-#define DEVID_CMD646	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_646})
-#define DEVID_CMD648	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_648})
-#define DEVID_CMD649	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_649})
-#define DEVID_CMD680	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_680})
-#define DEVID_SIS5513	((ide_pci_devid_t){PCI_VENDOR_ID_SI,      PCI_DEVICE_ID_SI_5513})
-#define DEVID_OPTI621	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C621})
-#define DEVID_OPTI621V	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C558})
-#define DEVID_OPTI621X	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C825})
-#define DEVID_TRM290	((ide_pci_devid_t){PCI_VENDOR_ID_TEKRAM,  PCI_DEVICE_ID_TEKRAM_DC290})
-#define DEVID_NS87410	((ide_pci_devid_t){PCI_VENDOR_ID_NS,      PCI_DEVICE_ID_NS_87410})
-#define DEVID_NS87415	((ide_pci_devid_t){PCI_VENDOR_ID_NS,      PCI_DEVICE_ID_NS_87415})
-#define DEVID_HT6565	((ide_pci_devid_t){PCI_VENDOR_ID_HOLTEK,  PCI_DEVICE_ID_HOLTEK_6565})
-#define DEVID_AEC6210	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP850UF})
-#define DEVID_AEC6260	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP860})
-#define DEVID_AEC6260R	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP860R})
-#define DEVID_W82C105	((ide_pci_devid_t){PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105})
-#define DEVID_UM8673F	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8673F})
-#define DEVID_UM8886A	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886A})
-#define DEVID_UM8886BF	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886BF})
-#define DEVID_HPT34X	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT343})
-#define DEVID_HPT366	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT366})
-#define DEVID_ALI15X3	((ide_pci_devid_t){PCI_VENDOR_ID_AL,      PCI_DEVICE_ID_AL_M5229})
-#define DEVID_CY82C693	((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ,  PCI_DEVICE_ID_CONTAQ_82C693})
-#define DEVID_HINT	((ide_pci_devid_t){0x3388,                0x8013})
-#define DEVID_CS5530	((ide_pci_devid_t){PCI_VENDOR_ID_CYRIX,   PCI_DEVICE_ID_CYRIX_5530_IDE})
-#define DEVID_AMD7401	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_COBRA_7401})
-#define DEVID_AMD7409	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7409})
-#define DEVID_AMD7411	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7411})
-#define DEVID_AMD7441	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7441})
-#define DEVID_PDCADMA	((ide_pci_devid_t){PCI_VENDOR_ID_PDC,     PCI_DEVICE_ID_PDC_1841})
-#define DEVID_SLC90E66	((ide_pci_devid_t){PCI_VENDOR_ID_EFAR,    PCI_DEVICE_ID_EFAR_SLC90E66_1})
-#define DEVID_OSB4	((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE})
-#define DEVID_CSB5	((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE})
-#define DEVID_ITE8172G	((ide_pci_devid_t){PCI_VENDOR_ID_ITE,     PCI_DEVICE_ID_ITE_IT8172G})
-
-#define	IDE_IGNORE	((void *)-1)
-#define IDE_NO_DRIVER	((void *)-2)
-
-#ifdef CONFIG_BLK_DEV_AEC62XX
-extern unsigned int pci_init_aec62xx(struct pci_dev *, const char *);
-extern unsigned int ata66_aec62xx(ide_hwif_t *);
-extern void ide_init_aec62xx(ide_hwif_t *);
-extern void ide_dmacapable_aec62xx(ide_hwif_t *, unsigned long);
-#define PCI_AEC62XX	&pci_init_aec62xx
-#define ATA66_AEC62XX	&ata66_aec62xx
-#define INIT_AEC62XX	&ide_init_aec62xx
-#define DMA_AEC62XX	&ide_dmacapable_aec62xx
-#else
-#define PCI_AEC62XX	NULL
-#define ATA66_AEC62XX	NULL
-#define INIT_AEC62XX	IDE_NO_DRIVER
-#define DMA_AEC62XX	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_ALI15X3
-extern unsigned int pci_init_ali15x3(struct pci_dev *, const char *);
-extern unsigned int ata66_ali15x3(ide_hwif_t *);
-extern void ide_init_ali15x3(ide_hwif_t *);
-extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long);
-#define PCI_ALI15X3	&pci_init_ali15x3
-#define ATA66_ALI15X3	&ata66_ali15x3
-#define INIT_ALI15X3	&ide_init_ali15x3
-#define DMA_ALI15X3	&ide_dmacapable_ali15x3
-#else
-#define PCI_ALI15X3	NULL
-#define ATA66_ALI15X3	NULL
-#define INIT_ALI15X3	IDE_NO_DRIVER
-#define DMA_ALI15X3	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_AMD74XX
-extern unsigned int pci_init_amd74xx(struct pci_dev *, const char *);
-extern unsigned int ata66_amd74xx(ide_hwif_t *);
-extern void ide_init_amd74xx(ide_hwif_t *);
-extern void ide_dmacapable_amd74xx(ide_hwif_t *, unsigned long);
-#define PCI_AMD74XX	&pci_init_amd74xx
-#define ATA66_AMD74XX	&ata66_amd74xx
-#define INIT_AMD74XX	&ide_init_amd74xx
-#define DMA_AMD74XX	&ide_dmacapable_amd74xx
-#else
-#define PCI_AMD74XX	NULL
-#define ATA66_AMD74XX	NULL
-#define INIT_AMD74XX	IDE_NO_DRIVER
-#define DMA_AMD74XX	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_CMD64X
-extern unsigned int pci_init_cmd64x(struct pci_dev *, const char *);
-extern unsigned int ata66_cmd64x(ide_hwif_t *);
-extern void ide_init_cmd64x(ide_hwif_t *);
-extern void ide_dmacapable_cmd64x(ide_hwif_t *, unsigned long);
-#define PCI_CMD64X	&pci_init_cmd64x
-#define ATA66_CMD64X	&ata66_cmd64x
-#define INIT_CMD64X	&ide_init_cmd64x
-#else
-#define PCI_CMD64X	NULL
-#define ATA66_CMD64X	NULL
-#ifdef __sparc_v9__
-#define INIT_CMD64X	IDE_IGNORE
-#else
-#define INIT_CMD64X	IDE_NO_DRIVER
-#endif
-#endif
-
-#ifdef CONFIG_BLK_DEV_CY82C693
-extern unsigned int pci_init_cy82c693(struct pci_dev *, const char *);
-extern void ide_init_cy82c693(ide_hwif_t *);
-#define PCI_CY82C693	&pci_init_cy82c693
-#define INIT_CY82C693	&ide_init_cy82c693
-#else
-#define PCI_CY82C693	NULL
-#define INIT_CY82C693	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_CS5530
-extern unsigned int pci_init_cs5530(struct pci_dev *, const char *);
-extern void ide_init_cs5530(ide_hwif_t *);
-#define PCI_CS5530	&pci_init_cs5530
-#define INIT_CS5530	&ide_init_cs5530
-#else
-#define PCI_CS5530	NULL
-#define INIT_CS5530	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_HPT34X
-extern unsigned int pci_init_hpt34x(struct pci_dev *, const char *);
-extern void ide_init_hpt34x(ide_hwif_t *);
-#define PCI_HPT34X	&pci_init_hpt34x
-#define INIT_HPT34X	&ide_init_hpt34x
-#else
-#define PCI_HPT34X	NULL
-#define INIT_HPT34X	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_HPT366
-extern byte hpt363_shared_irq;
-extern byte hpt363_shared_pin;
-extern unsigned int pci_init_hpt366(struct pci_dev *, const char *);
-extern unsigned int ata66_hpt366(ide_hwif_t *);
-extern void ide_init_hpt366(ide_hwif_t *);
-extern void ide_dmacapable_hpt366(ide_hwif_t *, unsigned long);
-#define PCI_HPT366	&pci_init_hpt366
-#define ATA66_HPT366	&ata66_hpt366
-#define INIT_HPT366	&ide_init_hpt366
-#define DMA_HPT366	&ide_dmacapable_hpt366
-#else
-static byte hpt363_shared_irq;
-static byte hpt363_shared_pin;
-#define PCI_HPT366	NULL
-#define ATA66_HPT366	NULL
-#define INIT_HPT366	IDE_NO_DRIVER
-#define DMA_HPT366	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_NS87415
-extern void ide_init_ns87415(ide_hwif_t *);
-#define INIT_NS87415	&ide_init_ns87415
-#else
-#define INIT_NS87415	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_OPTI621
-extern void ide_init_opti621(ide_hwif_t *);
-#define INIT_OPTI621	&ide_init_opti621
-#else
-#define INIT_OPTI621	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_PDC_ADMA
-extern unsigned int pci_init_pdcadma(struct pci_dev *, const char *);
-extern unsigned int ata66_pdcadma(ide_hwif_t *);
-extern void ide_init_pdcadma(ide_hwif_t *);
-extern void ide_dmacapable_pdcadma(ide_hwif_t *, unsigned long);
-#define PCI_PDCADMA	&pci_init_pdcadma
-#define ATA66_PDCADMA	&ata66_pdcadma
-#define INIT_PDCADMA	&ide_init_pdcadma
-#define DMA_PDCADMA	&ide_dmacapable_pdcadma
-#else
-#define PCI_PDCADMA	IDE_IGNORE
-#define ATA66_PDCADMA	IDE_IGNORE
-#define INIT_PDCADMA	IDE_IGNORE
-#define DMA_PDCADMA	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_PDC202XX
-extern unsigned int pci_init_pdc202xx(struct pci_dev *, const char *);
-extern unsigned int ata66_pdc202xx(ide_hwif_t *);
-extern void ide_init_pdc202xx(ide_hwif_t *);
-#define PCI_PDC202XX	&pci_init_pdc202xx
-#define ATA66_PDC202XX	&ata66_pdc202xx
-#define INIT_PDC202XX	&ide_init_pdc202xx
-#else
-#define PCI_PDC202XX	NULL
-#define ATA66_PDC202XX	NULL
-#define INIT_PDC202XX	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_PIIX
-extern unsigned int pci_init_piix(struct pci_dev *, const char *);
-extern unsigned int ata66_piix(ide_hwif_t *);
-extern void ide_init_piix(ide_hwif_t *);
-#define PCI_PIIX	&pci_init_piix
-#define ATA66_PIIX	&ata66_piix
-#define INIT_PIIX	&ide_init_piix
-#else
-#define PCI_PIIX	NULL
-#define ATA66_PIIX	NULL
-#define INIT_PIIX	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_IT8172
-extern unsigned int pci_init_it8172(struct pci_dev *, const char *);
-extern unsigned int ata66_it8172(ide_hwif_t *);
-extern void ide_init_it8172(ide_hwif_t *);
-#define PCI_IT8172	&pci_init_it8172
-#define INIT_IT8172	&ide_init_it8172
-#else
-#define PCI_IT8172	NULL
-#define ATA66_IT8172	NULL
-#define INIT_IT8172	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_RZ1000
-extern void ide_init_rz1000(ide_hwif_t *);
-#define INIT_RZ1000	&ide_init_rz1000
-#else
-#define INIT_RZ1000	IDE_IGNORE
-#endif
-
-#define INIT_SAMURAI	NULL
-
-#ifdef CONFIG_BLK_DEV_SVWKS
-extern unsigned int pci_init_svwks(struct pci_dev *, const char *);
-extern unsigned int ata66_svwks(ide_hwif_t *);
-extern void ide_init_svwks(ide_hwif_t *);
-#define PCI_SVWKS	&pci_init_svwks
-#define ATA66_SVWKS	&ata66_svwks
-#define INIT_SVWKS	&ide_init_svwks
-#else
-#define PCI_SVWKS	NULL
-#define ATA66_SVWKS	NULL
-#define INIT_SVWKS	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_SIS5513
-extern unsigned int pci_init_sis5513(struct pci_dev *, const char *);
-extern unsigned int ata66_sis5513(ide_hwif_t *);
-extern void ide_init_sis5513(ide_hwif_t *);
-#define PCI_SIS5513	&pci_init_sis5513
-#define ATA66_SIS5513	&ata66_sis5513
-#define INIT_SIS5513	&ide_init_sis5513
-#else
-#define PCI_SIS5513	NULL
-#define ATA66_SIS5513	NULL
-#define INIT_SIS5513	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_SLC90E66
-extern unsigned int pci_init_slc90e66(struct pci_dev *, const char *);
-extern unsigned int ata66_slc90e66(ide_hwif_t *);
-extern void ide_init_slc90e66(ide_hwif_t *);
-#define PCI_SLC90E66	&pci_init_slc90e66
-#define ATA66_SLC90E66	&ata66_slc90e66
-#define INIT_SLC90E66	&ide_init_slc90e66
-#else
-#define PCI_SLC90E66	NULL
-#define ATA66_SLC90E66	NULL
-#define INIT_SLC90E66	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_SL82C105
-extern unsigned int pci_init_sl82c105(struct pci_dev *, const char *);
-extern void dma_init_sl82c105(ide_hwif_t *, unsigned long);
-extern void ide_init_sl82c105(ide_hwif_t *);
-#define PCI_W82C105	&pci_init_sl82c105
-#define DMA_W82C105	&dma_init_sl82c105
-#define INIT_W82C105	&ide_init_sl82c105
-#else
-#define PCI_W82C105	NULL
-#define DMA_W82C105	NULL
-#define INIT_W82C105	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_TRM290
-extern void ide_init_trm290(ide_hwif_t *);
-#define INIT_TRM290	&ide_init_trm290
-#else
-#define INIT_TRM290	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-extern unsigned int pci_init_via82cxxx(struct pci_dev *, const char *);
-extern unsigned int ata66_via82cxxx(ide_hwif_t *);
-extern void ide_init_via82cxxx(ide_hwif_t *);
-extern void ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long);
-#define PCI_VIA82CXXX	&pci_init_via82cxxx
-#define ATA66_VIA82CXXX	&ata66_via82cxxx
-#define INIT_VIA82CXXX	&ide_init_via82cxxx
-#define DMA_VIA82CXXX	&ide_dmacapable_via82cxxx
-#else
-#define PCI_VIA82CXXX	NULL
-#define ATA66_VIA82CXXX	NULL
-#define INIT_VIA82CXXX	IDE_NO_DRIVER
-#define DMA_VIA82CXXX	NULL
-#endif
-
-typedef struct ide_pci_enablebit_s {
-	byte	reg;	/* byte pci reg holding the enable-bit */
-	byte	mask;	/* mask to isolate the enable-bit */
-	byte	val;	/* value of masked reg when "enabled" */
-} ide_pci_enablebit_t;
-
-typedef struct ide_pci_device_s {
-	ide_pci_devid_t		devid;
-	char			*name;
-	unsigned int		(*init_chipset)(struct pci_dev *dev, const char *name);
-	unsigned int		(*ata66_check)(ide_hwif_t *hwif);
-	void 			(*init_hwif)(ide_hwif_t *hwif);
-	void			(*dma_init)(ide_hwif_t *hwif, unsigned long dmabase);
-	ide_pci_enablebit_t	enablebits[2];
-	byte			bootable;
-	unsigned int		extra;
-} ide_pci_device_t;
-
-static ide_pci_device_t ide_pci_chipsets[] __initdata = {
-	{DEVID_PIIXa,	"PIIX",		NULL,		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_PIIXb,	"PIIX",		NULL,		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_MPIIX,	"MPIIX",	NULL,		NULL,		INIT_PIIX,	NULL,		{{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX3,	"PIIX3",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_PIIX4,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_ICH0,	"ICH0", 	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4E2,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH,	"ICH",  	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4U2,	"PIIX4",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4NX,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH2,	"ICH2", 	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH2M,	"ICH2M",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH3M,	"ICH3M",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH3,	"ICH3", 	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH4,	"ICH4", 	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_CICH,	"C-ICH",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_VIA_IDE,	"VIA_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_MR_IDE,	"VP_IDE",	PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
-	{DEVID_VP_IDE,	"VP_IDE",	PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
-#ifndef CONFIG_PDC202XX_FORCE
-        {DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	16 },
-        {DEVID_PDC20262,"PDC20262",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
-        {DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
-        {DEVID_PDC20267,"PDC20267",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
-#else /* !CONFIG_PDC202XX_FORCE */
-	{DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}}, 	OFF_BOARD,	16 },
-	{DEVID_PDC20262,"PDC20262",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
-	{DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
-	{DEVID_PDC20267,"PDC20267",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
-#endif
-	{DEVID_PDC20268,"PDC20268",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	/* Promise used a different PCI ident for the raid card apparently to try and
-	   prevent Linux detecting it and using our own raid code. We want to detect
-	   it for the ataraid drivers, so we have to list both here.. */
-	{DEVID_PDC20270,"PDC20270",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_PDC20269,"PDC20269",	PCI_PDC202XX,	ATA66_PDC202XX,	 INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_PDC20275,"PDC20275",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_PDC20276,"PDC20276",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_RZ1000,	"RZ1000",	NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_RZ1001,	"RZ1001",	NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_SAMURAI,	"SAMURAI",	NULL,		NULL,		INIT_SAMURAI,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CMD640,	"CMD640",	NULL,		NULL,		IDE_IGNORE,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_NS87410,	"NS87410",	NULL,		NULL,		NULL,		NULL,		{{0x43,0x08,0x08}, {0x47,0x08,0x08}}, 	ON_BOARD,	0 },
-	{DEVID_SIS5513,	"SIS5513",	PCI_SIS5513,	ATA66_SIS5513,	INIT_SIS5513,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	ON_BOARD,	0 },
-	{DEVID_CMD643,	"CMD643",	PCI_CMD64X,	NULL,		INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CMD646,	"CMD646",	PCI_CMD64X,	NULL,		INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x51,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_CMD648,	"CMD648",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CMD649,	"CMD649",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-#ifndef CONFIG_BLK_DEV_CMD680
-	{DEVID_CMD680,	"CMD680",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-#else /* CONFIG_BLK_DEV_CMD680 */
-	{DEVID_CMD680,	"CMD680",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-#endif /* !CONFIG_BLK_DEV_CMD680 */
-	{DEVID_HT6565,	"HT6565",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_OPTI621,	"OPTI621",	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_OPTI621X,"OPTI621X",	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_TRM290,	"TRM290",	NULL,		NULL,		INIT_TRM290,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_NS87415,	"NS87415",	NULL,		NULL,		INIT_NS87415,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_AEC6210,	"AEC6210",	PCI_AEC62XX,	NULL,		INIT_AEC62XX,	DMA_AEC62XX,	{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	OFF_BOARD,	0 },
-	{DEVID_AEC6260,	"AEC6260",	PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	0 },
-	{DEVID_AEC6260R,"AEC6260R",	PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},	OFF_BOARD,	0 },
-	{DEVID_W82C105,	"W82C105",	PCI_W82C105,	NULL,		INIT_W82C105,	DMA_W82C105,	{{0x40,0x01,0x01}, {0x40,0x10,0x10}}, 	ON_BOARD,	0 },
-	{DEVID_UM8673F,	"UM8673F",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_UM8886A,	"UM8886A",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_UM8886BF,"UM8886BF",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_HPT34X,	"HPT34X",	PCI_HPT34X,	NULL,		INIT_HPT34X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	16 },
-	{DEVID_HPT366,	"HPT366",	PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	240 },
-	{DEVID_ALI15X3,	"ALI15X3",	PCI_ALI15X3,	ATA66_ALI15X3,	INIT_ALI15X3,	DMA_ALI15X3,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CY82C693,"CY82C693",	PCI_CY82C693,	NULL,		INIT_CY82C693,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_HINT,	"HINT_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CS5530,	"CS5530",	PCI_CS5530,	NULL,		INIT_CS5530,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_AMD7401,	"AMD7401",	NULL,		NULL,		NULL,		DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_AMD7409,	"AMD7409",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_AMD7411,	"AMD7411",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_AMD7441,	"AMD7441",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_PDCADMA,	"PDCADMA",	PCI_PDCADMA,	ATA66_PDCADMA,	INIT_PDCADMA,	DMA_PDCADMA,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_SLC90E66,"SLC90E66",	PCI_SLC90E66,	ATA66_SLC90E66,	INIT_SLC90E66,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-        {DEVID_OSB4,    "ServerWorks OSB4",		PCI_SVWKS,	ATA66_SVWKS,	INIT_SVWKS,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CSB5,	"ServerWorks CSB5",		PCI_SVWKS,	ATA66_SVWKS,	INIT_SVWKS,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_ITE8172G,"IT8172G",	PCI_IT8172,	NULL,	INIT_IT8172,	NULL,		{{0x00,0x00,0x00}, {0x40,0x00,0x01}},	ON_BOARD,	0 },
-	{IDE_PCI_DEVID_NULL, "PCI_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 }};
-
-/*
- * This allows offboard ide-pci cards the enable a BIOS, verify interrupt
- * settings of split-mirror pci-config space, place chipset into init-mode,
- * and/or preserve an interrupt if the card is not native ide support.
- */
-static unsigned int __init ide_special_settings (struct pci_dev *dev, const char *name)
-{
-	switch(dev->device) {
-		case PCI_DEVICE_ID_TTI_HPT366:
-		case PCI_DEVICE_ID_PROMISE_20246:
-		case PCI_DEVICE_ID_PROMISE_20262:
-		case PCI_DEVICE_ID_PROMISE_20265:
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20270:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			return dev->irq;
-		default:
-			break;
-	}
-	return 0;
-}
-
-/*
- * Match a PCI IDE port against an entry in ide_hwifs[],
- * based on io_base port if possible.
- */
-static ide_hwif_t __init *ide_match_hwif (unsigned long io_base, byte bootable, const char *name)
-{
-	int h;
-	ide_hwif_t *hwif;
-
-	/*
-	 * Look for a hwif with matching io_base specified using
-	 * parameters to ide_setup().
-	 */
-	for (h = 0; h < MAX_HWIFS; ++h) {
-		hwif = &ide_hwifs[h];
-		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
-			if (hwif->chipset == ide_generic)
-				return hwif; /* a perfect match */
-		}
-	}
-	/*
-	 * Look for a hwif with matching io_base default value.
-	 * If chipset is "ide_unknown", then claim that hwif slot.
-	 * Otherwise, some other chipset has already claimed it..  :(
-	 */
-	for (h = 0; h < MAX_HWIFS; ++h) {
-		hwif = &ide_hwifs[h];
-		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
-			if (hwif->chipset == ide_unknown)
-				return hwif; /* match */
-			printk("%s: port 0x%04lx already claimed by %s\n", name, io_base, hwif->name);
-			return NULL;	/* already claimed */
-		}
-	}
-	/*
-	 * Okay, there is no hwif matching our io_base,
-	 * so we'll just claim an unassigned slot.
-	 * Give preference to claiming other slots before claiming ide0/ide1,
-	 * just in case there's another interface yet-to-be-scanned
-	 * which uses ports 1f0/170 (the ide0/ide1 defaults).
-	 *
-	 * Unless there is a bootable card that does not use the standard
-	 * ports 1f0/170 (the ide0/ide1 defaults). The (bootable) flag.
-	 */
-	if (bootable) {
-		for (h = 0; h < MAX_HWIFS; ++h) {
-			hwif = &ide_hwifs[h];
-			if (hwif->chipset == ide_unknown)
-				return hwif;	/* pick an unused entry */
-		}
-	} else {
-		for (h = 2; h < MAX_HWIFS; ++h) {
-			hwif = ide_hwifs + h;
-			if (hwif->chipset == ide_unknown)
-				return hwif;	/* pick an unused entry */
-		}
-	}
-	for (h = 0; h < 2; ++h) {
-		hwif = ide_hwifs + h;
-		if (hwif->chipset == ide_unknown)
-			return hwif;	/* pick an unused entry */
-	}
-	printk("%s: too many IDE interfaces, no room in table\n", name);
-	return NULL;
-}
-
-static int __init ide_setup_pci_baseregs (struct pci_dev *dev, const char *name)
-{
-	byte reg, progif = 0;
-
-	/*
-	 * Place both IDE interfaces into PCI "native" mode:
-	 */
-	if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || (progif & 5) != 5) {
-		if ((progif & 0xa) != 0xa) {
-			printk("%s: device not capable of full native PCI mode\n", name);
-			return 1;
-		}
-		printk("%s: placing both ports into native PCI mode\n", name);
-		(void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
-		if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || (progif & 5) != 5) {
-			printk("%s: rewrite of PROGIF failed, wanted 0x%04x, got 0x%04x\n", name, progif|5, progif);
-			return 1;
-		}
-	}
-	/*
-	 * Setup base registers for IDE command/control spaces for each interface:
-	 */
-	for (reg = 0; reg < 4; reg++) {
-		struct resource *res = dev->resource + reg;
-		if ((res->flags & IORESOURCE_IO) == 0)
-			continue;
-		if (!res->start) {
-			printk("%s: Missing I/O address #%d\n", name, reg);
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- * ide_setup_pci_device() looks at the primary/secondary interfaces
- * on a PCI IDE device and, if they are enabled, prepares the IDE driver
- * for use with them.  This generic code works for most PCI chipsets.
- *
- * One thing that is not standardized is the location of the
- * primary/secondary interface "enable/disable" bits.  For chipsets that
- * we "know" about, this information is in the ide_pci_device_t struct;
- * for all other chipsets, we just assume both interfaces are enabled.
- */
-static void __init ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d)
-{
-	unsigned int port, at_least_one_hwif_enabled = 0, autodma = 0, pciirq = 0;
-	unsigned short pcicmd = 0, tried_config = 0;
-	byte tmp = 0;
-	ide_hwif_t *hwif, *mate = NULL;
-	unsigned int class_rev;
-	static int secondpdc = 0;
-
-#ifdef CONFIG_IDEDMA_AUTO
-	if (!noautodma)
-		autodma = 1;
-#endif
-
-	if (d->init_hwif == IDE_NO_DRIVER) {
-		printk(KERN_WARNING "%s: detected chipset, but driver not compiled in!\n", d->name);
-		d->init_hwif = NULL;
-	}
-
-	if (pci_enable_device(dev)) {
-		if(pci_enable_device_bars(dev, 1<<4))
-		{
-			printk(KERN_WARNING "%s: (ide_setup_pci_device:) Could not enable device.\n", d->name);
-			return;
-		}
-		printk(KERN_INFO "%s: BIOS setup was incomplete.\n", d->name);
-	}
-
-check_if_enabled:
-	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
-		printk("%s: error accessing PCI regs\n", d->name);
-		return;
-	}
-	if (!(pcicmd & PCI_COMMAND_IO)) {	/* is device disabled? */
-		/*
-		 * PnP BIOS was *supposed* to have set this device up for us,
-		 * but we can do it ourselves, so long as the BIOS has assigned an IRQ
-		 *  (or possibly the device is using a "legacy header" for IRQs).
-		 * Maybe the user deliberately *disabled* the device,
-		 * but we'll eventually ignore it again if no drives respond.
-		 */
-		if (tried_config++
-		 || ide_setup_pci_baseregs(dev, d->name)
-		 || pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_IO)) {
-			printk("%s: device disabled (BIOS)\n", d->name);
-			return;
-		}
-		autodma = 0;	/* default DMA off if we had to configure it here */
-		goto check_if_enabled;
-	}
-	if (tried_config)
-		printk("%s: device enabled (Linux)\n", d->name);
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-
-	if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) {
-		/* see comments in hpt34x.c on why..... */
-		char *chipset_names[] = {"HPT343", "HPT345"};
-		strcpy(d->name, chipset_names[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0]);
-		d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD;
-	}
-
-	printk("%s: chipset revision %d\n", d->name, class_rev);
-
-	/*
-	 * Can we trust the reported IRQ?
-	 */
-	pciirq = dev->irq;
-	
-	if (dev->class >> 8 == PCI_CLASS_STORAGE_RAID)
-	{
-	    /*  By rights we want to ignore these, but the Promise Fastrak
-		 *	people have some strange ideas about proprietary so we have
-		 *	to act otherwise on those. The supertrak however we need
-		 *	to skip 
-		 */
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265))
-		{
-			printk(KERN_INFO "ide: Found promise 20265 in RAID mode.\n");
-			if(dev->bus->self && dev->bus->self->vendor == PCI_VENDOR_ID_INTEL &&
-			   dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960)
-			{
-				printk(KERN_INFO "ide: Skipping Promise PDC20265 attached to I2O RAID controller.\n");
-				return;
-			}
-		}
-		/* Its attached to something else, just a random bridge.
-		   Suspect a fastrak and fall through */
-	}
-
-	if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) {
-		printk("%s: not 100%% native mode: will probe irqs later\n", d->name);
-		/*
-		 * This allows offboard ide-pci cards the enable a BIOS,
-		 * verify interrupt settings of split-mirror pci-config
-		 * space, place chipset into init-mode, and/or preserve
-		 * an interrupt if the card is not native ide support.
-		 */
-		pciirq = (d->init_chipset) ? d->init_chipset(dev, d->name) : ide_special_settings(dev, d->name);
-	} else if (tried_config) {
-		printk("%s: will probe irqs later\n", d->name);
-		pciirq = 0;
-	} else if (!pciirq) {
-		printk("%s: bad irq (%d): will probe later\n", d->name, pciirq);
-		pciirq = 0;
-	} else {
-		if (d->init_chipset)
-			(void) d->init_chipset(dev, d->name);
-#ifdef __sparc__
-		printk("%s: 100%% native mode on irq %s\n",
-		       d->name, __irq_itoa(pciirq));
-#else
-		printk("%s: 100%% native mode on irq %d\n", d->name, pciirq);
-#endif
-	}
-
-	/*
-	 * Set up the IDE ports
-	 */
-	for (port = 0; port <= 1; ++port) {
-		unsigned long base = 0, ctl = 0;
-		ide_pci_enablebit_t *e = &(d->enablebits[port]);
-	
-		/* 
-		 * If this is a Promise FakeRaid controller, the 2nd controller will be marked as 
-		 * disabled while it is actually there and enabled by the bios for raid purposes. 
-		 * Skip the normal "is it enabled" test for those.
-		 */
-		if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265)) && (secondpdc++==1) && (port==1)  ) 
-			goto controller_ok;
-		if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262)) && (secondpdc++==1) && (port==1)  ) 
-			goto controller_ok;
-			
-		if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || (tmp & e->mask) != e->val))
-			continue;	/* port not enabled */
-controller_ok:			
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) && (port) && (class_rev < 0x03))
-			return;
-		if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE || (dev->class & (port ? 4 : 1)) != 0) {
-			ctl  = dev->resource[(2*port)+1].start;
-			base = dev->resource[2*port].start;
-			if (!(ctl & PCI_BASE_ADDRESS_IO_MASK) ||
-			    !(base & PCI_BASE_ADDRESS_IO_MASK)) {
-				printk("%s: IO baseregs (BIOS) are reported as MEM, report to <andre@linux-ide.org>.\n", d->name);
-#if 0
-				/* FIXME! This really should check that it really gets the IO/MEM part right! */
-				continue;
-#endif
-			}
-		}
-		if ((ctl && !base) || (base && !ctl)) {
-			printk("%s: inconsistent baseregs (BIOS) for port %d, skipping\n", d->name, port);
-			continue;
-		}
-		if (!ctl)
-			ctl = port ? 0x374 : 0x3f4;	/* use default value */
-		if (!base)
-			base = port ? 0x170 : 0x1f0;	/* use default value */
-		if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL)
-			continue;	/* no room in ide_hwifs[] */
-		if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
-			ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL);
-			memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-			hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
-		}
-		hwif->chipset = ide_pci;
-		hwif->pci_dev = dev;
-		hwif->pci_devid = d->devid;
-		hwif->channel = port;
-		if (!hwif->irq)
-			hwif->irq = pciirq;
-		if (mate) {
-			hwif->mate = mate;
-			mate->mate = hwif;
-			if (IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210)) {
-				hwif->serialized = 1;
-				mate->serialized = 1;
-			}
-		}
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886BF) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8673F)) {
-			hwif->irq = hwif->channel ? 15 : 14;
-			goto bypass_umc_dma;
-		}
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_MPIIX))
-			goto bypass_piix_dma;
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDCADMA))
-			goto bypass_legacy_dma;
-		if (hwif->udma_four) {
-			printk("%s: ATA-66/100 forced bit set (WARNING)!!\n", d->name);
-		} else {
-			hwif->udma_four = (d->ata66_check) ? d->ata66_check(hwif) : 0;
-		}
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PIIX4NX) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)  ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_VIA_IDE) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_MR_IDE)  ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_VP_IDE))
-			autodma = 0;
-		if (autodma)
-			hwif->autodma = 1;
-
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20267) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20270) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20269) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20275) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20276) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260R) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD646) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD648) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD649) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD680) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_OSB4) ||
-		    ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) {
-			unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name);
-			if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) {
-				/*
- 	 			 * Set up BM-DMA capability (PnP BIOS should have done this)
- 	 			 */
-		    		if (!IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530))
-					hwif->autodma = 0;	/* default DMA off if we had to configure it here */
-				(void) pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_MASTER);
-				if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) || !(pcicmd & PCI_COMMAND_MASTER)) {
-					printk("%s: %s error updating PCICMD\n", hwif->name, d->name);
-					dma_base = 0;
-				}
-			}
-			if (dma_base) {
-				if (d->dma_init) {
-					d->dma_init(hwif, dma_base);
-				} else {
-					ide_setup_dma(hwif, dma_base, 8);
-				}
-			} else {
-				printk("%s: %s Bus-Master DMA disabled (BIOS)\n", hwif->name, d->name);
-			}
-		}
-#endif	/* CONFIG_BLK_DEV_IDEDMA */
-bypass_legacy_dma:
-bypass_piix_dma:
-bypass_umc_dma:
-		if (d->init_hwif)  /* Call chipset-specific routine for each enabled hwif */
-			d->init_hwif(hwif);
-		mate = hwif;
-		at_least_one_hwif_enabled = 1;
-	}
-	if (!at_least_one_hwif_enabled)
-		printk("%s: neither IDE port enabled (BIOS)\n", d->name);
-}
-
-static void __init pdc20270_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)
-{
-	struct pci_dev *dev2 = NULL, *findev;
-	ide_pci_device_t *d2;
-
-	if ((dev->bus->self &&
-	     dev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
-	    (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) {
-		if (PCI_SLOT(dev->devfn) & 2) {
-			return;
-		}
-		d->extra = 0;
-		pci_for_each_dev(findev) {
-			if ((findev->vendor == dev->vendor) &&
-			    (findev->device == dev->device) &&
-			    (PCI_SLOT(findev->devfn) & 2)) {
-				byte irq = 0, irq2 = 0;
-				dev2 = findev;
-				pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
-				pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2);
-                                if (irq != irq2) {
-					dev2->irq = dev->irq;
-                                        pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, irq);
-                                }
-
-			}
-		}
-	}
-
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn);
-	ide_setup_pci_device(dev, d);
-	if (!dev2)
-		return;
-	d2 = d;
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn);
-	ide_setup_pci_device(dev2, d2);
-}
-
-static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)
-{
-	struct pci_dev *dev2 = NULL, *findev;
-	ide_pci_device_t *d2;
-	unsigned char pin1 = 0, pin2 = 0;
-	unsigned int class_rev;
-	char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A", "HPT372"};
-
-	if (PCI_FUNC(dev->devfn) & 1)
-		return;
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-	if (class_rev > 5)
-		class_rev = 5;
-	
-	strcpy(d->name, chipset_names[class_rev]);
-
-	switch(class_rev) {
-		case 4:
-		case 3:	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn);
-			ide_setup_pci_device(dev, d);
-			return;
-		default:	break;
-	}
-
-	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
-	pci_for_each_dev(findev) {
-		if ((findev->vendor == dev->vendor) &&
-		    (findev->device == dev->device) &&
-		    ((findev->devfn - dev->devfn) == 1) &&
-		    (PCI_FUNC(findev->devfn) & 1)) {
-			dev2 = findev;
-			pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
-			hpt363_shared_pin = (pin1 != pin2) ? 1 : 0;
-			hpt363_shared_irq = (dev->irq == dev2->irq) ? 1 : 0;
-			if (hpt363_shared_pin && hpt363_shared_irq) {
-				d->bootable = ON_BOARD;
-				printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", d->name, pin1, pin2);
-#if 0
-				/* I forgot why I did this once, but it fixed something. */
-				pci_write_config_byte(dev2, PCI_INTERRUPT_PIN, dev->irq);
-				printk("PCI: %s: Fixing interrupt %d pin %d to ZERO \n", d->name, dev2->irq, pin2);
-				pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, 0);
-#endif
-			}
-			break;
-		}
-	}
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn);
-	ide_setup_pci_device(dev, d);
-	if (!dev2)
-		return;
-	d2 = d;
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn);
-	ide_setup_pci_device(dev2, d2);
-}
-
-/*
- * ide_scan_pcibus() gets invoked at boot time from ide.c.
- * It finds all PCI IDE controllers and calls ide_setup_pci_device for them.
- */
-void __init ide_scan_pcidev (struct pci_dev *dev)
-{
-	ide_pci_devid_t		devid;
-	ide_pci_device_t	*d;
-
-	devid.vid = dev->vendor;
-	devid.did = dev->device;
-	for (d = ide_pci_chipsets; d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d);
-	if (d->init_hwif == IDE_IGNORE)
-		printk("%s: ignored by ide_scan_pci_device() (uses own driver)\n", d->name);
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_OPTI621V) && !(PCI_FUNC(dev->devfn) & 1))
-		return;
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))
-		return;	/* CY82C693 is more than only a IDE controller */
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_ITE8172G) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))
-		return;	/* IT8172G is also more than only an IDE controller */
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) && !(PCI_FUNC(dev->devfn) & 1))
-		return;	/* UM8886A/BF pair */
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366))
-		hpt366_device_order_fixup(dev, d);
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20270))
-		pdc20270_device_order_fixup(dev, d);
-	else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
-		if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL))
-			printk("%s: unknown IDE controller on PCI bus %02x device %02x, VID=%04x, DID=%04x\n",
-			       d->name, dev->bus->number, dev->devfn, devid.vid, devid.did);
-		else
-			printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn);
-		ide_setup_pci_device(dev, d);
-	}
-}
-
-void __init ide_scan_pcibus (int scan_direction)
-{
-	struct pci_dev *dev;
-
-	if (!scan_direction) {
-		pci_for_each_dev(dev) {
-			ide_scan_pcidev(dev);
-		}
-	} else {
-		pci_for_each_dev_reverse(dev) {
-			ide_scan_pcidev(dev);
-		}
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-pmac.c linux-2.4.21/drivers/ide/ide-pmac.c
--- linux-2.4.20/drivers/ide/ide-pmac.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-pmac.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1794 +0,0 @@
-/*
- * linux/drivers/ide/ide-pmac.c
- *
- * Support for IDE interfaces on PowerMacs.
- * These IDE interfaces are memory-mapped and have a DBDMA channel
- * for doing DMA.
- *
- *  Copyright (C) 1998-2001 Paul Mackerras & Ben. Herrenschmidt
- *
- *  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.
- *
- * Some code taken from drivers/ide/ide-dma.c:
- *
- *  Copyright (c) 1995-1998  Mark Lord
- *
- */
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/pci.h>
-
-#include <asm/prom.h>
-#include <asm/io.h>
-#include <asm/dbdma.h>
-#include <asm/ide.h>
-#include <asm/mediabay.h>
-#include <asm/pci-bridge.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/sections.h>
-#include <asm/irq.h>
-#ifdef CONFIG_PMAC_PBOOK
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#endif
-#include "ide_modes.h"
-
-extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
-extern void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq);
-
-#define IDE_PMAC_DEBUG
-
-#define DMA_WAIT_TIMEOUT	500
-
-struct pmac_ide_hwif {
-	ide_ioreg_t			regbase;
-	int				irq;
-	int				kind;
-	int				aapl_bus_id;
-	struct device_node*		node;
-	u32				timings[2];
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-	/* Those fields are duplicating what is in hwif. We currently
-	 * can't use the hwif ones because of some assumptions that are
-	 * beeing done by the generic code about the kind of dma controller
-	 * and format of the dma table. This will have to be fixed though.
-	 */
-	volatile struct dbdma_regs*	dma_regs;
-	struct dbdma_cmd*		dma_table_cpu;
-	dma_addr_t			dma_table_dma;
-	struct scatterlist*		sg_table;
-	int				sg_nents;
-	int				sg_dma_direction;
-#endif
-	
-} pmac_ide[MAX_HWIFS] __pmacdata;
-
-static int pmac_ide_count;
-
-enum {
-	controller_ohare,	/* OHare based */
-	controller_heathrow,	/* Heathrow/Paddington */
-	controller_kl_ata3,	/* KeyLargo ATA-3 */
-	controller_kl_ata4,	/* KeyLargo ATA-4 */
-	controller_kl_ata4_80	/* KeyLargo ATA-4 with 80 conductor cable */
-};
-
-/*
- * Extra registers, both 32-bit little-endian
- */
-#define IDE_TIMING_CONFIG	0x200
-#define IDE_INTERRUPT		0x300
-
-/*
- * Timing configuration register definitions
- */
-
-/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
-#define SYSCLK_TICKS(t)		(((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS)
-#define SYSCLK_TICKS_66(t)	(((t) + IDE_SYSCLK_66_NS - 1) / IDE_SYSCLK_66_NS)
-#define IDE_SYSCLK_NS		30	/* 33Mhz cell */
-#define IDE_SYSCLK_66_NS	15	/* 66Mhz cell */
-
-/* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on
- * 40 connector cable and to 4 on 80 connector one.
- * Clock unit is 15ns (66Mhz)
- * 
- * 3 Values can be programmed:
- *  - Write data setup, which appears to match the cycle time. They
- *    also call it DIOW setup.
- *  - Ready to pause time (from spec)
- *  - Address setup. That one is weird. I don't see where exactly
- *    it fits in UDMA cycles, I got it's name from an obscure piece
- *    of commented out code in Darwin. They leave it to 0, we do as
- *    well, despite a comment that would lead to think it has a
- *    min value of 45ns.
- * Apple also add 60ns to the write data setup (or cycle time ?) on
- * reads.
- */
-#define TR_66_UDMA_MASK			0xfff00000
-#define TR_66_UDMA_EN			0x00100000 /* Enable Ultra mode for DMA */
-#define TR_66_UDMA_ADDRSETUP_MASK	0xe0000000 /* Address setup */
-#define TR_66_UDMA_ADDRSETUP_SHIFT	29
-#define TR_66_UDMA_RDY2PAUS_MASK	0x1e000000 /* Ready 2 pause time */
-#define TR_66_UDMA_RDY2PAUS_SHIFT	25
-#define TR_66_UDMA_WRDATASETUP_MASK	0x01e00000 /* Write data setup time */
-#define TR_66_UDMA_WRDATASETUP_SHIFT	21
-#define TR_66_MDMA_MASK			0x000ffc00
-#define TR_66_MDMA_RECOVERY_MASK	0x000f8000
-#define TR_66_MDMA_RECOVERY_SHIFT	15
-#define TR_66_MDMA_ACCESS_MASK		0x00007c00
-#define TR_66_MDMA_ACCESS_SHIFT		10
-#define TR_66_PIO_MASK			0x000003ff
-#define TR_66_PIO_RECOVERY_MASK		0x000003e0
-#define TR_66_PIO_RECOVERY_SHIFT	5
-#define TR_66_PIO_ACCESS_MASK		0x0000001f
-#define TR_66_PIO_ACCESS_SHIFT		0
-
-/* 33Mhz cell, found in OHare, Heathrow (& Paddington) and KeyLargo
- * Can do pio & mdma modes, clock unit is 30ns (33Mhz)
- * 
- * The access time and recovery time can be programmed. Some older
- * Darwin code base limit OHare to 150ns cycle time. I decided to do
- * the same here fore safety against broken old hardware ;)
- * The HalfTick bit, when set, adds half a clock (15ns) to the access
- * time and removes one from recovery. It's not supported on KeyLargo
- * implementation afaik. The E bit appears to be set for PIO mode 0 and
- * is used to reach long timings used in this mode.
- */
-#define TR_33_MDMA_MASK			0x003ff800
-#define TR_33_MDMA_RECOVERY_MASK	0x001f0000
-#define TR_33_MDMA_RECOVERY_SHIFT	16
-#define TR_33_MDMA_ACCESS_MASK		0x0000f800
-#define TR_33_MDMA_ACCESS_SHIFT		11
-#define TR_33_MDMA_HALFTICK		0x00200000
-#define TR_33_PIO_MASK			0x000007ff
-#define TR_33_PIO_E			0x00000400
-#define TR_33_PIO_RECOVERY_MASK		0x000003e0
-#define TR_33_PIO_RECOVERY_SHIFT	5
-#define TR_33_PIO_ACCESS_MASK		0x0000001f
-#define TR_33_PIO_ACCESS_SHIFT		0
-
-/*
- * Interrupt register definitions
- */
-#define IDE_INTR_DMA			0x80000000
-#define IDE_INTR_DEVICE			0x40000000
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-
-/* Rounded Multiword DMA timings
- * 
- * I gave up finding a generic formula for all controller
- * types and instead, built tables based on timing values
- * used by Apple in Darwin's implementation.
- */
-struct mdma_timings_t {
-	int	accessTime;
-	int	recoveryTime;
-	int	cycleTime;
-};
-
-struct mdma_timings_t mdma_timings_33[] __pmacdata =
-{
-    { 240, 240, 480 },
-    { 180, 180, 360 },
-    { 135, 135, 270 },
-    { 120, 120, 240 },
-    { 105, 105, 210 },
-    {  90,  90, 180 },
-    {  75,  75, 150 },
-    {  75,  45, 120 },
-    {   0,   0,   0 }
-};
-
-struct mdma_timings_t mdma_timings_33k[] __pmacdata =
-{
-    { 240, 240, 480 },
-    { 180, 180, 360 },
-    { 150, 150, 300 },
-    { 120, 120, 240 },
-    {  90, 120, 210 },
-    {  90,  90, 180 },
-    {  90,  60, 150 },
-    {  90,  30, 120 },
-    {   0,   0,   0 }
-};
-
-struct mdma_timings_t mdma_timings_66[] __pmacdata =
-{
-    { 240, 240, 480 },
-    { 180, 180, 360 },
-    { 135, 135, 270 },
-    { 120, 120, 240 },
-    { 105, 105, 210 },
-    {  90,  90, 180 },
-    {  90,  75, 165 },
-    {  75,  45, 120 },
-    {   0,   0,   0 }
-};
-
-/* Ultra DMA timings (rounded) */
-struct {
-	int	addrSetup; /* ??? */
-	int	rdy2pause;
-	int	wrDataSetup;
-} udma_timings[] __pmacdata =
-{
-    {   0, 180,  120 },	/* Mode 0 */
-    {   0, 150,  90 },	/*      1 */
-    {   0, 120,  60 },	/*      2 */
-    {   0, 90,   45 },	/*      3 */
-    {   0, 90,   30 }	/*      4 */
-};
-
-/* allow up to 256 DBDMA commands per xfer */
-#define MAX_DCMDS		256
-
-/* Wait 2s for disk to answer on IDE bus after
- * enable operation.
- * NOTE: There is at least one case I know of a disk that needs about 10sec
- *       before anwering on the bus. I beleive we could add a kernel command
- *       line arg to override this delay for such cases.
- */
-#define IDE_WAKEUP_DELAY_MS	2000
-
-static void pmac_ide_setup_dma(struct device_node *np, int ix);
-static int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
-static int pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr);
-static int pmac_ide_tune_chipset(ide_drive_t *drive, byte speed);
-static void pmac_ide_tuneproc(ide_drive_t *drive, byte pio);
-static void pmac_ide_selectproc(ide_drive_t *drive);
-
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-
-#ifdef CONFIG_PMAC_PBOOK
-static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when);
-struct pmu_sleep_notifier idepmac_sleep_notifier = {
-	idepmac_notify_sleep, SLEEP_LEVEL_BLOCK,
-};
-#endif /* CONFIG_PMAC_PBOOK */
-
-static int pmac_ide_notify_reboot(struct notifier_block *, unsigned long, void *);
-static struct notifier_block pmac_ide_reboot_notifier = {
-	pmac_ide_notify_reboot,
-	NULL,
-	0
-};
-
-static int __pmac
-pmac_ide_find(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	ide_ioreg_t base;
-	int i;
-	
-	for (i=0; i<pmac_ide_count; i++) {
-		base = pmac_ide[i].regbase;
-		if (base && base == hwif->io_ports[0])
-			return i;
-	}
-	return -1;
-}
-
-/*
- * N.B. this can't be an initfunc, because the media-bay task can
- * call ide_[un]register at any time.
- */
-void __pmac
-pmac_ide_init_hwif_ports(hw_regs_t *hw,
-			      ide_ioreg_t data_port, ide_ioreg_t ctrl_port,
-			      int *irq)
-{
-	int i, ix;
-
-	if (data_port == 0)
-		return;
-
-	for (ix = 0; ix < MAX_HWIFS; ++ix)
-		if (data_port == pmac_ide[ix].regbase)
-			break;
-
-	if (ix >= MAX_HWIFS) {
-		/* Probably a PCI interface... */
-		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
-			hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET;
-		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-		return;
-	}
-
-	for (i = 0; i < 8; ++i)
-		hw->io_ports[i] = data_port + i * 0x10;
-	hw->io_ports[8] = data_port + 0x160;
-
-	if (irq != NULL)
-		*irq = pmac_ide[ix].irq;
-
-	ide_hwifs[ix].tuneproc = pmac_ide_tuneproc;
-	ide_hwifs[ix].selectproc = pmac_ide_selectproc;
-	ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset;
-	if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table_cpu) {
-		ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
-		if (!noautodma)
-			ide_hwifs[ix].autodma = 1;
-#endif
-	}
-}
-
-#if 0
-/* This one could be later extended to handle CMD IDE and be used by some kind
- * of /proc interface. I want to be able to get the devicetree path of a block
- * device for yaboot configuration
- */
-struct device_node*
-pmac_ide_get_devnode(ide_drive_t *drive)
-{
-	int i = pmac_ide_find(drive);
-	if (i < 0)
-		return NULL;
-	return pmac_ide[i].node;
-}
-#endif
-
-/* Setup timings for the selected drive (master/slave). I still need to verify if this
- * is enough, I beleive selectproc will be called whenever an IDE command is started,
- * but... */
-static void __pmac
-pmac_ide_selectproc(ide_drive_t *drive)
-{
-	int i = pmac_ide_find(drive);
-	if (i < 0)
-		return;
-
-	if (drive->select.b.unit & 0x01)
-		out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
-			pmac_ide[i].timings[1]);
-	else
-		out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
-			pmac_ide[i].timings[0]);
-	(void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));
-}
-
-
-/* Note: We don't use the generic routine here because for some
- * yet unexplained reasons, it cause some media-bay CD-ROMs to
- * lockup the bus. Strangely, this new version of the code is
- * almost identical to the generic one and works, I've not yet
- * managed to figure out what bit is causing the lockup in the
- * generic code, possibly a timing issue...
- * 
- * --BenH
- */
-static int __pmac
-wait_for_ready(ide_drive_t *drive)
-{
-	/* Timeout bumped for some powerbooks */
-	int timeout = 2000;
-	byte stat;
-
-	while(--timeout) {
-		stat = GET_STAT();
-		if(!(stat & BUSY_STAT)) {
-			if (drive->ready_stat == 0)
-				break;
-			else if((stat & drive->ready_stat) || (stat & ERR_STAT))
-				break;
-		}
-		mdelay(1);
-	}
-	if((stat & ERR_STAT) || timeout <= 0) {
-		if (stat & ERR_STAT) {
-			printk(KERN_ERR "ide_pmac: wait_for_ready, error status: %x\n", stat);
-		}
-		return 1;
-	}
-	return 0;
-}
-
-static int __pmac
-pmac_ide_do_setfeature(ide_drive_t *drive, byte command)
-{
-	int result = 1;
-	ide_hwif_t *hwif = HWIF(drive);
-	
-	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
-	udelay(1);
-	SELECT_DRIVE(HWIF(drive), drive);
-	SELECT_MASK(HWIF(drive), drive, 0);
-	udelay(1);
-	(void)GET_STAT(); /* Get rid of pending error state */
-	if(wait_for_ready(drive)) {
-		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n");
-		goto out;
-	}
-	udelay(10);
-	OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
-	OUT_BYTE(command, IDE_NSECTOR_REG);
-	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
-	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
-	udelay(1);
-	result = wait_for_ready(drive);
-	OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
-	if (result)
-		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n");
-out:
-	SELECT_MASK(HWIF(drive), drive, 0);
-	if (result == 0) {
-		drive->id->dma_ultra &= ~0xFF00;
-		drive->id->dma_mword &= ~0x0F00;
-		drive->id->dma_1word &= ~0x0F00;
-		switch(command) {
-			case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
-			case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
-			case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
-			case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
-			case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
-			case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
-			case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
-			case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
-			case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
-			case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
-			case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
-			case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
-			case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
-			case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
-			default: break;
-		}
-	}
-	enable_irq(hwif->irq);
-	return result;
-}
-
-/* Calculate PIO timings */
-static void __pmac
-pmac_ide_tuneproc(ide_drive_t *drive, byte pio)
-{
-	ide_pio_data_t d;
-	int i;
-	u32 *timings;
-	unsigned accessTicks, recTicks;
-	unsigned accessTime, recTime;
-	
-	i = pmac_ide_find(drive);
-	if (i < 0)
-		return;
-		
-	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
-	accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time);
-	if (drive->select.b.unit & 0x01)
-		timings = &pmac_ide[i].timings[1];
-	else
-		timings = &pmac_ide[i].timings[0];
-
-	recTime = d.cycle_time - ide_pio_timings[pio].active_time
-			- ide_pio_timings[pio].setup_time;
-	recTime = max(recTime, 150U);
-	accessTime = ide_pio_timings[pio].active_time;
-	accessTime = max(accessTime, 150U);
-	if (pmac_ide[i].kind == controller_kl_ata4 ||
-		pmac_ide[i].kind == controller_kl_ata4_80) {
-		/* 66Mhz cell */
-		accessTicks = SYSCLK_TICKS_66(accessTime);
-		accessTicks = min(accessTicks, 0x1fU);
-		recTicks = SYSCLK_TICKS_66(recTime);
-		recTicks = min(recTicks, 0x1fU);
-		*timings = ((*timings) & ~TR_66_PIO_MASK) |
-				(accessTicks << TR_66_PIO_ACCESS_SHIFT) |
-				(recTicks << TR_66_PIO_RECOVERY_SHIFT);
-	} else {
-		/* 33Mhz cell */
-		int ebit = 0;
-		accessTicks = SYSCLK_TICKS(accessTime);
-		accessTicks = min(accessTicks, 0x1fU);
-		accessTicks = max(accessTicks, 4U);
-		recTicks = SYSCLK_TICKS(recTime);
-		recTicks = min(recTicks, 0x1fU);
-		recTicks = max(recTicks, 5U) - 4;
-		if (recTicks > 9) {
-			recTicks--; /* guess, but it's only for PIO0, so... */
-			ebit = 1;
-		}
-		*timings = ((*timings) & ~TR_33_PIO_MASK) |
-				(accessTicks << TR_33_PIO_ACCESS_SHIFT) |
-				(recTicks << TR_33_PIO_RECOVERY_SHIFT);
-		if (ebit)
-			*timings |= TR_33_PIO_E;
-	}
-
-#ifdef IDE_PMAC_DEBUG
-	printk(KERN_ERR "ide_pmac: Set PIO timing for mode %d, reg: 0x%08x\n",
-		pio,  *timings);
-#endif	
-		
-	if (drive->select.all == IN_BYTE(IDE_SELECT_REG))
-		pmac_ide_selectproc(drive);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-static int __pmac
-set_timings_udma(u32 *timings, byte speed)
-{
-	unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks;
-
-	rdyToPauseTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].rdy2pause);
-	wrDataSetupTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].wrDataSetup);
-	addrTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].addrSetup);
-
-	*timings = ((*timings) & ~(TR_66_UDMA_MASK | TR_66_MDMA_MASK)) |
-			(wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) | 
-			(rdyToPauseTicks << TR_66_UDMA_RDY2PAUS_SHIFT) |
-			(addrTicks <<TR_66_UDMA_ADDRSETUP_SHIFT) |
-			TR_66_UDMA_EN;
-#ifdef IDE_PMAC_DEBUG
-	printk(KERN_ERR "ide_pmac: Set UDMA timing for mode %d, reg: 0x%08x\n",
-		speed & 0xf,  *timings);
-#endif	
-
-	return 0;
-}
-
-static int __pmac
-set_timings_mdma(int intf_type, u32 *timings, byte speed, int drive_cycle_time)
-{
-	int cycleTime, accessTime, recTime;
-	unsigned accessTicks, recTicks;
-	struct mdma_timings_t* tm;
-	int i;
-
-	/* Get default cycle time for mode */
-	switch(speed & 0xf) {
-		case 0: cycleTime = 480; break;
-		case 1: cycleTime = 150; break;
-		case 2: cycleTime = 120; break;
-		default:
-			return -1;
-	}
-	/* Adjust for drive */
-	if (drive_cycle_time && drive_cycle_time > cycleTime)
-		cycleTime = drive_cycle_time;
-	/* OHare limits according to some old Apple sources */	
-	if ((intf_type == controller_ohare) && (cycleTime < 150))
-		cycleTime = 150;
-	/* Get the proper timing array for this controller */
-	switch(intf_type) {
-		case controller_kl_ata4:
-		case controller_kl_ata4_80:
-			tm = mdma_timings_66;
-			break;
-		case controller_kl_ata3:
-			tm = mdma_timings_33k;
-			break;
-		default:
-			tm = mdma_timings_33;
-			break;
-	}
-	/* Lookup matching access & recovery times */
-	i = -1;
-	for (;;) {
-		if (tm[i+1].cycleTime < cycleTime)
-			break;
-		i++;
-	}
-	if (i < 0)
-		return -1;
-	cycleTime = tm[i].cycleTime;
-	accessTime = tm[i].accessTime;
-	recTime = tm[i].recoveryTime;
-
-#ifdef IDE_PMAC_DEBUG
-	printk(KERN_ERR "ide_pmac: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n",
-		cycleTime, accessTime, recTime);
-#endif	
-	if (intf_type == controller_kl_ata4 || intf_type == controller_kl_ata4_80) {
-		/* 66Mhz cell */
-		accessTicks = SYSCLK_TICKS_66(accessTime);
-		accessTicks = min(accessTicks, 0x1fU);
-		accessTicks = max(accessTicks, 0x1U);
-		recTicks = SYSCLK_TICKS_66(recTime);
-		recTicks = min(recTicks, 0x1fU);
-		recTicks = max(recTicks, 0x3U);
-		/* Clear out mdma bits and disable udma */
-		*timings = ((*timings) & ~(TR_66_MDMA_MASK | TR_66_UDMA_MASK)) |
-			(accessTicks << TR_66_MDMA_ACCESS_SHIFT) |
-			(recTicks << TR_66_MDMA_RECOVERY_SHIFT);
-	} else if (intf_type == controller_kl_ata3) {
-		/* 33Mhz cell on KeyLargo */
-		accessTicks = SYSCLK_TICKS(accessTime);
-		accessTicks = max(accessTicks, 1U);
-		accessTicks = min(accessTicks, 0x1fU);
-		accessTime = accessTicks * IDE_SYSCLK_NS;
-		recTicks = SYSCLK_TICKS(recTime);
-		recTicks = max(recTicks, 1U);
-		recTicks = min(recTicks, 0x1fU);
-		*timings = ((*timings) & ~TR_33_MDMA_MASK) |
-				(accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
-				(recTicks << TR_33_MDMA_RECOVERY_SHIFT);
-	} else {
-		/* 33Mhz cell on others */
-		int halfTick = 0;
-		int origAccessTime = accessTime;
-		int origRecTime = recTime;
-		
-		accessTicks = SYSCLK_TICKS(accessTime);
-		accessTicks = max(accessTicks, 1U);
-		accessTicks = min(accessTicks, 0x1fU);
-		accessTime = accessTicks * IDE_SYSCLK_NS;
-		recTicks = SYSCLK_TICKS(recTime);
-		recTicks = max(recTicks, 2U) - 1;
-		recTicks = min(recTicks, 0x1fU);
-		recTime = (recTicks + 1) * IDE_SYSCLK_NS;
-		if ((accessTicks > 1) &&
-		    ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
-		    ((recTime - IDE_SYSCLK_NS/2) >= origRecTime)) {
-            		halfTick = 1;
-			accessTicks--;
-		}
-		*timings = ((*timings) & ~TR_33_MDMA_MASK) |
-				(accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
-				(recTicks << TR_33_MDMA_RECOVERY_SHIFT);
-		if (halfTick)
-			*timings |= TR_33_MDMA_HALFTICK;
-	}
-#ifdef IDE_PMAC_DEBUG
-	printk(KERN_ERR "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",
-		speed & 0xf,  *timings);
-#endif	
-	return 0;
-}
-#endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */
-
-/* You may notice we don't use this function on normal operation,
- * our, normal mdma function is supposed to be more precise
- */
-static int __pmac
-pmac_ide_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	int intf		= pmac_ide_find(drive);
-	int unit		= (drive->select.b.unit & 0x01);
-	int ret			= 0;
-	u32 *timings;
-
-	if (intf < 0)
-		return 1;
-		
-	timings = &pmac_ide[intf].timings[unit];
-	
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-			if (pmac_ide[intf].kind != controller_kl_ata4_80)
-				return 1;		
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-			if (pmac_ide[intf].kind != controller_kl_ata4 &&
-				pmac_ide[intf].kind != controller_kl_ata4_80)
-				return 1;		
-			ret = set_timings_udma(timings, speed);
-			break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_MW_DMA_0:
-			ret = set_timings_mdma(pmac_ide[intf].kind, timings, speed, 0);
-			break;
-		case XFER_SW_DMA_2:
-		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0:
-			return 1;
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-			pmac_ide_tuneproc(drive, speed & 0x07);
-			break;
-		default:
-			ret = 1;
-	}
-	if (ret)
-		return ret;
-
-	ret = pmac_ide_do_setfeature(drive, speed);
-	if (ret)
-		return ret;
-		
-	pmac_ide_selectproc(drive);	
-	drive->current_speed = speed;
-
-	return 0;
-}
-
-static void __pmac
-sanitize_timings(int i)
-{
-	unsigned value;
-	
-	switch(pmac_ide[i].kind) {
-		case controller_kl_ata4:
-		case controller_kl_ata4_80:
-			value = 0x0008438c;
-			break;
-		case controller_kl_ata3:
-			value = 0x00084526;
-			break;
-		case controller_heathrow:
-		case controller_ohare:
-		default:
-			value = 0x00074526;
-			break;
-	}
-	pmac_ide[i].timings[0] = pmac_ide[i].timings[1] = value;
-}
-
-ide_ioreg_t __pmac
-pmac_ide_get_base(int index)
-{
-	return pmac_ide[index].regbase;
-}
-
-int __pmac
-pmac_ide_check_base(ide_ioreg_t base)
-{
-	int ix;
-	
- 	for (ix = 0; ix < MAX_HWIFS; ++ix)
-		if (base == pmac_ide[ix].regbase)
-			return ix;
-	return -1;
-}
-
-int __pmac
-pmac_ide_get_irq(ide_ioreg_t base)
-{
-	int ix;
-
-	for (ix = 0; ix < MAX_HWIFS; ++ix)
-		if (base == pmac_ide[ix].regbase)
-			return pmac_ide[ix].irq;
-	return 0;
-}
-
-static int ide_majors[]  __pmacdata = { 3, 22, 33, 34, 56, 57 };
-
-kdev_t __init
-pmac_find_ide_boot(char *bootdevice, int n)
-{
-	int i;
-	
-	/*
-	 * Look through the list of IDE interfaces for this one.
-	 */
-	for (i = 0; i < pmac_ide_count; ++i) {
-		char *name;
-		if (!pmac_ide[i].node || !pmac_ide[i].node->full_name)
-			continue;
-		name = pmac_ide[i].node->full_name;
-		if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) {
-			/* XXX should cope with the 2nd drive as well... */
-			return MKDEV(ide_majors[i], 0);
-		}
-	}
-
-	return 0;
-}
-
-void __init
-pmac_ide_probe(void)
-{
-	struct device_node *np;
-	int i;
-	struct device_node *atas;
-	struct device_node *p, **pp, *removables, **rp;
-	unsigned long base;
-	int irq, big_delay;
-	ide_hwif_t *hwif;
-
-	if (_machine != _MACH_Pmac)
-		return;
-	pp = &atas;
-	rp = &removables;
-	p = find_devices("ATA");
-	if (p == NULL)
-		p = find_devices("IDE");
-	if (p == NULL)
-		p = find_type_devices("ide");
-	if (p == NULL)
-		p = find_type_devices("ata");
-	/* Move removable devices such as the media-bay CDROM
-	   on the PB3400 to the end of the list. */
-	for (; p != NULL; p = p->next) {
-		if (p->parent && p->parent->type
-		    && strcasecmp(p->parent->type, "media-bay") == 0) {
-			*rp = p;
-			rp = &p->next;
-		} else {
-			*pp = p;
-			pp = &p->next;
-		}
-	}
-	*rp = NULL;
-	*pp = removables;
-	big_delay = 0;
-
-	for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) {
-		struct device_node *tp;
-		struct pmac_ide_hwif* pmhw;
-		int *bidp;
-		int in_bay = 0;
-		u8 pbus, pid;
-		struct pci_dev *pdev = NULL;
-
-		/*
-		 * If this node is not under a mac-io or dbdma node,
-		 * leave it to the generic PCI driver.
-		 */
-		for (tp = np->parent; tp != 0; tp = tp->parent)
-			if (tp->type && (strcmp(tp->type, "mac-io") == 0
-					 || strcmp(tp->type, "dbdma") == 0))
-				break;
-		if (tp == 0)
-			continue;
-
-		if (np->n_addrs == 0) {
-			printk(KERN_WARNING "ide: no address for device %s\n",
-			       np->full_name);
-			continue;
-		}
-
-		/* We need to find the pci_dev of the mac-io holding the
-		 * IDE interface
-		 */
-		if (pci_device_from_OF_node(tp, &pbus, &pid) == 0)
-			pdev = pci_find_slot(pbus, pid);
-		if (pdev == NULL)
-			printk(KERN_WARNING "ide: no PCI host for device %s, DMA disabled\n",
-			       np->full_name);
-
-		/*
-		 * If this slot is taken (e.g. by ide-pci.c) try the next one.
-		 */
-		while (i < MAX_HWIFS
-		       && ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0)
-			++i;
-		if (i >= MAX_HWIFS)
-			break;
-		pmhw = &pmac_ide[i];
-
-		/*
-		 * Some older OFs have bogus sizes, causing request_OF_resource
-		 * to fail. We fix them up here
-		 */
-		if (np->addrs[0].size > 0x1000)
-			np->addrs[0].size = 0x1000;
-		if (np->n_addrs > 1 && np->addrs[1].size > 0x100)
-			np->addrs[1].size = 0x100;
-
-		if (request_OF_resource(np, 0, "  (mac-io IDE IO)") == NULL) {
-			printk(KERN_ERR "ide-pmac(%s): can't request IO resource !\n", np->name);
-			continue;
-		}
-
-		base = (unsigned long) ioremap(np->addrs[0].address, 0x400) - _IO_BASE;
-
-		/* XXX This is bogus. Should be fixed in the registry by checking
-		   the kind of host interrupt controller, a bit like gatwick
-		   fixes in irq.c
-		 */
-		if (np->n_intrs == 0) {
-			printk(KERN_WARNING "ide: no intrs for device %s, using 13\n",
-			       np->full_name);
-			irq = 13;
-		} else {
-			irq = np->intrs[0].line;
-		}
-		pmhw->regbase = base;
-		pmhw->irq = irq;
-		pmhw->node = np;
-		if (device_is_compatible(np, "keylargo-ata")) {
-			if (strcmp(np->name, "ata-4") == 0)
-				pmhw->kind = controller_kl_ata4;
-			else
-				pmhw->kind = controller_kl_ata3;
-		} else if (device_is_compatible(np, "heathrow-ata"))
-			pmhw->kind = controller_heathrow;
-		else
-			pmhw->kind = controller_ohare;
-
-		bidp = (int *)get_property(np, "AAPL,bus-id", NULL);
-		pmhw->aapl_bus_id =  bidp ? *bidp : 0;
-
-		if (pmhw->kind == controller_kl_ata4) {
-			char* cable = get_property(np, "cable-type", NULL);
-			if (cable && !strncmp(cable, "80-", 3))
-				pmhw->kind = controller_kl_ata4_80;
-		}
-
-		/* Make sure we have sane timings */
-		sanitize_timings(i);
-
-		if (np->parent && np->parent->name
-		    && strcasecmp(np->parent->name, "media-bay") == 0) {
-#ifdef CONFIG_PMAC_PBOOK
-			media_bay_set_ide_infos(np->parent,base,irq,i);
-#endif /* CONFIG_PMAC_PBOOK */
-			in_bay = 1;
-			if (!bidp)
-				pmhw->aapl_bus_id = 1;
-		} else if (pmhw->kind == controller_ohare) {
-			/* The code below is having trouble on some ohare machines
-			 * (timing related ?). Until I can put my hand on one of these
-			 * units, I keep the old way
-			 */
-			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1);
-		} else {
- 			/* This is necessary to enable IDE when net-booting */
-			printk(KERN_INFO "pmac_ide: enabling IDE bus ID %d\n",
-				pmhw->aapl_bus_id);
-			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmhw->aapl_bus_id, 1);
-			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmhw->aapl_bus_id, 1);
-			mdelay(10);
-			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmhw->aapl_bus_id, 0);
-			big_delay = 1;
-		}
-
-		hwif = &ide_hwifs[i];
-		pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq);
-		memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-		hwif->chipset = ide_pmac;
-		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay;
-		hwif->udma_four = (pmhw->kind == controller_kl_ata4_80);
-		hwif->pci_dev = pdev;
-		hwif->drives[0].unmask = 1;
-		hwif->drives[1].unmask = 1;
-#ifdef CONFIG_PMAC_PBOOK
-		if (in_bay && check_media_bay_by_base(base, MB_CD) == 0)
-			hwif->noprobe = 0;
-#endif /* CONFIG_PMAC_PBOOK */
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-		if (np->n_addrs >= 2) {
-			/* has a DBDMA controller channel */
-			pmac_ide_setup_dma(np, i);
-		}
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-
-		++i;
-	}
-	pmac_ide_count = i;
-	if (big_delay)
-		mdelay(IDE_WAKEUP_DELAY_MS);
-
-#ifdef CONFIG_PMAC_PBOOK
-	pmu_register_sleep_notifier(&idepmac_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
-	register_reboot_notifier(&pmac_ide_reboot_notifier);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-
-static void __init 
-pmac_ide_setup_dma(struct device_node *np, int ix)
-{
-	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
-
-	if (request_OF_resource(np, 1, " (mac-io IDE DMA)") == NULL) {
-		printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n", np->name);
-		return;
-	}
-
-	pmif->dma_regs =
-		(volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200);
-
-	/*
-	 * Allocate space for the DBDMA commands.
-	 * The +2 is +1 for the stop command and +1 to allow for
-	 * aligning the start address to a multiple of 16 bytes.
-	 */
-	pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent(
-		ide_hwifs[ix].pci_dev,
-		(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
-		&pmif->dma_table_dma);
-	if (pmif->dma_table_cpu == NULL) {
-		printk(KERN_ERR "%s: unable to allocate DMA command list\n",
-		       ide_hwifs[ix].name);
-		return;
-	}
-
-	pmif->sg_table = kmalloc(sizeof(struct scatterlist) * MAX_DCMDS,
-				 GFP_KERNEL);
-	if (pmif->sg_table == NULL) {
-		pci_free_consistent(	ide_hwifs[ix].pci_dev,
-					(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
-				    	pmif->dma_table_cpu, pmif->dma_table_dma);
-		return;
-	}
-	ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
-	if (!noautodma)
-		ide_hwifs[ix].autodma = 1;
-#endif
-}
-
-static int
-pmac_ide_build_sglist (int ix, struct request *rq)
-{
-	ide_hwif_t *hwif = &ide_hwifs[ix];
-	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
-	struct buffer_head *bh;
-	struct scatterlist *sg = pmif->sg_table;
-	unsigned long lastdataend = ~0UL;
-	int nents = 0;
-
-	if (hwif->sg_dma_active)
-		BUG();
-
-	if (rq->cmd == READ)
-		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-	else
-		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
-
-	bh = rq->bh;
-	do {
-		struct scatterlist *sge;
-		unsigned int size = bh->b_size;
-
-		/* continue segment from before? */
-		if (bh_phys(bh) == lastdataend) {
-			sg[nents-1].length += size;
-			lastdataend += size;
-			continue;
-		}
-
-		/* start new segment */
-		if (nents >= MAX_DCMDS)
-			return 0;
-
-		sge = &sg[nents];
-		memset(sge, 0, sizeof(*sge));
-
-		if (bh->b_page) {
-			sge->page = bh->b_page;
-			sge->offset = bh_offset(bh);
-		} else {
-			if ((unsigned long)bh->b_data < PAGE_SIZE)
-				BUG();
-			sge->address = bh->b_data;
-		}
-		sge->length = size;
-		lastdataend = bh_phys(bh) + size;
-		nents++;
-	} while ((bh = bh->b_reqnext) != NULL);
-
-	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
-}
-
-static int
-pmac_ide_raw_build_sglist (int ix, struct request *rq)
-{
-	ide_hwif_t *hwif = &ide_hwifs[ix];
-	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
-	struct scatterlist *sg = hwif->sg_table;
-	int nents = 0;
-	ide_task_t *args = rq->special;
-	unsigned char *virt_addr = rq->buffer;
-	int sector_count = rq->nr_sectors;
-
-//	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA) ||
-//	    (args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA_EXT))
-	if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
-		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
-	else
-		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-	
-	if (sector_count > 128) {
-		memset(&sg[nents], 0, sizeof(*sg));
-		sg[nents].address = virt_addr;
-		sg[nents].length = 128  * SECTOR_SIZE;
-		nents++;
-		virt_addr = virt_addr + (128 * SECTOR_SIZE);
-		sector_count -= 128;
-	}
-	memset(&sg[nents], 0, sizeof(*sg));
-	sg[nents].address = virt_addr;
-	sg[nents].length =  sector_count  * SECTOR_SIZE;
-	nents++;
-   
-	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
-}
-
-/*
- * pmac_ide_build_dmatable builds the DBDMA command list
- * for a transfer and sets the DBDMA channel to point to it.
- */
-static int
-pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr)
-{
-	struct dbdma_cmd *table;
-	int i, count = 0;
-	struct request *rq = HWGROUP(drive)->rq;
-	volatile struct dbdma_regs *dma = pmac_ide[ix].dma_regs;
-	struct scatterlist *sg;
-
-	/* DMA table is already aligned */
-	table = (struct dbdma_cmd *) pmac_ide[ix].dma_table_cpu;
-
-	/* Make sure DMA controller is stopped (necessary ?) */
-	out_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16);
-	while (in_le32(&dma->status) & RUN)
-		udelay(1);
-
-	/* Build sglist */
-	if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE)
-		pmac_ide[ix].sg_nents = i = pmac_ide_raw_build_sglist(ix, rq);
-	else
-		pmac_ide[ix].sg_nents = i = pmac_ide_build_sglist(ix, rq);
-	if (!i)
-		return 0;
-
-	/* Build DBDMA commands list */
-	sg = pmac_ide[ix].sg_table;
-	while (i) {
-		u32 cur_addr;
-		u32 cur_len;
-
-		cur_addr = sg_dma_address(sg);
-		cur_len = sg_dma_len(sg);
-
-		while (cur_len) {
-			unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
-
-			if (++count >= MAX_DCMDS) {
-				printk(KERN_WARNING "%s: DMA table too small\n",
-				       drive->name);
-				return 0; /* revert to PIO for this request */
-			}
-			st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE);
-			st_le16(&table->req_count, tc);
-			st_le32(&table->phy_addr, cur_addr);
-			table->cmd_dep = 0;
-			table->xfer_status = 0;
-			table->res_count = 0;
-			cur_addr += tc;
-			cur_len -= tc;
-			++table;
-		}
-		sg++;
-		i--;
-	}
-
-	/* convert the last command to an input/output last command */
-	if (count)
-		st_le16(&table[-1].command, wr? OUTPUT_LAST: INPUT_LAST);
-	else
-		printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name);
-
-	/* add the stop command to the end of the list */
-	memset(table, 0, sizeof(struct dbdma_cmd));
-	out_le16(&table->command, DBDMA_STOP);
-
-	out_le32(&dma->cmdptr, pmac_ide[ix].dma_table_dma);
-	return 1;
-}
-
-/* Teardown mappings after DMA has completed.  */
-static void
-pmac_ide_destroy_dmatable (ide_drive_t *drive, int ix)
-{
-	struct pci_dev *dev = HWIF(drive)->pci_dev;
-	struct scatterlist *sg = pmac_ide[ix].sg_table;
-	int nents = pmac_ide[ix].sg_nents;
-
-	if (nents) {
-		pci_unmap_sg(dev, sg, nents, pmac_ide[ix].sg_dma_direction);
-		pmac_ide[ix].sg_nents = 0;
-	}
-}
-
-static __inline__ unsigned char
-dma_bits_to_command(unsigned char bits)
-{
-	if(bits & 0x04)
-		return XFER_MW_DMA_2;
-	if(bits & 0x02)
-		return XFER_MW_DMA_1;
-	if(bits & 0x01)
-		return XFER_MW_DMA_0;
-	return 0;
-}
-
-static __inline__ unsigned char
-udma_bits_to_command(unsigned char bits, int high_speed)
-{
-	if (high_speed) {
-		if(bits & 0x10)
-			return XFER_UDMA_4;
-		if(bits & 0x08)
-			return XFER_UDMA_3;
-	}
-	if(bits & 0x04)
-		return XFER_UDMA_2;
-	if(bits & 0x02)
-		return XFER_UDMA_1;
-	if(bits & 0x01)
-		return XFER_UDMA_0;
-	return 0;
-}
-
-/* Calculate MultiWord DMA timings */
-static int __pmac
-pmac_ide_mdma_enable(ide_drive_t *drive, int idx)
-{
-	byte bits = drive->id->dma_mword & 0x07;
-	byte feature = dma_bits_to_command(bits);
-	u32 *timings;
-	int drive_cycle_time;
-	struct hd_driveid *id = drive->id;
-	int ret;
-
-	/* Set feature on drive */
-    	printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf);
-	ret = pmac_ide_do_setfeature(drive, feature);
-	if (ret) {
-	    	printk(KERN_WARNING "%s: Failed !\n", drive->name);
-	    	return 0;
-	}
-
-	if (!drive->init_speed)
-		drive->init_speed = feature;
-	
-	/* which drive is it ? */
-	if (drive->select.b.unit & 0x01)
-		timings = &pmac_ide[idx].timings[1];
-	else
-		timings = &pmac_ide[idx].timings[0];
-
-	/* Check if drive provide explicit cycle time */
-	if ((id->field_valid & 2) && (id->eide_dma_time))
-		drive_cycle_time = id->eide_dma_time;
-	else
-		drive_cycle_time = 0;
-
-	/* Calculate controller timings */
-	set_timings_mdma(pmac_ide[idx].kind, timings, feature, drive_cycle_time);
-
-	drive->current_speed = feature;	
-	return 1;
-}
-
-/* Calculate Ultra DMA timings */
-static int __pmac
-pmac_ide_udma_enable(ide_drive_t *drive, int idx, int high_speed)
-{
-	byte bits = drive->id->dma_ultra & 0x1f;
-	byte feature = udma_bits_to_command(bits, high_speed);
-	u32 *timings;
-	int ret;
-
-	/* Set feature on drive */
-    	printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf);
-	ret = pmac_ide_do_setfeature(drive, feature);
-	if (ret) {
-		printk(KERN_WARNING "%s: Failed !\n", drive->name);
-		return 0;
-	}
-
-	if (!drive->init_speed)
-		drive->init_speed = feature;
-
-	/* which drive is it ? */
-	if (drive->select.b.unit & 0x01)
-		timings = &pmac_ide[idx].timings[1];
-	else
-		timings = &pmac_ide[idx].timings[0];
-
-	set_timings_udma(timings, feature);
-
-	drive->current_speed = feature;	
-	return 1;
-}
-
-static int __pmac
-pmac_ide_check_dma(ide_drive_t *drive)
-{
-	int ata4, udma, idx;
-	struct hd_driveid *id = drive->id;
-	int enable = 1;
-
-	drive->using_dma = 0;
-	
-	idx = pmac_ide_find(drive);
-	if (idx < 0)
-		return 0;
-		
-	if (drive->media == ide_floppy)
-		enable = 0;
-	if (((id->capability & 1) == 0) && !check_drive_lists(drive, GOOD_DMA_DRIVE))
-		enable = 0;
-	if (check_drive_lists(drive, BAD_DMA_DRIVE))
-		enable = 0;
-
-	udma = 0;
-	ata4 = (pmac_ide[idx].kind == controller_kl_ata4 ||
-		pmac_ide[idx].kind == controller_kl_ata4_80);
-			
-	if(enable) {
-		if (ata4 && (drive->media == ide_disk) &&
-		    (id->field_valid & 0x0004) && (id->dma_ultra & 0x1f)) {
-			/* UltraDMA modes. */
-			drive->using_dma = pmac_ide_udma_enable(drive, idx,
-				pmac_ide[idx].kind == controller_kl_ata4_80);
-		}
-		if (!drive->using_dma && (id->dma_mword & 0x0007)) {
-			/* Normal MultiWord DMA modes. */
-			drive->using_dma = pmac_ide_mdma_enable(drive, idx);
-		}
-		OUT_BYTE(0, IDE_CONTROL_REG);
-		/* Apply settings to controller */
-		pmac_ide_selectproc(drive);
-	}
-	return 0;
-}
-
-static inline void pmac_ide_toggle_bounce(ide_drive_t *drive, int on)
-{
-	dma64_addr_t addr = BLK_BOUNCE_HIGH;
-
-	if (HWIF(drive)->no_highio || HWIF(drive)->pci_dev == NULL)
-		return;
-
-	if (on && drive->media == ide_disk) {
-		if (!PCI_DMA_BUS_IS_PHYS)
-			addr = BLK_BOUNCE_ANY;
-		else
-			addr = HWIF(drive)->pci_dev->dma_mask;
-	}
-
-	blk_queue_bounce_limit(&drive->queue, addr);
-}
-
-static int __pmac
-pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	int ix, dstat;
-	volatile struct dbdma_regs *dma;
-	byte unit = (drive->select.b.unit & 0x01);
-	byte ata4;
-	int reading = 0;
-
-	/* Can we stuff a pointer to our intf structure in config_data
-	 * or select_data in hwif ?
-	 */
-	ix = pmac_ide_find(drive);
-	if (ix < 0)
-		return 0;		
-	dma = pmac_ide[ix].dma_regs;
-	ata4 = (pmac_ide[ix].kind == controller_kl_ata4 ||
-		pmac_ide[ix].kind == controller_kl_ata4_80);
-	
-	switch (func) {
-	case ide_dma_off:
-		printk(KERN_INFO "%s: DMA disabled\n", drive->name);
-	case ide_dma_off_quietly:
-		drive->using_dma = 0;
-		pmac_ide_toggle_bounce(drive, 0);
-		break;
-	case ide_dma_on:
-	case ide_dma_check:
-		pmac_ide_check_dma(drive);
-		if (drive->using_dma)
-			pmac_ide_toggle_bounce(drive, 1);
-		break;
-	case ide_dma_read:
-		reading = 1;
-	case ide_dma_write:
-		SELECT_READ_WRITE(HWIF(drive),drive,func);
-		if (!pmac_ide_build_dmatable(drive, ix, !reading))
-			return 1;
-		/* Apple adds 60ns to wrDataSetup on reads */
-		if (ata4 && (pmac_ide[ix].timings[unit] & TR_66_UDMA_EN)) {
-			out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
-				pmac_ide[ix].timings[unit] + 
-				(reading ? 0x00800000UL : 0));
-			(void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));
-		}
-		drive->waiting_for_dma = 1;
-		if (drive->media != ide_disk)
-			return 0;
-		ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
-		if ((HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) &&
-		    (drive->addressing == 1)) {
-			ide_task_t *args = HWGROUP(drive)->rq->special;
-			OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
-		} else if (drive->addressing) {
-			OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
-		} else {
-			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-		}
-	case ide_dma_begin:
-		out_le32(&dma->control, (RUN << 16) | RUN);
-		/* Make sure it gets to the controller right now */
-		(void)in_le32(&dma->control);
-		break;
-	case ide_dma_end: /* returns 1 on error, 0 otherwise */
-		drive->waiting_for_dma = 0;
-		dstat = in_le32(&dma->status);
-		out_le32(&dma->control, ((RUN|WAKE|DEAD) << 16));
-		pmac_ide_destroy_dmatable(drive, ix);
-		/* verify good dma status */
-		return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
-	case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
-		/* We have to things to deal with here:
-		 * 
-		 * - The dbdma won't stop if the command was started
-		 * but completed with an error without transfering all
-		 * datas. This happens when bad blocks are met during
-		 * a multi-block transfer.
-		 * 
-		 * - The dbdma fifo hasn't yet finished flushing to
-		 * to system memory when the disk interrupt occurs.
-		 * 
-		 * The trick here is to increment drive->waiting_for_dma,
-		 * and return as if no interrupt occured. If the counter
-		 * reach a certain timeout value, we then return 1. If
-		 * we really got the interrupt, it will happen right away
-		 * again.
-		 * Apple's solution here may be more elegant. They issue
-		 * a DMA channel interrupt (a separate irq line) via a DBDMA
-		 * NOP command just before the STOP, and wait for both the
-		 * disk and DBDMA interrupts to have completed.
-		 */
-		 
-		/* If ACTIVE is cleared, the STOP command have passed and
-		 * transfer is complete.
-		 */
-		if (!(in_le32(&dma->status) & ACTIVE))
-			return 1;
-		if (!drive->waiting_for_dma)
-			printk(KERN_WARNING "ide%d, ide_dma_test_irq \
-				called while not waiting\n", ix);
-
-		/* If dbdma didn't execute the STOP command yet, the
-		 * active bit is still set */
-		drive->waiting_for_dma++;
-		if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
-			printk(KERN_WARNING "ide%d, timeout waiting \
-				for dbdma command stop\n", ix);
-			return 1;
-		}
-		udelay(1);
-		return 0;
-
-		/* Let's implement tose just in case someone wants them */
-	case ide_dma_bad_drive:
-	case ide_dma_good_drive:
-		return check_drive_lists(drive, (func == ide_dma_good_drive));
-	case ide_dma_verbose:
-		return report_drive_dmaing(drive);
-	case ide_dma_retune:
-	case ide_dma_lostirq:
-	case ide_dma_timeout:
-		printk(KERN_WARNING "ide_pmac_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func),  func);
-		return 1;
-	default:
-		printk(KERN_WARNING "ide_pmac_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func);
-		return 1;
-	}
-	return 0;
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-
-static void __pmac
-idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base)
-{
-	int j;
-	
-	/* FIXME: We only handle the master IDE disk, we shoud
-	 *        try to fix CD-ROMs here
-	 */
-	switch (drive->media) {
-	case ide_disk:
-		/* Spin down the drive */
-		outb(drive->select.all, base+0x60);
-		(void)inb(base+0x60);
-		udelay(100);
-		outb(0x0, base+0x30);
-		outb(0x0, base+0x20);
-		outb(0x0, base+0x40);
-		outb(0x0, base+0x50);
-		outb(0xe0, base+0x70);
-		outb(0x2, base+0x160);   
-		for (j = 0; j < 10; j++) {
-			int status;
-			mdelay(100);
-			status = inb(base+0x70);
-			if (!(status & BUSY_STAT) && (status & DRQ_STAT))
-				break;
-		}
-		break;
-	case ide_cdrom:
-		// todo
-		break;
-	case ide_floppy:
-		// todo
-		break;
-	}
-}
-
-#ifdef CONFIG_PMAC_PBOOK
-static void __pmac
-idepmac_wake_device(ide_drive_t *drive, int used_dma)
-{
-	/* We force the IDE subdriver to check for a media change
-	 * This must be done first or we may lost the condition
-	 *
-	 * Problem: This can schedule. I moved the block device
-	 * wakeup almost late by priority because of that.
-	 */
-	if (DRIVER(drive) && DRIVER(drive)->media_change)
-		DRIVER(drive)->media_change(drive);
-
-	/* We kick the VFS too (see fix in ide.c revalidate) */
-	check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS));
-	
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-	/* We re-enable DMA on the drive if it was active. */
-	/* This doesn't work with the CD-ROM in the media-bay, probably
-	 * because of a pending unit attention. The problem if that if I
-	 * clear the error, the filesystem dies.
-	 */
-	if (used_dma && !ide_spin_wait_hwgroup(drive)) {
-		/* Lock HW group */
-		HWGROUP(drive)->busy = 1;
-		pmac_ide_check_dma(drive);
-		HWGROUP(drive)->busy = 0;
-		if (!list_empty(&drive->queue.queue_head))
-			ide_do_request(HWGROUP(drive), 0);
-		spin_unlock_irq(&io_request_lock);
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-}
-
-static void __pmac
-idepmac_sleep_interface(int i, unsigned base, int mediabay)
-{
-	struct device_node* np = pmac_ide[i].node;
-
-	/* We clear the timings */
-	pmac_ide[i].timings[0] = 0;
-	pmac_ide[i].timings[1] = 0;
-	
-	/* The media bay will handle itself just fine */
-	if (mediabay)
-		return;
-	
-	/* Disable the bus */
-	ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmac_ide[i].aapl_bus_id, 0);
-}
-
-static void __pmac
-idepmac_wake_interface(int i, unsigned long base, int mediabay)
-{
-	struct device_node* np = pmac_ide[i].node;
-
-	if (!mediabay) {
-		/* Revive IDE disk and controller */
-		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmac_ide[i].aapl_bus_id, 1);
-		ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmac_ide[i].aapl_bus_id, 1);
-		mdelay(10);
-		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmac_ide[i].aapl_bus_id, 0);
-	}
-}
-
-static void
-idepmac_sleep_drive(ide_drive_t *drive, int idx, unsigned long base)
-{
-	int unlock = 0;
-
-	/* Wait for HW group to complete operations */
-	if (ide_spin_wait_hwgroup(drive)) {
-		// What can we do here ? Wake drive we had already
-		// put to sleep and return an error ?
-	} else {
-		unlock = 1;
-		/* Lock HW group */
-		HWGROUP(drive)->busy = 1;
-		/* Stop the device */
-		idepmac_sleep_device(drive, idx, base);
-	}
-	if (unlock)
-		spin_unlock_irq(&io_request_lock);
-}
-
-static void
-idepmac_wake_drive(ide_drive_t *drive, unsigned long base)
-{
-	unsigned long flags;
-	int j;
-	
-	/* Reset timings */
-	pmac_ide_selectproc(drive);
-	mdelay(10);
-	
-	/* Wait up to 20 seconds for the drive to be ready */
-	for (j = 0; j < 200; j++) {
-		int status;
-		mdelay(100);
-		outb(drive->select.all, base + 0x60);
-		if (inb(base + 0x60) != drive->select.all)
-			continue;
-		status = inb(base + 0x70);
-		if (!(status & BUSY_STAT))
-			break;
-	}
-
-	/* We resume processing on the HW group */
-	spin_lock_irqsave(&io_request_lock, flags);
-	HWGROUP(drive)->busy = 0;
-	if (!list_empty(&drive->queue.queue_head))
-		ide_do_request(HWGROUP(drive), 0);
-	spin_unlock_irqrestore(&io_request_lock, flags);			
-}
-
-/* Note: We support only master drives for now. This will have to be
- * improved if we want to handle sleep on the iMacDV where the CD-ROM
- * is a slave.
- * 
- * Well, actually, that sorta works on the iBook2 when the CD-ROM is
- * a slave, though it will fail to spin_wait_hwgroup for the slave
- * device as it is marked busy by the master sleep code. Well, it's
- * probably not worth fixing now as we don't have sleep code for
- * ATAPI devices anyway. Future kernels will hopefully deal with
- * IDE PM in a more generic way.
- */
-static int __pmac
-idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
-{
-	int i, ret;
-	unsigned long base;
-	int big_delay;
- 
-	switch (when) {
-	case PBOOK_SLEEP_REQUEST:
-		break;
-	case PBOOK_SLEEP_REJECT:
-		break;
-	case PBOOK_SLEEP_NOW:
-		for (i = 0; i < pmac_ide_count; ++i) {
-			ide_hwif_t *hwif;
-			int dn;
-
-			if ((base = pmac_ide[i].regbase) == 0)
-				continue;
-
-			hwif = &ide_hwifs[i];
-			for (dn=0; dn<MAX_DRIVES; dn++) {
-				if (!hwif->drives[dn].present)
-					continue;
-				idepmac_sleep_drive(&hwif->drives[dn], i, base);
-			}
-			/* Disable irq during sleep */
-			disable_irq(pmac_ide[i].irq);
-			
-			/* Check if this is a media bay with an IDE device or not
-			 * a media bay.
-			 */
-			ret = check_media_bay_by_base(base, MB_CD);
-			if ((ret == 0) || (ret == -ENODEV))
-				idepmac_sleep_interface(i, base, (ret == 0));
-		}
-		break;
-	case PBOOK_WAKE:
-		big_delay = 0;
-		for (i = 0; i < pmac_ide_count; ++i) {
-
-			if ((base = pmac_ide[i].regbase) == 0)
-				continue;
-				
-			/* Make sure we have sane timings */		
-			sanitize_timings(i);
-
-			/* Check if this is a media bay with an IDE device or not
-			 * a media bay
-			 */
-			ret = check_media_bay_by_base(base, MB_CD);
-			if ((ret == 0) || (ret == -ENODEV)) {
-				idepmac_wake_interface(i, base, (ret == 0));				
-				big_delay = 1;
-			}
-
-		}
-		/* Let hardware get up to speed */
-		if (big_delay)
-			mdelay(IDE_WAKEUP_DELAY_MS);
-	
-		for (i = 0; i < pmac_ide_count; ++i) {
-			ide_hwif_t *hwif;
-			int used_dma, dn;
-			int irq_on = 0;
-			
-			if ((base = pmac_ide[i].regbase) == 0)
-				continue;
-				
-			hwif = &ide_hwifs[i];
-			for (dn=0; dn<MAX_DRIVES; dn++) {
-				ide_drive_t *drive = &hwif->drives[dn];
-				if (!drive->present)
-					continue;
-				/* We don't have re-configured DMA yet */
-				used_dma = drive->using_dma;
-				drive->using_dma = 0;
-				idepmac_wake_drive(drive, base);
-				if (!irq_on) {
-					enable_irq(pmac_ide[i].irq);
-					irq_on = 1;
-				}
-				idepmac_wake_device(drive, used_dma);
-			}
-			if (!irq_on)
-				enable_irq(pmac_ide[i].irq);
-		}
-		break;
-	}
-	return PBOOK_SLEEP_OK;
-}
-#endif /* CONFIG_PMAC_PBOOK */
-
-static int __pmac
-pmac_ide_notify_reboot(struct notifier_block *this, unsigned long code, void *x)
-{
-	int i, gotone;
-	unsigned long base;
-
-	if (code != SYS_HALT && code != SYS_POWER_OFF)
-		return 0;
-
-	gotone = 0;
-	for (i = 0; i < pmac_ide_count; ++i) {
-		ide_hwif_t *hwif;
-		ide_drive_t *drive;
-		int unlock = 0;
-		int dn;
-
-		if ((base = pmac_ide[i].regbase) == 0)
-				continue;	
-
-		hwif = &ide_hwifs[i];
-		for (dn=0; dn<MAX_DRIVES; dn++) {
-			drive = &hwif->drives[dn];
-			if (drive->present) {
-				gotone = 1;
-				/* Wait for HW group to complete operations */
-				if (ide_spin_wait_hwgroup(drive)) {
-					// What can we do here ? Wake drive we had already
-					// put to sleep and return an error ?
-				} else {
-					unlock = 1;
-					/* Lock HW group */
-					HWGROUP(drive)->busy = 1;
-
-					/* Stop the device */
-					idepmac_sleep_device(drive, i, base);
-				}
-			}
-			if (unlock)
-				spin_unlock_irq(&io_request_lock);
-		}
-	}
-	if (gotone)
-		mdelay(1000);
-		
-	return NOTIFY_DONE;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-pnp.c linux-2.4.21/drivers/ide/ide-pnp.c
--- linux-2.4.20/drivers/ide/ide-pnp.c	2001-05-01 23:06:23.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-pnp.c	2002-12-18 18:58:11.000000000 +0000
@@ -21,12 +21,6 @@
 
 #include <linux/isapnp.h>
 
-#ifndef PREPARE_FUNC
-#define PREPARE_FUNC(dev)  (dev->prepare)
-#define ACTIVATE_FUNC(dev)  (dev->activate)
-#define DEACTIVATE_FUNC(dev)  (dev->deactivate)
-#endif
-
 #define DEV_IO(dev, index) (dev->resource[index].start)
 #define DEV_IRQ(dev, index) (dev->irq_resource[index].start)
 
@@ -54,6 +48,7 @@
 };
 
 /* Generic initialisation function for ISA PnP IDE interface */
+
 static int __init pnpide_generic_init(struct pci_dev *dev, int enable)
 {
 	hw_regs_t hw;
@@ -66,13 +61,16 @@
 		return 1;
 
 	ide_setup_ports(&hw, (ide_ioreg_t) DEV_IO(dev, 0),
-			generic_ide_offsets, (ide_ioreg_t) DEV_IO(dev, 1),
-			0, NULL, DEV_IRQ(dev, 0));
+			generic_ide_offsets,
+			(ide_ioreg_t) DEV_IO(dev, 1),
+			0, NULL,
+//			generic_pnp_ide_iops,
+			DEV_IRQ(dev, 0));
 
 	index = ide_register_hw(&hw, NULL);
 
 	if (index != -1) {
-	    	printk("ide%d: %s IDE interface\n", index, DEV_NAME(dev));
+	    	printk(KERN_INFO "ide%d: %s IDE interface\n", index, DEV_NAME(dev));
 		return 0;
 	}
 
@@ -88,7 +86,6 @@
 	{	0 }
 };
 
-#ifdef MODULE
 #define NR_PNP_DEVICES 8
 struct pnp_dev_inst {
 	struct pci_dev *dev;
@@ -96,11 +93,11 @@
 };
 static struct pnp_dev_inst devices[NR_PNP_DEVICES];
 static int pnp_ide_dev_idx = 0;
-#endif
 
 /*
  * Probe for ISA PnP IDE interfaces.
  */
+
 void __init pnpide_init(int enable)
 {
 	struct pci_dev *dev = NULL;
@@ -109,19 +106,18 @@
 	if (!isapnp_present())
 		return;
 
-#ifdef MODULE
 	/* Module unload, deactivate all registered devices. */
 	if (!enable) {
 		int i;
 		for (i = 0; i < pnp_ide_dev_idx; i++) {
+			dev = devices[i].dev;
 			devices[i].dev_type->init_fn(dev, 0);
-
-			if (DEACTIVATE_FUNC(devices[i].dev))
-				DEACTIVATE_FUNC(devices[i].dev)(devices[i].dev);
+			if (dev->deactivate)
+				dev->deactivate(dev);
 		}
 		return;
 	}
-#endif
+
 	for (dev_type = idepnp_devices; dev_type->vendor; dev_type++) {
 		while ((dev = isapnp_find_dev(NULL, dev_type->vendor,
 			dev_type->device, dev))) {
@@ -129,20 +125,20 @@
 			if (dev->active)
 				continue;
 
-       			if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
-				printk("ide: %s prepare failed\n", DEV_NAME(dev));
+       			if (dev->prepare && dev->prepare(dev) < 0) {
+				printk(KERN_ERR"ide-pnp: %s prepare failed\n", DEV_NAME(dev));
 				continue;
 			}
 
-			if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) {
-				printk("ide: %s activate failed\n", DEV_NAME(dev));
+			if (dev->activate && dev->activate(dev) < 0) {
+				printk(KERN_ERR"ide: %s activate failed\n", DEV_NAME(dev));
 				continue;
 			}
 
 			/* Call device initialization function */
 			if (dev_type->init_fn(dev, 1)) {
-				if (DEACTIVATE_FUNC(dev))
-					DEACTIVATE_FUNC(dev)(dev);
+				if (dev->deactivate(dev))
+					dev->deactivate(dev);
 			} else {
 #ifdef MODULE
 				/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-probe.c linux-2.4.21/drivers/ide/ide-probe.c
--- linux-2.4.20/drivers/ide/ide-probe.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-probe.c	2002-12-18 18:58:01.000000000 +0000
@@ -46,40 +46,77 @@
 #include <linux/delay.h>
 #include <linux/ide.h>
 #include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/kmod.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-static inline void do_identify (ide_drive_t *drive, byte cmd)
+/*
+ * CompactFlash cards and their brethern pretend to be removable
+ * hard disks, except:
+ *	(1) they never have a slave unit, and
+ *	(2) they don't have doorlock mechanisms.
+ * This test catches them, and is invoked elsewhere when setting
+ * appropriate config bits.
+ *
+ * FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD)
+ * devices, so in linux 2.3.x we should change this to just treat all PCMCIA
+ * drives this way, and get rid of the model-name tests below
+ * (too big of an interface change for 2.2.x).
+ * At that time, we might also consider parameterizing the timeouts and retries,
+ * since these are MUCH faster than mechanical drives.	-M.Lord
+ */
+inline int drive_is_flashcard (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+
+	if (drive->removable && id != NULL) {
+		if (id->config == 0x848a) return 1;	/* CompactFlash */
+		if (!strncmp(id->model, "KODAK ATA_FLASH", 15)	/* Kodak */
+		 || !strncmp(id->model, "Hitachi CV", 10)	/* Hitachi */
+		 || !strncmp(id->model, "SunDisk SDCFB", 13)	/* SunDisk */
+		 || !strncmp(id->model, "HAGIWARA HPC", 12)	/* Hagiwara */
+		 || !strncmp(id->model, "LEXAR ATA_FLASH", 15)	/* Lexar */
+		 || !strncmp(id->model, "ATA_FLASH", 9))	/* Simple Tech */
+		{
+			return 1;	/* yes, it is a flash memory card */
+		}
+	}
+	return 0;	/* no, it is not a flash memory card */
+}
+
+static inline void do_identify (ide_drive_t *drive, u8 cmd)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	int bswap = 1;
 	struct hd_driveid *id;
 
-	id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_ATOMIC);	/* called with interrupts disabled! */
+	/* called with interrupts disabled! */
+	id = drive->id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
 	if (!id) {
-		printk(KERN_WARNING "(ide-probe::do_identify) Out of memory.\n");
+		printk(KERN_WARNING "(ide-probe::do_identify) "
+			"Out of memory.\n");
 		goto err_kmalloc;
 	}
+	/* read 512 bytes of id info */
+	hwif->ata_input_data(drive, id, SECTOR_WORDS);
 
-	ide_input_data(drive, id, SECTOR_WORDS);		/* read 512 bytes of id info */
-	ide__sti();	/* local CPU only */
+	local_irq_enable();
 	ide_fix_driveid(id);
 
-	if (id->word156 == 0x4d42) {
-		printk("%s: drive->id->word156 == 0x%04x \n", drive->name, drive->id->word156);
-	}
-
 	if (!drive->forced_lun)
 		drive->last_lun = id->last_lun & 0x7;
+
 #if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA)
 	/*
 	 * EATA SCSI controllers do a hardware ATA emulation:
 	 * Ignore them if there is a driver for them available.
 	 */
-	if ((id->model[0] == 'P' && id->model[1] == 'M')
-	 || (id->model[0] == 'S' && id->model[1] == 'K')) {
+	if ((id->model[0] == 'P' && id->model[1] == 'M') ||
+	    (id->model[0] == 'S' && id->model[1] == 'K')) {
 		printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model);
 		goto err_misc;
 	}
@@ -93,27 +130,30 @@
 		if ((id->model[0] == 'N' && id->model[1] == 'E') /* NEC */
 		 || (id->model[0] == 'F' && id->model[1] == 'X') /* Mitsumi */
 		 || (id->model[0] == 'P' && id->model[1] == 'i'))/* Pioneer */
-			bswap ^= 1;	/* Vertos drives may still be weird */
+			/* Vertos drives may still be weird */
+			bswap ^= 1;	
 	}
-	ide_fixstring (id->model,     sizeof(id->model),     bswap);
-	ide_fixstring (id->fw_rev,    sizeof(id->fw_rev),    bswap);
-	ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
+	ide_fixstring(id->model,     sizeof(id->model),     bswap);
+	ide_fixstring(id->fw_rev,    sizeof(id->fw_rev),    bswap);
+	ide_fixstring(id->serial_no, sizeof(id->serial_no), bswap);
 
 	if (strstr(id->model, "E X A B Y T E N E S T"))
 		goto err_misc;
 
-	id->model[sizeof(id->model)-1] = '\0';	/* we depend on this a lot! */
+	/* we depend on this a lot! */
+	id->model[sizeof(id->model)-1] = '\0';
 	printk("%s: %s, ", drive->name, id->model);
 	drive->present = 1;
+	drive->dead = 0;
 
 	/*
 	 * Check for an ATAPI device
 	 */
 	if (cmd == WIN_PIDENTIFY) {
-		byte type = (id->config >> 8) & 0x1f;
+		u8 type = (id->config >> 8) & 0x1f;
 		printk("ATAPI ");
 #ifdef CONFIG_BLK_DEV_PDC4030
-		if (HWIF(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) {
+		if (hwif->channel == 1 && hwif->chipset == ide_pdc4030) {
 			printk(" -- not supported on 2nd Promise port\n");
 			goto err_misc;
 		}
@@ -121,19 +161,24 @@
 		switch (type) {
 			case ide_floppy:
 				if (!strstr(id->model, "CD-ROM")) {
-					if (!strstr(id->model, "oppy") && !strstr(id->model, "poyp") && !strstr(id->model, "ZIP"))
+					if (!strstr(id->model, "oppy") &&
+					    !strstr(id->model, "poyp") &&
+					    !strstr(id->model, "ZIP"))
 						printk("cdrom or floppy?, assuming ");
 					if (drive->media != ide_cdrom) {
 						printk ("FLOPPY");
+						drive->removable = 1;
 						break;
 					}
 				}
-				type = ide_cdrom;	/* Early cdrom models used zero */
+				/* Early cdrom models used zero */
+				type = ide_cdrom;
 			case ide_cdrom:
 				drive->removable = 1;
 #ifdef CONFIG_PPC
 				/* kludge for Apple PowerBook internal zip */
-				if (!strstr(id->model, "CD-ROM") && strstr(id->model, "ZIP")) {
+				if (!strstr(id->model, "CD-ROM") &&
+				    strstr(id->model, "ZIP")) {
 					printk ("FLOPPY");
 					type = ide_floppy;
 					break;
@@ -164,18 +209,21 @@
 		drive->removable = 1;
 	/*
 	 * Prevent long system lockup probing later for non-existant
-	 * slave drive if the hwif is actually a flash memory card of some variety:
+	 * slave drive if the hwif is actually a flash memory card of
+	 * some variety:
 	 */
+	drive->is_flash = 0;
 	if (drive_is_flashcard(drive)) {
-		ide_drive_t *mate = &HWIF(drive)->drives[1^drive->select.b.unit];
+		ide_drive_t *mate = &hwif->drives[1^drive->select.b.unit];
 		if (!mate->ata_flash) {
 			mate->present = 0;
 			mate->noprobe = 1;
 		}
+		drive->is_flash = 1;
 	}
 	drive->media = ide_disk;
-	printk("ATA DISK drive\n");
-	QUIRK_LIST(HWIF(drive),drive);
+	printk("%s DISK drive\n", (drive->is_flash) ? "CFA" : "ATA" );
+	QUIRK_LIST(drive);
 	return;
 
 err_misc:
@@ -195,95 +243,117 @@
  *		1  device timed-out (no response to identify request)
  *		2  device aborted the command (refused to identify itself)
  */
-static int actual_try_to_identify (ide_drive_t *drive, byte cmd)
+static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	int rc;
 	ide_ioreg_t hd_status;
 	unsigned long timeout;
-	byte s, a;
+	u8 s = 0, a = 0;
 
 	if (IDE_CONTROL_REG) {
 		/* take a deep breath */
 		ide_delay_50ms();
-		a = IN_BYTE(IDE_ALTSTATUS_REG);
-		s = IN_BYTE(IDE_STATUS_REG);
+		a = hwif->INB(IDE_ALTSTATUS_REG);
+		s = hwif->INB(IDE_STATUS_REG);
 		if ((a ^ s) & ~INDEX_STAT) {
-			printk("%s: probing with STATUS(0x%02x) instead of ALTSTATUS(0x%02x)\n", drive->name, s, a);
-			hd_status = IDE_STATUS_REG;	/* ancient Seagate drives, broken interfaces */
+			printk("%s: probing with STATUS(0x%02x) instead of "
+				"ALTSTATUS(0x%02x)\n", drive->name, s, a);
+			/* ancient Seagate drives, broken interfaces */
+			hd_status = IDE_STATUS_REG;
 		} else {
-			hd_status = IDE_ALTSTATUS_REG;	/* use non-intrusive polling */
+			/* use non-intrusive polling */
+			hd_status = IDE_ALTSTATUS_REG;
 		}
 	} else {
 		ide_delay_50ms();
 		hd_status = IDE_STATUS_REG;
 	}
 
-	/* set features register for atapi identify command to be sure of reply */
+	/* set features register for atapi
+	 * identify command to be sure of reply
+	 */
 	if ((cmd == WIN_PIDENTIFY))
-		OUT_BYTE(0,IDE_FEATURE_REG);	/* disable dma & overlap */
+		/* disable dma & overlap */
+		hwif->OUTB(0, IDE_FEATURE_REG);
 
-#if CONFIG_BLK_DEV_PDC4030
-	if (HWIF(drive)->chipset == ide_pdc4030) {
-		/* DC4030 hosted drives need their own identify... */
-		extern int pdc4030_identify(ide_drive_t *);
-		if (pdc4030_identify(drive)) {
+	if (hwif->identify != NULL) {
+		if (hwif->identify(drive))
 			return 1;
-		}
-	} else
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-		OUT_BYTE(cmd,IDE_COMMAND_REG);		/* ask drive for ID */
+	} else {
+		/* ask drive for ID */
+		hwif->OUTB(cmd, IDE_COMMAND_REG);
+	}
 	timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
 	timeout += jiffies;
 	do {
-		if (0 < (signed long)(jiffies - timeout)) {
-			return 1;	/* drive timed-out */
+		if (time_after(jiffies, timeout)) {
+			/* drive timed-out */
+			return 1;
 		}
-		ide_delay_50ms();		/* give drive a breather */
-	} while (IN_BYTE(hd_status) & BUSY_STAT);
+		/* give drive a breather */
+		ide_delay_50ms();
+	} while ((hwif->INB(hd_status)) & BUSY_STAT);
 
-	ide_delay_50ms();		/* wait for IRQ and DRQ_STAT */
-	if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
+	/* wait for IRQ and DRQ_STAT */
+	ide_delay_50ms();
+	if (OK_STAT((hwif->INB(IDE_STATUS_REG)), DRQ_STAT, BAD_R_STAT)) {
 		unsigned long flags;
-		__save_flags(flags);	/* local CPU only */
-		__cli();		/* local CPU only; some systems need this */
-		do_identify(drive, cmd); /* drive returned ID */
-		rc = 0;			/* drive responded with ID */
-		(void) GET_STAT();	/* clear drive IRQ */
-		__restore_flags(flags);	/* local CPU only */
-	} else
-		rc = 2;			/* drive refused ID */
+
+		/* local CPU only; some systems need this */
+		local_irq_save(flags);
+		/* drive returned ID */
+		do_identify(drive, cmd);
+		/* drive responded with ID */
+		rc = 0;
+		/* clear drive IRQ */
+		(void) hwif->INB(IDE_STATUS_REG);
+		local_irq_restore(flags);
+	} else {
+		/* drive refused ID */
+		rc = 2;
+	}
 	return rc;
 }
 
-static int try_to_identify (ide_drive_t *drive, byte cmd)
+static int try_to_identify (ide_drive_t *drive, u8 cmd)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	int retval;
 	int autoprobe = 0;
 	unsigned long cookie = 0;
 
-	if (IDE_CONTROL_REG && !HWIF(drive)->irq) {
+	if (IDE_CONTROL_REG && !hwif->irq) {
 		autoprobe = 1;
 		cookie = probe_irq_on();
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* enable device irq */
+		/* enable device irq */
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
 	}
 
 	retval = actual_try_to_identify(drive, cmd);
 
 	if (autoprobe) {
 		int irq;
-		OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* mask device irq */
-		(void) GET_STAT();			/* clear drive IRQ */
+		/* mask device irq */
+		hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+		/* clear drive IRQ */
+		(void) hwif->INB(IDE_STATUS_REG);
 		udelay(5);
 		irq = probe_irq_off(cookie);
-		if (!HWIF(drive)->irq) {
+		if (!hwif->irq) {
 			if (irq > 0) {
-				HWIF(drive)->irq = irq;
-			} else {	/* Mmmm.. multiple IRQs.. don't know which was ours */
-				printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie);
+				hwif->irq = irq;
+			} else {
+				/* Mmmm.. multiple IRQs..
+				 * don't know which was ours
+				 */
+				printk("%s: IRQ probe failed (0x%lx)\n",
+					drive->name, cookie);
 #ifdef CONFIG_BLK_DEV_CMD640
 #ifdef CMD640_DUMP_REGS
-				if (HWIF(drive)->chipset == ide_cmd640) {
-					printk("%s: Hmmm.. probably a driver problem.\n", drive->name);
+				if (hwif->chipset == ide_cmd640) {
+					printk("%s: Hmmm.. probably a driver "
+						"problem.\n", drive->name);
 					CMD640_DUMP_REGS;
 				}
 #endif /* CMD640_DUMP_REGS */
@@ -311,11 +381,13 @@
  *		3  bad status from device (possible for ATAPI drives)
  *		4  probe was not attempted because failure was obvious
  */
-static int do_probe (ide_drive_t *drive, byte cmd)
+static int do_probe (ide_drive_t *drive, u8 cmd)
 {
 	int rc;
 	ide_hwif_t *hwif = HWIF(drive);
-	if (drive->present) {	/* avoid waiting for inappropriate probes */
+
+	if (drive->present) {
+		/* avoid waiting for inappropriate probes */
 		if ((drive->media != ide_disk) && (cmd == WIN_IDENTIFY))
 			return 4;
 	}
@@ -324,44 +396,66 @@
 		drive->name, drive->present, drive->media,
 		(cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
 #endif
-	ide_delay_50ms();	/* needed for some systems (e.g. crw9624 as drive0 with disk as slave) */
-	SELECT_DRIVE(hwif,drive);
+
+	/* needed for some systems
+	 * (e.g. crw9624 as drive0 with disk as slave)
+	 */
 	ide_delay_50ms();
-	if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) {
+	SELECT_DRIVE(drive);
+	ide_delay_50ms();
+	if (hwif->INB(IDE_SELECT_REG) != drive->select.all && !drive->present) {
 		if (drive->select.b.unit != 0) {
-			SELECT_DRIVE(hwif,&hwif->drives[0]);	/* exit with drive0 selected */
-			ide_delay_50ms();		/* allow BUSY_STAT to assert & clear */
+			/* exit with drive0 selected */
+			SELECT_DRIVE(&hwif->drives[0]);
+			/* allow BUSY_STAT to assert & clear */
+			ide_delay_50ms();
 		}
-		return 3;    /* no i/f present: mmm.. this should be a 4 -ml */
+		/* no i/f present: mmm.. this should be a 4 -ml */
+		return 3;
 	}
 
-	if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT)
-	 || drive->present || cmd == WIN_PIDENTIFY)
-	{
-		if ((rc = try_to_identify(drive,cmd)))   /* send cmd and wait */
-			rc = try_to_identify(drive,cmd); /* failed: try again */
-		if (rc == 1 && cmd == WIN_PIDENTIFY && drive->autotune != 2) {
+	if (OK_STAT((hwif->INB(IDE_STATUS_REG)), READY_STAT, BUSY_STAT) ||
+	    drive->present || cmd == WIN_PIDENTIFY) {
+		/* send cmd and wait */
+		if ((rc = try_to_identify(drive, cmd))) {
+			/* failed: try again */
+			rc = try_to_identify(drive,cmd);
+		}
+		if (hwif->INB(IDE_STATUS_REG) == (BUSY_STAT|READY_STAT))
+			return 4;
+
+		if ((rc == 1 && cmd == WIN_PIDENTIFY) &&
+			((drive->autotune == IDE_TUNE_DEFAULT) ||
+			(drive->autotune == IDE_TUNE_AUTO))) {
 			unsigned long timeout;
-			printk("%s: no response (status = 0x%02x), resetting drive\n", drive->name, GET_STAT());
+			printk("%s: no response (status = 0x%02x), "
+				"resetting drive\n", drive->name,
+				hwif->INB(IDE_STATUS_REG));
 			ide_delay_50ms();
-			OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+			hwif->OUTB(drive->select.all, IDE_SELECT_REG);
 			ide_delay_50ms();
-			OUT_BYTE(WIN_SRST, IDE_COMMAND_REG);
+			hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
 			timeout = jiffies;
-			while ((GET_STAT() & BUSY_STAT) && time_before(jiffies, timeout + WAIT_WORSTCASE))
+			while (((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) &&
+			       time_before(jiffies, timeout + WAIT_WORSTCASE))
 				ide_delay_50ms();
 			rc = try_to_identify(drive, cmd);
 		}
 		if (rc == 1)
-			printk("%s: no response (status = 0x%02x)\n", drive->name, GET_STAT());
-		(void) GET_STAT();		/* ensure drive irq is clear */
+			printk("%s: no response (status = 0x%02x)\n",
+				drive->name, hwif->INB(IDE_STATUS_REG));
+		/* ensure drive irq is clear */
+		(void) hwif->INB(IDE_STATUS_REG);
 	} else {
-		rc = 3;				/* not present or maybe ATAPI */
+		/* not present or maybe ATAPI */
+		rc = 3;
 	}
 	if (drive->select.b.unit != 0) {
-		SELECT_DRIVE(hwif,&hwif->drives[0]);	/* exit with drive0 selected */
+		/* exit with drive0 selected */
+		SELECT_DRIVE(&hwif->drives[0]);
 		ide_delay_50ms();
-		(void) GET_STAT();		/* ensure drive irq is clear */
+		/* ensure drive irq is clear */
+		(void) hwif->INB(IDE_STATUS_REG);
 	}
 	return rc;
 }
@@ -371,12 +465,13 @@
  */
 static void enable_nest (ide_drive_t *drive)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long timeout;
 
-	printk("%s: enabling %s -- ", HWIF(drive)->name, drive->id->model);
-	SELECT_DRIVE(HWIF(drive), drive);
+	printk("%s: enabling %s -- ", hwif->name, drive->id->model);
+	SELECT_DRIVE(drive);
 	ide_delay_50ms();
-	OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
+	hwif->OUTB(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
 	timeout = jiffies + WAIT_WORSTCASE;
 	do {
 		if (time_after(jiffies, timeout)) {
@@ -384,14 +479,20 @@
 			return;
 		}
 		ide_delay_50ms();
-	} while (GET_STAT() & BUSY_STAT);
+	} while ((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT);
+
 	ide_delay_50ms();
-	if (!OK_STAT(GET_STAT(), 0, BAD_STAT))
-		printk("failed (status = 0x%02x)\n", GET_STAT());
-	else
+
+	if (!OK_STAT((hwif->INB(IDE_STATUS_REG)), 0, BAD_STAT)) {
+		printk("failed (status = 0x%02x)\n", hwif->INB(IDE_STATUS_REG));
+	} else {
 		printk("success\n");
-	if (do_probe(drive, WIN_IDENTIFY) >= 2) {	/* if !(success||timed-out) */
-		(void) do_probe(drive, WIN_PIDENTIFY);	/* look for ATAPI device */
+	}
+
+	/* if !(success||timed-out) */
+	if (do_probe(drive, WIN_IDENTIFY) >= 2) {
+		/* look for ATAPI device */
+		(void) do_probe(drive, WIN_PIDENTIFY);
 	}
 }
 
@@ -401,176 +502,243 @@
  * Returns:	0  no device was found
  *		1  device was found (note: drive->present might still be 0)
  */
-static inline byte probe_for_drive (ide_drive_t *drive)
+static inline u8 probe_for_drive (ide_drive_t *drive)
 {
-	if (drive->noprobe)			/* skip probing? */
+	/* skip probing? */
+	if (drive->noprobe)
 		return drive->present;
-	if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */
-		(void) do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */
+
+	/* if !(success||timed-out) */
+	if (do_probe(drive, WIN_IDENTIFY) >= 2) {
+		/* look for ATAPI device */
+		(void) do_probe(drive, WIN_PIDENTIFY);
 	}
 	if (drive->id && strstr(drive->id->model, "E X A B Y T E N E S T"))
 		enable_nest(drive);
 	if (!drive->present)
-		return 0;			/* drive not found */
-	if (drive->id == NULL) {		/* identification failed? */
+		/* drive not found */
+		return 0;
+
+	/* identification failed? */
+	if (drive->id == NULL) {
 		if (drive->media == ide_disk) {
-			printk ("%s: non-IDE drive, CHS=%d/%d/%d\n",
-			 drive->name, drive->cyl, drive->head, drive->sect);
+			printk("%s: non-IDE drive, CHS=%d/%d/%d\n",
+				drive->name, drive->cyl,
+				drive->head, drive->sect);
 		} else if (drive->media == ide_cdrom) {
 			printk("%s: ATAPI cdrom (?)\n", drive->name);
 		} else {
-			drive->present = 0;	/* nuke it */
+			/* nuke it */
+			drive->present = 0;
 		}
 	}
-	return 1;	/* drive was found */
+	/* drive was found */
+	return 1;
 }
 
-/*
- * Calculate the region that this interface occupies,
- * handling interfaces where the registers may not be
- * ordered sanely.  We deal with the CONTROL register
- * separately.
- */
+#define hwif_check_region(addr, num) \
+	((hwif->mmio) ? check_mem_region((addr),(num)) : check_region((addr),(num)))
+
 static int hwif_check_regions (ide_hwif_t *hwif)
 {
-	int region_errors = 0;
-
-	hwif->straight8 = 0;
-	region_errors  = ide_check_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_ERROR_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_LCYL_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_HCYL_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
+	u32 i		= 0;
+	int addr_errs	= 0;
 
+	if (hwif->mmio == 2)
+		return 0;
+	addr_errs  = hwif_check_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
+	for (i = IDE_ERROR_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		addr_errs += hwif_check_region(hwif->io_ports[i], 1);
 	if (hwif->io_ports[IDE_CONTROL_OFFSET])
-		region_errors += ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
+		addr_errs += hwif_check_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
 #if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
 	if (hwif->io_ports[IDE_IRQ_OFFSET])
-		region_errors += ide_check_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
+		addr_errs += hwif_check_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
 #endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
-	/*
-	 * If any errors are return, we drop the hwif interface.
-	 */
-	return(region_errors);
+	/* If any errors are return, we drop the hwif interface. */
+	hwif->straight8 = 0;
+	return(addr_errs);
 }
 
+//EXPORT_SYMBOL(hwif_check_regions);
+
+#define hwif_request_region(addr, num, name)	\
+	((hwif->mmio) ? request_mem_region((addr),(num),(name)) : request_region((addr),(num),(name)))
+
 static void hwif_register (ide_hwif_t *hwif)
 {
-	if (((unsigned long)hwif->io_ports[IDE_DATA_OFFSET] | 7) ==
-	    ((unsigned long)hwif->io_ports[IDE_STATUS_OFFSET])) {
-		ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name);
-		hwif->straight8 = 1;
-		goto jump_straight8;
-	}
+	u32 i = 0;
 
-	if (hwif->io_ports[IDE_DATA_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_ERROR_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_ERROR_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_NSECTOR_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_SECTOR_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_LCYL_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_LCYL_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_HCYL_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_HCYL_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_SELECT_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_SELECT_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_STATUS_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_STATUS_OFFSET], 1, hwif->name);
-
-jump_straight8:
+	if (hwif->mmio == 2)
+		return;
 	if (hwif->io_ports[IDE_CONTROL_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
+		hwif_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
 #if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
 	if (hwif->io_ports[IDE_IRQ_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_IRQ_OFFSET], 1, hwif->name);
+		hwif_request_region(hwif->io_ports[IDE_IRQ_OFFSET], 1, hwif->name);
 #endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
+	if (((unsigned long)hwif->io_ports[IDE_DATA_OFFSET] | 7) ==
+	    ((unsigned long)hwif->io_ports[IDE_STATUS_OFFSET])) {
+		hwif_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name);
+		hwif->straight8 = 1;
+		return;
+	}
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		hwif_request_region(hwif->io_ports[i], 1, hwif->name);
 }
 
+//EXPORT_SYMBOL(hwif_register);
+
 /*
  * This routine only knows how to look for drive units 0 and 1
  * on an interface, so any setting of MAX_DRIVES > 2 won't work here.
  */
-static void probe_hwif (ide_hwif_t *hwif)
+void probe_hwif (ide_hwif_t *hwif)
 {
 	unsigned int unit;
 	unsigned long flags;
+	unsigned int irqd;
 
 	if (hwif->noprobe)
 		return;
 #ifdef CONFIG_BLK_DEV_IDE
 	if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) {
 		extern void probe_cmos_for_drives(ide_hwif_t *);
-
-		probe_cmos_for_drives (hwif);
+		probe_cmos_for_drives(hwif);
 	}
 #endif
 
-	if ((hwif->chipset != ide_4drives || !hwif->mate->present) &&
+	if ((hwif->chipset != ide_4drives || !hwif->mate || !hwif->mate->present) &&
 #if CONFIG_BLK_DEV_PDC4030
 	    (hwif->chipset != ide_pdc4030 || hwif->channel == 0) &&
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 	    (hwif_check_regions(hwif))) {
-		int msgout = 0;
+		u16 msgout = 0;
 		for (unit = 0; unit < MAX_DRIVES; ++unit) {
 			ide_drive_t *drive = &hwif->drives[unit];
 			if (drive->present) {
 				drive->present = 0;
-				printk("%s: ERROR, PORTS ALREADY IN USE\n", drive->name);
+				printk("%s: ERROR, PORTS ALREADY IN USE\n",
+					drive->name);
 				msgout = 1;
 			}
 		}
 		if (!msgout)
-			printk("%s: ports already in use, skipping probe\n", hwif->name);
+			printk("%s: ports already in use, skipping probe\n",
+				hwif->name);
 		return;	
 	}
 
-	__save_flags(flags);	/* local CPU only */
-	__sti();		/* local CPU only; needed for jiffies and irq probing */
+	/*
+	 * We must always disable IRQ, as probe_for_drive will assert IRQ, but
+	 * we'll install our IRQ driver much later...
+	 */
+	irqd = hwif->irq;
+	if (irqd)
+		disable_irq(hwif->irq);
+
+	local_irq_set(flags);
 	/*
 	 * Second drive should only exist if first drive was found,
 	 * but a lot of cdrom drives are configured as single slaves.
 	 */
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
-		(void) probe_for_drive (drive);
+		drive->dn = ((hwif->channel ? 2 : 0) + unit);
+		hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
+		(void) probe_for_drive(drive);
 		if (drive->present && !hwif->present) {
 			hwif->present = 1;
-			if (hwif->chipset != ide_4drives || !hwif->mate->present) {
+			if (hwif->chipset != ide_4drives ||
+			    !hwif->mate || 
+			    !hwif->mate->present) {
 				hwif_register(hwif);
 			}
 		}
 	}
 	if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) {
 		unsigned long timeout = jiffies + WAIT_WORSTCASE;
-		byte stat;
+		u8 stat;
 
 		printk("%s: reset\n", hwif->name);
-		OUT_BYTE(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
 		udelay(10);
-		OUT_BYTE(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
 		do {
 			ide_delay_50ms();
-			stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
-		} while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies));
+			stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+		} while ((stat & BUSY_STAT) && time_after(timeout, jiffies));
 
 	}
-	__restore_flags(flags);	/* local CPU only */
+	local_irq_restore(flags);
+	/*
+	 * Use cached IRQ number. It might be (and is...) changed by probe
+	 * code above
+	 */
+	if (irqd)
+		enable_irq(irqd);
+
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
 		if (drive->present) {
-			ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
-			if (tuneproc != NULL && drive->autotune == 1)
-				tuneproc(drive, 255);	/* auto-tune PIO mode */
+			if (hwif->tuneproc != NULL && 
+				drive->autotune == IDE_TUNE_AUTO)
+				/* auto-tune PIO mode */
+				hwif->tuneproc(drive, 255);
+			/*
+			 * MAJOR HACK BARF :-/
+			 *
+			 * FIXME: chipsets own this cruft!
+			 */
+			/*
+			 * Move here to prevent module loading clashing.
+			 */
+	//		drive->autodma = hwif->autodma;
+			if ((hwif->ide_dma_check) &&
+				((drive->autotune == IDE_TUNE_DEFAULT) ||
+				(drive->autotune == IDE_TUNE_AUTO))) {
+				/*
+				 * Force DMAing for the beginning of the check.
+				 * Some chipsets appear to do interesting
+				 * things, if not checked and cleared.
+				 *   PARANOIA!!!
+				 */
+				hwif->ide_dma_off_quietly(drive);
+				hwif->ide_dma_check(drive);
+			}
+		}
+	}
+}
+
+EXPORT_SYMBOL(probe_hwif);
+
+#if 0
+int hwif_init (ide_hwif_t *hwif);
+int probe_hwif_init (ide_hwif_t *hwif)
+{
+	hwif->initializing = 1;
+	probe_hwif(hwif);
+	hwif_init(hwif);
+
+#if 1
+	if (hwif->present) {
+		u16 unit = 0;
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			ide_drive_t *drive = &hwif->drives[unit];
+			if (drive->present) {
+				ata_attach(drive);
+			}
 		}
 	}
+#endif
+	hwif->initializing = 0;
+	return 0;
 }
 
+EXPORT_SYMBOL(probe_hwif_init);
+#endif
+
 #if MAX_HWIFS > 1
 /*
  * save_match() is used to simplify logic in init_irq() below.
@@ -583,18 +751,20 @@
  *
  * This routine detects and reports such situations, but does not fix them.
  */
-static void save_match (ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
+void save_match (ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
 {
 	ide_hwif_t *m = *match;
 
 	if (m && m->hwgroup && m->hwgroup != new->hwgroup) {
 		if (!new->hwgroup)
 			return;
-		printk("%s: potential irq problem with %s and %s\n", hwif->name, new->name, m->name);
+		printk("%s: potential irq problem with %s and %s\n",
+			hwif->name, new->name, m->name);
 	}
 	if (!m || m->irq != hwif->irq) /* don't undo a prior perfect match */
 		*match = new;
 }
+EXPORT_SYMBOL(save_match);
 #endif /* MAX_HWIFS > 1 */
 
 /*
@@ -614,6 +784,7 @@
 	}
 }
 
+#undef __IRQ_HELL_SPIN
 /*
  * This routine sets up the irq for an ide interface, and creates a new
  * hwgroup for the irq/hwif if none was previously assigned.
@@ -627,20 +798,26 @@
  * but anything else has led to problems on some machines.  We re-enable
  * interrupts as much as we can safely do in most places.
  */
-static int init_irq (ide_hwif_t *hwif)
+int init_irq (ide_hwif_t *hwif)
 {
 	unsigned long flags;
 	unsigned int index;
 	ide_hwgroup_t *hwgroup, *new_hwgroup;
 	ide_hwif_t *match = NULL;
 
-	
+#if 0
+	/* Allocate the buffer and no sleep allowed */
+	new_hwgroup = kmalloc(sizeof(ide_hwgroup_t),GFP_ATOMIC);
+#else
 	/* Allocate the buffer and potentially sleep first */
-	
 	new_hwgroup = kmalloc(sizeof(ide_hwgroup_t),GFP_KERNEL);
+#endif
 	
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
+#ifndef __IRQ_HELL_SPIN
+	save_and_cli(flags);
+#else
+	spin_lock_irqsave(&io_request_lock, flags);
+#endif
 
 	hwif->hwgroup = NULL;
 #if MAX_HWIFS > 1
@@ -652,7 +829,8 @@
 		if (h->hwgroup) {  /* scan only initialized hwif's */
 			if (hwif->irq == h->irq) {
 				hwif->sharing_irq = h->sharing_irq = 1;
-				if (hwif->chipset != ide_pci || h->chipset != ide_pci) {
+				if (hwif->chipset != ide_pci ||
+				    h->chipset != ide_pci) {
 					save_match(hwif, h, &match);
 				}
 			}
@@ -677,7 +855,11 @@
 	} else {
 		hwgroup = new_hwgroup;
 		if (!hwgroup) {
-			restore_flags(flags);	/* all CPUs */
+#ifndef __IRQ_HELL_SPIN
+			restore_flags(flags);
+#else
+			spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 			return 1;
 		}
 		memset(hwgroup, 0, sizeof(ide_hwgroup_t));
@@ -695,19 +877,30 @@
 	 * Allocate the irq, if not already obtained for another hwif
 	 */
 	if (!match || match->irq != hwif->irq) {
-#ifdef CONFIG_IDEPCI_SHARE_IRQ
-		int sa = IDE_CHIPSET_IS_PCI(hwif->chipset) ? SA_SHIRQ : SA_INTERRUPT;
-#else /* !CONFIG_IDEPCI_SHARE_IRQ */
-		int sa = IDE_CHIPSET_IS_PCI(hwif->chipset) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT;
+		int sa = SA_INTERRUPT;
+#if defined(__mc68000__) || defined(CONFIG_APUS)
+		sa = SA_SHIRQ;
+#endif /* __mc68000__ || CONFIG_APUS */
+
+		if (IDE_CHIPSET_IS_PCI(hwif->chipset)) {
+			sa = SA_SHIRQ;
+#ifndef CONFIG_IDEPCI_SHARE_IRQ
+			sa |= SA_INTERRUPT;
 #endif /* CONFIG_IDEPCI_SHARE_IRQ */
+		}
 
 		if (hwif->io_ports[IDE_CONTROL_OFFSET])
-			OUT_BYTE(0x08, hwif->io_ports[IDE_CONTROL_OFFSET]); /* clear nIEN */
+			/* clear nIEN */
+			hwif->OUTB(0x08, hwif->io_ports[IDE_CONTROL_OFFSET]);
 
-		if (ide_request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwgroup)) {
+		if (request_irq(hwif->irq,&ide_intr,sa,hwif->name,hwgroup)) {
 			if (!match)
 				kfree(hwgroup);
-			restore_flags(flags);	/* all CPUs */
+#ifndef __IRQ_HELL_SPIN
+			restore_flags(flags);
+#else
+			spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 			return 1;
 		}
 	}
@@ -735,10 +928,16 @@
 		printk("%s : Adding missed hwif to hwgroup!!\n", hwif->name);
 #endif
 	}
-	restore_flags(flags);	/* all CPUs; safe now that hwif->hwgroup is set up */
+
+	/* all CPUs; safe now that hwif->hwgroup is set up */
+#ifndef __IRQ_HELL_SPIN
+	restore_flags(flags);
+#else
+	spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 
 #if !defined(__mc68000__) && !defined(CONFIG_APUS) && !defined(__sparc__)
-	printk("%s at 0x%03x-0x%03x,0x%03x on irq %d", hwif->name,
+	printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
 		hwif->io_ports[IDE_DATA_OFFSET],
 		hwif->io_ports[IDE_DATA_OFFSET]+7,
 		hwif->io_ports[IDE_CONTROL_OFFSET], hwif->irq);
@@ -748,7 +947,7 @@
 		hwif->io_ports[IDE_DATA_OFFSET]+7,
 		hwif->io_ports[IDE_CONTROL_OFFSET], __irq_itoa(hwif->irq));
 #else
-	printk("%s at %p on irq 0x%08x", hwif->name,
+	printk("%s at %x on irq 0x%08x", hwif->name,
 		hwif->io_ports[IDE_DATA_OFFSET], hwif->irq);
 #endif /* __mc68000__ && CONFIG_APUS */
 	if (match)
@@ -758,6 +957,8 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(init_irq);
+
 /*
  * init_gendisk() (as opposed to ide_geninit) is called for each major device,
  * after probing for drives, to allocate partition tables and other data
@@ -771,34 +972,27 @@
 	int *bs, *max_sect, *max_ra;
 	extern devfs_handle_t ide_devfs_handle;
 
-#if 1
 	units = MAX_DRIVES;
-#else
-	/* figure out maximum drive number on the interface */
-	for (units = MAX_DRIVES; units > 0; --units) {
-		if (hwif->drives[units-1].present)
-			break;
-	}
-#endif
 
 	minors    = units * (1<<PARTN_BITS);
-	gd        = kmalloc (sizeof(struct gendisk), GFP_KERNEL);
+	gd        = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
 	if (!gd)
 		goto err_kmalloc_gd;
-	memset (gd, 0, sizeof(struct gendisk));
-	gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
+	memset(gd, 0, sizeof(struct gendisk));
+	
+	gd->sizes = kmalloc(minors * sizeof(int), GFP_KERNEL);
 	if (!gd->sizes)
 		goto err_kmalloc_gd_sizes;
-	gd->part  = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
+	gd->part  = kmalloc(minors * sizeof(struct hd_struct), GFP_KERNEL);
 	if (!gd->part)
 		goto err_kmalloc_gd_part;
-	bs        = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	bs        = kmalloc(minors*sizeof(int), GFP_KERNEL);
 	if (!bs)
 		goto err_kmalloc_bs;
-	max_sect  = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	max_sect  = kmalloc(minors*sizeof(int), GFP_KERNEL);
 	if (!max_sect)
 		goto err_kmalloc_max_sect;
-	max_ra    = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	max_ra    = kmalloc(minors*sizeof(int), GFP_KERNEL);
 	if (!max_ra)
 		goto err_kmalloc_max_ra;
 
@@ -813,55 +1007,49 @@
 		/*
 		 * IDE can do up to 128K per request == 256
 		 */
-		*max_sect++ = ((hwif->chipset == ide_pdc4030) ? 127 : 128);
+		*max_sect++ = ((hwif->rqsize) ? hwif->rqsize : 128);
 		*max_ra++ = vm_max_readahead;
 	}
 
 	for (unit = 0; unit < units; ++unit)
 		hwif->drives[unit].part = &gd->part[unit << PARTN_BITS];
 
-	gd->major	= hwif->major;		/* our major device number */
-	gd->major_name	= IDE_MAJOR_NAME;	/* treated special in genhd.c */
-	gd->minor_shift	= PARTN_BITS;		/* num bits for partitions */
-	gd->max_p	= 1<<PARTN_BITS;	/* 1 + max partitions / drive */
-	gd->nr_real	= units;		/* current num real drives */
-	gd->real_devices= hwif;			/* ptr to internal data */
-	gd->next	= NULL;			/* linked list of major devs */
-	gd->fops        = ide_fops;             /* file operations */
-	gd->de_arr	= kmalloc (sizeof *gd->de_arr * units, GFP_KERNEL);
-	gd->flags	= kmalloc (sizeof *gd->flags * units, GFP_KERNEL);
+	/* our major device number */
+	gd->major	= hwif->major;
+	/* treated special in genhd.c */
+	gd->major_name	= IDE_MAJOR_NAME;
+	/* num bits for partitions */
+	gd->minor_shift	= PARTN_BITS;
+	/* 1 + max partitions / drive */
+	gd->max_p	= 1<<PARTN_BITS;
+	/* current num real drives */
+	gd->nr_real	= units;
+	/* ptr to internal data */
+	gd->real_devices= hwif;
+	/* linked list of major devs */
+	gd->next	= NULL;
+	/* file operations */
+	gd->fops        = ide_fops;
+	gd->de_arr	= kmalloc(sizeof *gd->de_arr * units, GFP_KERNEL);
+	gd->flags	= kmalloc(sizeof *gd->flags * units, GFP_KERNEL);
 	if (gd->de_arr)
-		memset (gd->de_arr, 0, sizeof *gd->de_arr * units);
+		memset(gd->de_arr, 0, sizeof *gd->de_arr * units);
 	if (gd->flags)
-		memset (gd->flags, 0, sizeof *gd->flags * units);
+		memset(gd->flags, 0, sizeof *gd->flags * units);
 
 	hwif->gd = gd;
 	add_gendisk(gd);
 
 	for (unit = 0; unit < units; ++unit) {
-#if 1
 		char name[64];
 		ide_add_generic_settings(hwif->drives + unit);
-		hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
+//		hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
 		sprintf (name, "host%d/bus%d/target%d/lun%d",
 			(hwif->channel && hwif->mate) ?
 			hwif->mate->index : hwif->index,
 			hwif->channel, unit, hwif->drives[unit].lun);
 		if (hwif->drives[unit].present)
 			hwif->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL);
-#else
-		if (hwif->drives[unit].present) {
-			char name[64];
-
-			ide_add_generic_settings(hwif->drives + unit);
-			hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
-			sprintf (name, "host%d/bus%d/target%d/lun%d",
-				 (hwif->channel && hwif->mate) ? hwif->mate->index : hwif->index,
-				 hwif->channel, unit, hwif->drives[unit].lun);
-			hwif->drives[unit].de =
-				devfs_mk_dir (ide_devfs_handle, name, NULL);
-		}
-#endif
 	}
 	return;
 
@@ -880,7 +1068,9 @@
 	return;
 }
 
-static int hwif_init (ide_hwif_t *hwif)
+EXPORT_SYMBOL(init_gendisk);
+
+int hwif_init (ide_hwif_t *hwif)
 {
 	if (!hwif->present)
 		return 0;
@@ -893,15 +1083,18 @@
 	}
 #ifdef CONFIG_BLK_DEV_HD
 	if (hwif->irq == HD_IRQ && hwif->io_ports[IDE_DATA_OFFSET] != HD_DATA) {
-		printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", hwif->name);
+		printk("%s: CANNOT SHARE IRQ WITH OLD "
+			"HARDDISK DRIVER (hd.c)\n", hwif->name);
 		return (hwif->present = 0);
 	}
 #endif /* CONFIG_BLK_DEV_HD */
-	
-	hwif->present = 0; /* we set it back to 1 if all is ok below */
+
+	/* we set it back to 1 if all is ok below */	
+	hwif->present = 0;
 
 	if (devfs_register_blkdev (hwif->major, hwif->name, ide_fops)) {
-		printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", hwif->name, hwif->major);
+		printk("%s: UNABLE TO GET MAJOR NUMBER %d\n",
+			hwif->name, hwif->major);
 		return (hwif->present = 0);
 	}
 	
@@ -912,14 +1105,15 @@
 		 *	this port and try that.
 		 */
 		if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) {
-			printk("%s: Disabled unable to get IRQ %d.\n", hwif->name, i);
-			(void) unregister_blkdev (hwif->major, hwif->name);
+			printk("%s: Disabled unable to get IRQ %d.\n",
+				hwif->name, i);
+			(void) unregister_blkdev(hwif->major, hwif->name);
 			return (hwif->present = 0);
 		}
 		if (init_irq(hwif)) {
 			printk("%s: probed IRQ %d and default IRQ %d failed.\n",
 				hwif->name, i, hwif->irq);
-			(void) unregister_blkdev (hwif->major, hwif->name);
+			(void) unregister_blkdev(hwif->major, hwif->name);
 			return (hwif->present = 0);
 		}
 		printk("%s: probed IRQ %d failed, using default.\n",
@@ -942,19 +1136,51 @@
 	return hwif->present;
 }
 
+EXPORT_SYMBOL(hwif_init);
+
 void export_ide_init_queue (ide_drive_t *drive)
 {
 	ide_init_queue(drive);
 }
 
-byte export_probe_for_drive (ide_drive_t *drive)
+EXPORT_SYMBOL(export_ide_init_queue);
+
+u8 export_probe_for_drive (ide_drive_t *drive)
 {
 	return probe_for_drive(drive);
 }
 
-EXPORT_SYMBOL(export_ide_init_queue);
 EXPORT_SYMBOL(export_probe_for_drive);
 
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+int probe_hwif_init (ide_hwif_t *hwif)
+{
+	hwif->initializing = 1;
+	probe_hwif(hwif);
+	hwif_init(hwif);
+
+#ifndef CLASSIC_BUILTINS_METHOD
+#  ifndef FAKE_CLASSIC_ATTACH_METHOD
+#    ifdef DIRECT_HWIF_PROBE_ATTACH_METHOD
+	if (hwif->present) {
+		u16 unit = 0;
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			ide_drive_t *drive = &hwif->drives[unit];
+			if (drive->present)
+				ide_attach_drive(drive);
+		}
+	}
+#    endif /* DIRECT_HWIF_PROBE_ATTACH_METHOD */
+#  endif /* FAKE_CLASSIC_ATTACH_METHOD */
+#endif /* CLASSIC_BUILTINS_METHOD */
+	hwif->initializing = 0;
+	return 0;
+}
+
+EXPORT_SYMBOL(probe_hwif_init);
+
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
 int ideprobe_init (void);
 static ide_module_t ideprobe_module = {
 	IDE_PROBE_MODULE,
@@ -975,12 +1201,20 @@
 	/*
 	 * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports
 	 */
+#ifdef HWIF_PROBE_CLASSIC_METHOD
 	for (index = 0; index < MAX_HWIFS; ++index)
 		if (probe[index])
 			probe_hwif(&ide_hwifs[index]);
+
 	for (index = 0; index < MAX_HWIFS; ++index)
 		if (probe[index])
 			hwif_init(&ide_hwifs[index]);
+#else /* HWIF_PROBE_CLASSIC_METHOD */
+	for (index = 0; index < MAX_HWIFS; ++index)
+		if (probe[index])
+			probe_hwif_init(&ide_hwifs[index]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
 	if (!ide_probe)
 		ide_probe = &ideprobe_module;
 	MOD_DEC_USE_COUNT;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-proc.c linux-2.4.21/drivers/ide/ide-proc.c
--- linux-2.4.20/drivers/ide/ide-proc.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-proc.c	2002-12-18 18:58:02.000000000 +0000
@@ -57,6 +57,9 @@
  */
 
 #include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+
 #include <asm/uaccess.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
@@ -74,59 +77,6 @@
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
 #endif
 
-#ifdef CONFIG_BLK_DEV_AEC62XX
-extern byte aec62xx_proc;
-int (*aec62xx_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_AEC62XX */
-#ifdef CONFIG_BLK_DEV_ALI15X3
-extern byte ali_proc;
-int (*ali_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_ALI15X3 */
-#ifdef CONFIG_BLK_DEV_AMD74XX
-extern byte amd74xx_proc;
-int (*amd74xx_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_AMD74XX */
-#ifdef CONFIG_BLK_DEV_CMD64X
-extern byte cmd64x_proc;
-int (*cmd64x_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_CMD64X */
-#ifdef CONFIG_BLK_DEV_CS5530
-extern byte cs5530_proc;
-int (*cs5530_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_CS5530 */
-#ifdef CONFIG_BLK_DEV_HPT34X
-extern byte hpt34x_proc;
-int (*hpt34x_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_HPT34X */
-#ifdef CONFIG_BLK_DEV_HPT366
-extern byte hpt366_proc;
-int (*hpt366_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_HPT366 */
-#ifdef CONFIG_BLK_DEV_PDC202XX
-extern byte pdc202xx_proc;
-int (*pdc202xx_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_PDC202XX */
-#ifdef CONFIG_BLK_DEV_PIIX
-extern byte piix_proc;
-int (*piix_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_PIIX */
-#ifdef CONFIG_BLK_DEV_SVWKS
-extern byte svwks_proc;
-int (*svwks_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_SVWKS */
-#ifdef CONFIG_BLK_DEV_SIS5513
-extern byte sis_proc;
-int (*sis_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_SIS5513 */
-#ifdef CONFIG_BLK_DEV_SLC90E66
-extern byte slc90e66_proc;
-int (*slc90e66_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_SLC90E66 */
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-extern byte via_proc;
-int (*via_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_VIA82CXXX */
-
 static int ide_getxdigit(char c)
 {
 	int digit;
@@ -160,6 +110,17 @@
 
 static struct proc_dir_entry * proc_ide_root = NULL;
 
+#ifdef CONFIG_BLK_DEV_IDEPCI
+#include <linux/delay.h>
+/*
+ * This is the list of registered PCI chipset driver data structures.
+ */
+static ide_pci_host_proc_t * ide_pci_host_proc_list;
+
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
+#undef __PROC_HELL
+
 static int proc_ide_write_config
 	(struct file *file, const char *buffer, unsigned long count, void *data)
 {
@@ -181,7 +142,11 @@
 	 * Do one full pass to verify all parameters,
 	 * then do another to actually write the regs.
 	 */
+#ifndef __PROC_HELL
 	save_flags(flags);	/* all CPUs */
+#else
+	spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	do {
 		const char *p;
 		if (for_real) {
@@ -190,15 +155,32 @@
 			ide_hwgroup_t *mategroup = NULL;
 			if (hwif->mate && hwif->mate->hwgroup)
 				mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup);
+#ifndef __PROC_HELL
 			cli();	/* all CPUs; ensure all writes are done together */
-			while (mygroup->busy || (mategroup && mategroup->busy)) {
+#else
+			spin_lock_irqsave(&io_request_lock, flags);
+#endif
+			while (mygroup->busy ||
+			       (mategroup && mategroup->busy)) {
+#ifndef __PROC_HELL
 				sti();	/* all CPUs */
-				if (0 < (signed long)(jiffies - timeout)) {
+#else
+				spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+				if (time_after(jiffies, timeout)) {
 					printk("/proc/ide/%s/config: channel(s) busy, cannot write\n", hwif->name);
+#ifndef __PROC_HELL
 					restore_flags(flags);	/* all CPUs */
+#else
+					spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 					return -EBUSY;
 				}
+#ifndef __PROC_HELL
 				cli();	/* all CPUs */
+#else
+				spin_lock_irqsave(&io_request_lock, flags);
+#endif
 			}
 		}
 		p = buffer;
@@ -213,7 +195,7 @@
 						break;
 				case 'P':	is_pci = 1;
 #ifdef CONFIG_BLK_DEV_IDEPCI
-						if (hwif->pci_dev && !IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL))
+						if (hwif->pci_dev && !hwif->pci_dev->vendor)
 							break;
 #endif	/* CONFIG_BLK_DEV_IDEPCI */
 						msg = "not a PCI device";
@@ -281,7 +263,11 @@
 							break;
 					}
 					if (rc) {
+#ifndef __PROC_HELL
 						restore_flags(flags);	/* all CPUs */
+#else
+						spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 						printk("proc_ide_write_config: error writing %s at bus %02x dev %02x reg 0x%x value 0x%x\n",
 							msg, dev->bus->number, dev->devfn, reg, val);
 						printk("proc_ide_write_config: error %d\n", rc);
@@ -311,11 +297,11 @@
  * 
  */
 					switch (digits) {
-						case 2:	outb(val, reg);
+						case 2:	hwif->OUTB(val, reg);
 							break;
-						case 4:	outw(val, reg);
+						case 4:	hwif->OUTW(val, reg);
 							break;
-						case 8:	outl(val, reg);
+						case 8:	hwif->OUTL(val, reg);
 							break;
 					}
 #endif /* !__mc68000__ && !CONFIG_APUS */
@@ -323,15 +309,23 @@
 			}
 		}
 	} while (!for_real++);
+#ifndef __PROC_HELL
 	restore_flags(flags);	/* all CPUs */
+#else
+	spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	return count;
 parse_error:
+#ifndef __PROC_HELL
 	restore_flags(flags);	/* all CPUs */
+#else
+	spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	printk("parse error\n");
 	return xx_xx_parse_error(start, startn, msg);
 }
 
-static int proc_ide_read_config
+int proc_ide_read_config
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	char		*out = page;
@@ -340,20 +334,26 @@
 #ifdef CONFIG_BLK_DEV_IDEPCI
 	ide_hwif_t	*hwif = (ide_hwif_t *)data;
 	struct pci_dev	*dev = hwif->pci_dev;
-	if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL) && dev && dev->bus) {
+	if ((hwif->pci_dev && hwif->pci_dev->vendor) && dev && dev->bus) {
 		int reg = 0;
 
-		out += sprintf(out, "pci bus %02x device %02x vid %04x did %04x channel %d\n",
-			dev->bus->number, dev->devfn, hwif->pci_devid.vid, hwif->pci_devid.did, hwif->channel);
+		out += sprintf(out, "pci bus %02x device %02x vendor %04x "
+				"device %04x channel %d\n",
+			dev->bus->number, dev->devfn,
+			hwif->pci_dev->vendor, hwif->pci_dev->device,
+			hwif->channel);
 		do {
-			byte val;
+			u8 val;
 			int rc = pci_read_config_byte(dev, reg, &val);
 			if (rc) {
-				printk("proc_ide_read_config: error %d reading bus %02x dev %02x reg 0x%02x\n",
+				printk("proc_ide_read_config: error %d reading"
+					" bus %02x dev %02x reg 0x%02x\n",
 					rc, dev->bus->number, dev->devfn, reg);
-				out += sprintf(out, "??%c", (++reg & 0xf) ? ' ' : '\n');
+				out += sprintf(out, "??%c",
+					(++reg & 0xf) ? ' ' : '\n');
 			} else
-				out += sprintf(out, "%02x%c", val, (++reg & 0xf) ? ' ' : '\n');
+				out += sprintf(out, "%02x%c",
+					val, (++reg & 0xf) ? ' ' : '\n');
 		} while (reg < 0x100);
 	} else
 #endif	/* CONFIG_BLK_DEV_IDEPCI */
@@ -362,6 +362,7 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+EXPORT_SYMBOL(proc_ide_read_config);
 
 static int ide_getdigit(char c)
 {
@@ -373,7 +374,7 @@
 	return digit;
 }
 
-static int proc_ide_read_drivers
+int proc_ide_read_drivers
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	char		*out = page;
@@ -384,14 +385,17 @@
 	while (p) {
 		driver = (ide_driver_t *) p->info;
 		if (driver)
-			out += sprintf(out, "%s version %s\n", driver->name, driver->version);
+			out += sprintf(out, "%s version %s\n",
+				driver->name, driver->version);
 		p = p->next;
 	}
 	len = out - page;
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_imodel
+EXPORT_SYMBOL(proc_ide_read_drivers);
+
+int proc_ide_read_imodel
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_hwif_t	*hwif = (ide_hwif_t *) data;
@@ -421,7 +425,9 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_mate
+EXPORT_SYMBOL(proc_ide_read_imodel);
+
+int proc_ide_read_mate
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_hwif_t	*hwif = (ide_hwif_t *) data;
@@ -434,7 +440,9 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_channel
+EXPORT_SYMBOL(proc_ide_read_mate);
+
+int proc_ide_read_channel
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_hwif_t	*hwif = (ide_hwif_t *) data;
@@ -446,31 +454,21 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_get_identify(ide_drive_t *drive, byte *buf)
-{
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-
-	taskfile.sector_count = 0x01;
-	taskfile.command = (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY ;
-
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
-}
+EXPORT_SYMBOL(proc_ide_read_channel);
 
-static int proc_ide_read_identify
+int proc_ide_read_identify
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *)data;
 	int		len = 0, i = 0;
 
-	if (drive && !proc_ide_get_identify(drive, page)) {
+	if (drive && !taskfile_lib_get_identify(drive, page)) {
 		unsigned short *val = (unsigned short *) page;
 		char *out = ((char *)val) + (SECTOR_WORDS * 4);
 		page = out;
 		do {
-			out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
+			out += sprintf(out, "%04x%c",
+				le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
 			val += 1;
 		} while (i < (SECTOR_WORDS * 2));
 		len = out - page;
@@ -480,7 +478,9 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_settings
+EXPORT_SYMBOL(proc_ide_read_identify);
+
+int proc_ide_read_settings
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
@@ -510,9 +510,11 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+EXPORT_SYMBOL(proc_ide_read_settings);
+
 #define MAX_LEN	30
 
-static int proc_ide_write_settings
+int proc_ide_write_settings
 	(struct file *file, const char *buffer, unsigned long count, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
@@ -587,6 +589,8 @@
 	return -EINVAL;
 }
 
+EXPORT_SYMBOL(proc_ide_write_settings);
+
 int proc_ide_read_capacity
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -598,10 +602,12 @@
 		len = sprintf(page, "(none)\n");
         else
 		len = sprintf(page,"%llu\n",
-			      (unsigned long long) ((ide_driver_t *)drive->driver)->capacity(drive));
+			      (u64) ((ide_driver_t *)drive->driver)->capacity(drive));
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+EXPORT_SYMBOL(proc_ide_read_capacity);
+
 int proc_ide_read_geometry
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -609,24 +615,32 @@
 	char		*out = page;
 	int		len;
 
-	out += sprintf(out,"physical     %d/%d/%d\n", drive->cyl, drive->head, drive->sect);
-	out += sprintf(out,"logical      %d/%d/%d\n", drive->bios_cyl, drive->bios_head, drive->bios_sect);
+	out += sprintf(out,"physical     %d/%d/%d\n",
+			drive->cyl, drive->head, drive->sect);
+	out += sprintf(out,"logical      %d/%d/%d\n",
+			drive->bios_cyl, drive->bios_head, drive->bios_sect);
+
 	len = out - page;
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_dmodel
+EXPORT_SYMBOL(proc_ide_read_geometry);
+
+int proc_ide_read_dmodel
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
 	struct hd_driveid *id = drive->id;
 	int		len;
 
-	len = sprintf(page, "%.40s\n", (id && id->model[0]) ? (char *)id->model : "(none)");
+	len = sprintf(page, "%.40s\n",
+		(id && id->model[0]) ? (char *)id->model : "(none)");
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_driver
+EXPORT_SYMBOL(proc_ide_read_dmodel);
+
+int proc_ide_read_driver
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
@@ -636,11 +650,14 @@
 	if (!driver)
 		len = sprintf(page, "(none)\n");
 	else
-		len = sprintf(page, "%s version %s\n", driver->name, driver->version);
+		len = sprintf(page, "%s version %s\n",
+			driver->name, driver->version);
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_write_driver
+EXPORT_SYMBOL(proc_ide_read_driver);
+
+int proc_ide_write_driver
 	(struct file *file, const char *buffer, unsigned long count, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
@@ -652,7 +669,9 @@
 	return count;
 }
 
-static int proc_ide_read_media
+EXPORT_SYMBOL(proc_ide_write_driver);
+
+int proc_ide_read_media
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
@@ -676,6 +695,8 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+EXPORT_SYMBOL(proc_ide_read_media);
+
 static ide_proc_entry_t generic_drive_entries[] = {
 	{ "driver",	S_IFREG|S_IRUGO,	proc_ide_read_driver,	proc_ide_write_driver },
 	{ "identify",	S_IFREG|S_IRUSR,	proc_ide_read_identify,	NULL },
@@ -702,6 +723,8 @@
 	}
 }
 
+EXPORT_SYMBOL(ide_add_proc_entries);
+
 void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
 {
 	if (!dir || !p)
@@ -712,7 +735,9 @@
 	}
 }
 
-static void create_proc_ide_drives(ide_hwif_t *hwif)
+EXPORT_SYMBOL(ide_remove_proc_entries);
+
+void create_proc_ide_drives(ide_hwif_t *hwif)
 {
 	int	d;
 	struct proc_dir_entry *ent;
@@ -742,6 +767,8 @@
 	}
 }
 
+EXPORT_SYMBOL(create_proc_ide_drives);
+
 void recreate_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
 {
 	struct proc_dir_entry *ent;
@@ -769,6 +796,8 @@
 	}
 }
 
+EXPORT_SYMBOL(recreate_proc_ide_device);
+
 void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
 {
 	ide_driver_t *driver = drive->driver;
@@ -783,19 +812,21 @@
 	}
 }
 
+EXPORT_SYMBOL(destroy_proc_ide_device);
+
 void destroy_proc_ide_drives(ide_hwif_t *hwif)
 {
 	int	d;
 
 	for (d = 0; d < MAX_DRIVES; d++) {
 		ide_drive_t *drive = &hwif->drives[d];
-//		ide_driver_t *driver = drive->driver;
-
 		if (drive->proc)
 			destroy_proc_ide_device(hwif, drive);
 	}
 }
 
+EXPORT_SYMBOL(destroy_proc_ide_drives);
+
 static ide_proc_entry_t hwif_entries[] = {
 	{ "channel",	S_IFREG|S_IRUGO,	proc_ide_read_channel,	NULL },
 	{ "config",	S_IFREG|S_IRUGO|S_IWUSR,proc_ide_read_config,	proc_ide_write_config },
@@ -823,7 +854,9 @@
 	}
 }
 
-static void destroy_proc_ide_interfaces(void)
+EXPORT_SYMBOL(create_proc_ide_interfaces);
+
+void destroy_proc_ide_interfaces(void)
 {
 	int	h;
 
@@ -844,8 +877,34 @@
 	}
 }
 
+EXPORT_SYMBOL(destroy_proc_ide_interfaces);
+
+#ifdef CONFIG_BLK_DEV_IDEPCI
+void ide_pci_register_host_proc (ide_pci_host_proc_t *p)
+{
+	ide_pci_host_proc_t *tmp;
+
+	if (!p) return;
+	p->next = NULL;
+	p->set = 1;
+	if (ide_pci_host_proc_list) {
+		tmp = ide_pci_host_proc_list;
+		while (tmp->next) tmp = tmp->next;
+		tmp->next = p;
+	} else
+		ide_pci_host_proc_list = p;
+}
+
+EXPORT_SYMBOL(ide_pci_register_host_proc);
+
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
 void proc_ide_create(void)
 {
+#ifdef CONFIG_BLK_DEV_IDEPCI
+	ide_pci_host_proc_t *p = ide_pci_host_proc_list;
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
 	proc_ide_root = proc_mkdir("ide", 0);
 	if (!proc_ide_root) return;
 
@@ -854,120 +913,40 @@
 	create_proc_read_entry("drivers", 0, proc_ide_root,
 				proc_ide_read_drivers, NULL);
 
-#ifdef CONFIG_BLK_DEV_AEC62XX
-	if ((aec62xx_display_info) && (aec62xx_proc))
-		create_proc_info_entry("aec62xx", 0, proc_ide_root, aec62xx_display_info);
-#endif /* CONFIG_BLK_DEV_AEC62XX */
-#ifdef CONFIG_BLK_DEV_ALI15X3
-	if ((ali_display_info) && (ali_proc))
-		create_proc_info_entry("ali", 0, proc_ide_root, ali_display_info);
-#endif /* CONFIG_BLK_DEV_ALI15X3 */
-#ifdef CONFIG_BLK_DEV_AMD74XX
-	if ((amd74xx_display_info) && (amd74xx_proc))
-		create_proc_info_entry("amd74xx", 0, proc_ide_root, amd74xx_display_info);
-#endif /* CONFIG_BLK_DEV_AMD74XX */
-#ifdef CONFIG_BLK_DEV_CMD64X
-	if ((cmd64x_display_info) && (cmd64x_proc))
-		create_proc_info_entry("cmd64x", 0, proc_ide_root, cmd64x_display_info);
-#endif /* CONFIG_BLK_DEV_CMD64X */
-#ifdef CONFIG_BLK_DEV_CS5530
-	if ((cs5530_display_info) && (cs5530_proc))
-		create_proc_info_entry("cs5530", 0, proc_ide_root, cs5530_display_info);
-#endif /* CONFIG_BLK_DEV_CS5530 */
-#ifdef CONFIG_BLK_DEV_HPT34X
-	if ((hpt34x_display_info) && (hpt34x_proc))
-		create_proc_info_entry("hpt34x", 0, proc_ide_root, hpt34x_display_info);
-#endif /* CONFIG_BLK_DEV_HPT34X */
-#ifdef CONFIG_BLK_DEV_HPT366
-	if ((hpt366_display_info) && (hpt366_proc))
-		create_proc_info_entry("hpt366", 0, proc_ide_root, hpt366_display_info);
-#endif /* CONFIG_BLK_DEV_HPT366 */
-#ifdef CONFIG_BLK_DEV_SVWKS
-	if ((svwks_display_info) && (svwks_proc))
-		create_proc_info_entry("svwks", 0, proc_ide_root, svwks_display_info);
-#endif /* CONFIG_BLK_DEV_SVWKS */
-#ifdef CONFIG_BLK_DEV_PDC202XX
-	if ((pdc202xx_display_info) && (pdc202xx_proc))
-		create_proc_info_entry("pdc202xx", 0, proc_ide_root, pdc202xx_display_info);
-#endif /* CONFIG_BLK_DEV_PDC202XX */
-#ifdef CONFIG_BLK_DEV_PIIX
-	if ((piix_display_info) && (piix_proc))
-		create_proc_info_entry("piix", 0, proc_ide_root, piix_display_info);
-#endif /* CONFIG_BLK_DEV_PIIX */
-#ifdef CONFIG_BLK_DEV_SIS5513
-	if ((sis_display_info) && (sis_proc))
-		create_proc_info_entry("sis", 0, proc_ide_root, sis_display_info);
-#endif /* CONFIG_BLK_DEV_SIS5513 */
-#ifdef CONFIG_BLK_DEV_SLC90E66
-	if ((slc90e66_display_info) && (slc90e66_proc))
-		create_proc_info_entry("slc90e66", 0, proc_ide_root, slc90e66_display_info);
-#endif /* CONFIG_BLK_DEV_SLC90E66 */
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-	if ((via_display_info) && (via_proc))
-		create_proc_info_entry("via", 0, proc_ide_root, via_display_info);
-#endif /* CONFIG_BLK_DEV_VIA82CXXX */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+	while (p != NULL)
+	{
+		if (p->name != NULL && p->set == 1 && p->get_info != NULL) 
+		{
+			p->parent = proc_ide_root;
+			create_proc_info_entry(p->name, 0, p->parent, p->get_info);
+			p->set = 2;
+		}
+		p = p->next;
+	}
+#endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
+EXPORT_SYMBOL(proc_ide_create);
+
 void proc_ide_destroy(void)
 {
-	/*
-	 * Mmmm.. does this free up all resources,
-	 * or do we need to do a more proper cleanup here ??
-	 */
-#ifdef CONFIG_BLK_DEV_AEC62XX
-	if ((aec62xx_display_info) && (aec62xx_proc))
-		remove_proc_entry("ide/aec62xx",0);
-#endif /* CONFIG_BLK_DEV_AEC62XX */
-#ifdef CONFIG_BLK_DEV_ALI15X3
-	if ((ali_display_info) && (ali_proc))
-		remove_proc_entry("ide/ali",0);
-#endif /* CONFIG_BLK_DEV_ALI15X3 */
-#ifdef CONFIG_BLK_DEV_AMD74XX
-	if ((amd74xx_display_info) && (amd74xx_proc))
-		remove_proc_entry("ide/amd74xx",0);
-#endif /* CONFIG_BLK_DEV_AMD74XX */
-#ifdef CONFIG_BLK_DEV_CMD64X
-	if ((cmd64x_display_info) && (cmd64x_proc))
-		remove_proc_entry("ide/cmd64x",0);
-#endif /* CONFIG_BLK_DEV_CMD64X */
-#ifdef CONFIG_BLK_DEV_CS5530
-	if ((cs5530_display_info) && (cs5530_proc))
-		remove_proc_entry("ide/cs5530",0);
-#endif /* CONFIG_BLK_DEV_CS5530 */
-#ifdef CONFIG_BLK_DEV_HPT34X
-	if ((hpt34x_display_info) && (hpt34x_proc))
-		remove_proc_entry("ide/hpt34x",0);
-#endif /* CONFIG_BLK_DEV_HPT34X */
-#ifdef CONFIG_BLK_DEV_HPT366
-	if ((hpt366_display_info) && (hpt366_proc))
-		remove_proc_entry("ide/hpt366",0);
-#endif /* CONFIG_BLK_DEV_HPT366 */
-#ifdef CONFIG_BLK_DEV_PDC202XX
-	if ((pdc202xx_display_info) && (pdc202xx_proc))
-		remove_proc_entry("ide/pdc202xx",0);
-#endif /* CONFIG_BLK_DEV_PDC202XX */
-#ifdef CONFIG_BLK_DEV_PIIX
-	if ((piix_display_info) && (piix_proc))
-		remove_proc_entry("ide/piix",0);
-#endif /* CONFIG_BLK_DEV_PIIX */
-#ifdef CONFIG_BLK_DEV_SVWKS
-	if ((svwks_display_info) && (svwks_proc))
-		remove_proc_entry("ide/svwks",0);
-#endif /* CONFIG_BLK_DEV_SVWKS */
-#ifdef CONFIG_BLK_DEV_SIS5513
-	if ((sis_display_info) && (sis_proc))
-		remove_proc_entry("ide/sis", 0);
-#endif /* CONFIG_BLK_DEV_SIS5513 */
-#ifdef CONFIG_BLK_DEV_SLC90E66
-	if ((slc90e66_display_info) && (slc90e66_proc))
-		remove_proc_entry("ide/slc90e66",0);
-#endif /* CONFIG_BLK_DEV_SLC90E66 */
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-	if ((via_display_info) && (via_proc))
-		remove_proc_entry("ide/via",0);
-#endif /* CONFIG_BLK_DEV_VIA82CXXX */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+	ide_pci_host_proc_t *p = ide_pci_host_proc_list;
+	char name[32];
 
-	remove_proc_entry("ide/drivers", 0);
+	while ((p->name != NULL) && (p->set) && (p->get_info != NULL)) {
+		name[0] = '\0';
+		sprintf(name, "ide/%s", p->name);
+		if (p->set == 2)
+			remove_proc_entry(p->name, p->parent);
+		if (p->next == NULL) break;
+		p = p->next;
+	}
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+	remove_proc_entry("ide/drivers", proc_ide_root);
 	destroy_proc_ide_interfaces();
 	remove_proc_entry("ide", 0);
 }
+
+EXPORT_SYMBOL(proc_ide_destroy);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-sibyte.c linux-2.4.21/drivers/ide/ide-sibyte.c
--- linux-2.4.20/drivers/ide/ide-sibyte.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-sibyte.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,333 +0,0 @@
-/*
- * Copyright (C) 2001 Broadcom 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.  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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-/*  Derived loosely from ide-pmac.c, so:
- *  
- *  Copyright (C) 1998 Paul Mackerras.
- *  Copyright (C) 1995-1998 Mark Lord
- */
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/sibyte/sb1250_regs.h>
-#include <asm/sibyte/sb1250_int.h>
-#include <asm/sibyte/sb1250_genbus.h>
-#include <asm/sibyte/64bit.h>
-#include <asm/sibyte/board.h>
-
-/* Note: this should be general for any board using IDE on GenBus */
-
-extern struct ide_ops std_ide_ops;
-
-static ide_hwif_t *sb_ide_hwif = NULL;
-static unsigned long ide_base;
-
-#define SIBYTE_IDE_BASE        (KSEG1ADDR(ide_base)-mips_io_port_base)
-#define SIBYTE_IDE_REG(pcaddr) (SIBYTE_IDE_BASE + ((pcaddr)<<5))
-
-/*
- * We are limiting the number of PCI-IDE devices to leave room for
- * GenBus IDE (and possibly PCMCIA/CF?)
- */
-static int sibyte_ide_default_irq(ide_ioreg_t base)
-{
-	return 0;
-}
-
-static ide_ioreg_t sibyte_ide_default_io_base(int index)
-{
-	return 0;
-}
-
-static void sibyte_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port,
-				       ide_ioreg_t ctrl_port, int *irq)
-{
-	std_ide_ops.ide_init_hwif_ports(hw, data_port, ctrl_port, irq);
-}
-
-static int sibyte_ide_request_irq(unsigned int irq,
-                                void (*handler)(int,void *, struct pt_regs *),
-                                unsigned long flags, const char *device,
-                                void *dev_id)
-{
-	return request_irq(irq, handler, flags, device, dev_id);
-}
-
-static void sibyte_ide_free_irq(unsigned int irq, void *dev_id)
-{
-	free_irq(irq, dev_id);
-}
-
-static inline int is_sibyte_ide(ide_ioreg_t from)
-{
-	return (sb_ide_hwif &&
-		((from == sb_ide_hwif->io_ports[IDE_DATA_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_ERROR_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_NSECTOR_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_SECTOR_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_LCYL_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_HCYL_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_SELECT_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_STATUS_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_CONTROL_OFFSET])));
-}
-
-static int sibyte_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-	/* Figure out if it's the SiByte IDE; if so, don't do anything
-           since our I/O space is in a weird place. */
-	if (is_sibyte_ide(from))
-		return 0;
-	else
-#ifdef CONFIG_BLK_DEV_IDE
-		return std_ide_ops.ide_check_region(from, extent);
-#else
-		return 0;
-#endif
-}
-
-static void sibyte_ide_request_region(ide_ioreg_t from, unsigned int extent,
-				     const char *name)
-{
-#ifdef CONFIG_BLK_DEV_IDE
-	if (!is_sibyte_ide(from))
-		std_ide_ops.ide_request_region(from, extent, name);
-#endif
-}
-
-static void sibyte_ide_release_region(ide_ioreg_t from, unsigned int extent)
-{
-#ifdef CONFIG_BLK_DEV_IDE
-	if (!is_sibyte_ide(from))
-		std_ide_ops.ide_release_region(from, extent);
-#endif
-}
-
-struct ide_ops sibyte_ide_ops = {
-	&sibyte_ide_default_irq,
-	&sibyte_ide_default_io_base,
-	&sibyte_ide_init_hwif_ports,
-	&sibyte_ide_request_irq,
-	&sibyte_ide_free_irq,
-	&sibyte_ide_check_region,
-	&sibyte_ide_request_region,
-	&sibyte_ide_release_region
-};
-
-/*
- * I/O operations. The FPGA for SiByte generic bus IDE deals with
- * byte-swapping for us, so we can't share the I/O macros with other
- * IDE (e.g. PCI-IDE) devices.
- */
-
-#define sibyte_outb(val,port)					\
-do {								\
-	*(volatile u8 *)(mips_io_port_base + (port)) = val;	\
-} while(0)
-
-#define sibyte_outw(val,port)					\
-do {								\
-	*(volatile u16 *)(mips_io_port_base + (port)) = val;	\
-} while(0)
-
-#define sibyte_outl(val,port)					\
-do {								\
-	*(volatile u32 *)(mips_io_port_base + (port)) = val;	\
-} while(0)
-
-static inline unsigned char sibyte_inb(unsigned long port)
-{
-	return (*(volatile u8 *)(mips_io_port_base + (port)));
-}
-
-static inline unsigned short sibyte_inw(unsigned long port)
-{
-	return (*(volatile u16 *)(mips_io_port_base + (port)));
-}
-
-static inline unsigned int sibyte_inl(unsigned long port)
-{
-	return (*(volatile u32 *)(mips_io_port_base + (port)));
-}
-
-
-static inline void sibyte_outsb(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		sibyte_outb(*(u8 *)addr, port);
-		addr++;
-	}
-}
-
-static inline void sibyte_insb(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		*(u8 *)addr = sibyte_inb(port);
-		addr++;
-	}
-}
-
-static inline void sibyte_outsw(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		sibyte_outw(*(u16 *)addr, port);
-		addr += 2;
-	}
-}
-
-static inline void sibyte_insw(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		*(u16 *)addr = sibyte_inw(port);
-		addr += 2;
-	}
-}
-
-static inline void sibyte_outsl(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		sibyte_outl(*(u32 *)addr, port);
-		addr += 4;
-	}
-}
-
-static inline void sibyte_insl(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		*(u32 *)addr = sibyte_inl(port);
-		addr += 4;
-	}
-}
-
-static void sibyte_ideproc(ide_ide_action_t action, ide_drive_t *drive,
-			   void *buffer, unsigned int count)
-{
-	/*  slow? vlb_sync? */
-	switch (action) {
-	case ideproc_ide_input_data:
-		if (drive->io_32bit) {
-			sibyte_insl(IDE_DATA_REG, buffer, count);
-		} else {
-			sibyte_insw(IDE_DATA_REG, buffer, count<<1);
-		}
-		break;
-	case ideproc_ide_output_data:
-		if (drive->io_32bit) {
-			sibyte_outsl(IDE_DATA_REG, buffer, count);
-		} else {
-			sibyte_outsw(IDE_DATA_REG, buffer, count<<1);
-		}
-		break;
-	case ideproc_atapi_input_bytes:
-		count++;
-		if (drive->io_32bit) {
-			sibyte_insl(IDE_DATA_REG, buffer, count>>2);
-		} else {
-			sibyte_insw(IDE_DATA_REG, buffer, count>>1);
-		}
-		if ((count & 3) >= 2)
-			sibyte_insw(IDE_DATA_REG, (char *)buffer + (count & ~3), 1);
-		break;
-	case ideproc_atapi_output_bytes:
-		count++;
-		if (drive->io_32bit) {
-			sibyte_outsl(IDE_DATA_REG, buffer, count>>2);
-		} else {
-			sibyte_outsw(IDE_DATA_REG, buffer, count>>1);
-		}
-		if ((count & 3) >= 2)
-			sibyte_outsw(IDE_DATA_REG, (char *)buffer + (count & ~3), 1);
-		break;
-	}
-}
-
-/*
- * selectproc and intrproc aren't really necessary, since
- * byte-swapping doesn't affect byte ops; they are included for
- * consistency.
- */
-static void sibyte_selectproc(ide_drive_t *drive)
-{
-	sibyte_outb(drive->select.all, IDE_SELECT_REG);
-}
-
-static void sibyte_intrproc(ide_drive_t *drive)
-{
-	sibyte_outb(drive->ctl|2, IDE_CONTROL_REG);
-}
-
-void __init sibyte_ide_probe(void)
-{
-	int i;
-	ide_hwif_t *hwif;
-	/* 
-	 * Find the first untaken slot in hwifs 
-	 */
-	for (i = 0; i < MAX_HWIFS; i++) {
-		if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET]) {
-			break;
-		}
-	}
-	if (i == MAX_HWIFS) {
-		printk("No space for SiByte onboard IDE driver in ide_hwifs[].  Not enabled.\n");
-		return;
-	}
-
-	/* Find memory base address */
-#ifdef __MIPSEL__
-	/* Pass1 workaround (bug 1624) */
-	if (sb1250_pass == K_SYS_REVISION_PASS1)
-		ide_base = G_IO_START_ADDR(csr_in32(4+(IO_SPACE_BASE|A_IO_EXT_REG(R_IO_EXT_REG(R_IO_EXT_START_ADDR, IDE_CS))))) << S_IO_ADDRBASE;
-	else
-#endif
-		ide_base = G_IO_START_ADDR(csr_in32(IO_SPACE_BASE|A_IO_EXT_REG(R_IO_EXT_REG(R_IO_EXT_START_ADDR, IDE_CS)))) << S_IO_ADDRBASE;
-
-	/*
-	 * Set up our stuff; we're a little odd because our io_ports
-	 * aren't in the usual place, and byte-swapping isn't
-	 * necessary.
-	 */
-	hwif = &ide_hwifs[i];
-	hwif->hw.io_ports[IDE_DATA_OFFSET]    = SIBYTE_IDE_REG(0x1f0);
-	hwif->hw.io_ports[IDE_ERROR_OFFSET]   = SIBYTE_IDE_REG(0x1f1);
-	hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SIBYTE_IDE_REG(0x1f2);
-	hwif->hw.io_ports[IDE_SECTOR_OFFSET]  = SIBYTE_IDE_REG(0x1f3);
-	hwif->hw.io_ports[IDE_LCYL_OFFSET]    = SIBYTE_IDE_REG(0x1f4);
-	hwif->hw.io_ports[IDE_HCYL_OFFSET]    = SIBYTE_IDE_REG(0x1f5);
-	hwif->hw.io_ports[IDE_SELECT_OFFSET]  = SIBYTE_IDE_REG(0x1f6);
-	hwif->hw.io_ports[IDE_STATUS_OFFSET]  = SIBYTE_IDE_REG(0x1f7);
-	hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SIBYTE_IDE_REG(0x3f6);
-	hwif->hw.irq                          = K_INT_GB_IDE;
-	hwif->irq                             = K_INT_GB_IDE;
-	hwif->noprobe                         = 0;
-	/* Use our own non-byte-swapping routines */
-	hwif->ideproc                         = sibyte_ideproc;
-	hwif->selectproc                      = sibyte_selectproc;
-	hwif->intrproc                        = sibyte_intrproc;
-
-	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-	printk("SiByte onboard IDE configured as device %i\n", i);
-	sb_ide_hwif = hwif;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-tape.c linux-2.4.21/drivers/ide/ide-tape.c
--- linux-2.4.20/drivers/ide/ide-tape.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-tape.c	2002-12-18 18:58:04.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/ide-tape.c		Version 1.17a	Jan, 2001
+ * linux/drivers/ide/ide-tape.c		Version 1.17b	Dec, 2002
  *
  * Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il>
  *
@@ -291,6 +291,28 @@
  * Ver 1.17a Apr 2001 Willem Riede osst@riede.org
  * 			- Get drive's actual block size from mode sense block descriptor
  * 			- Limit size of pipeline
+ * Ver 1.17b Dec 2002   Alan Stern <stern@rowland.harvard.edu>
+ *			Changed IDETAPE_MIN_PIPELINE_STAGES to 1 and actually used
+ *			 it in the code!
+ *			Actually removed aborted stages in idetape_abort_pipeline
+ *			 instead of just changing the command code.
+ *			Made the transfer byte count for Request Sense equal to the
+ *			 actual length of the data transfer.
+ *			Changed handling of partial data transfers: they do not
+ *			 cause DMA errors.
+ *			Moved initiation of DMA transfers to the correct place.
+ *			Removed reference to unallocated memory.
+ *			Made __idetape_discard_read_pipeline return the number of
+ *			 sectors skipped, not the number of stages.
+ *			Replaced errant kfree() calls with __idetape_kfree_stage().
+ *			Fixed off-by-one error in testing the pipeline length.
+ *			Fixed handling of filemarks in the read pipeline.
+ *			Small code optimization for MTBSF and MTBSFM ioctls.
+ *			Don't try to unlock the door during device close if is
+ *			 already unlocked!
+ *			Cosmetic fixes to miscellaneous debugging output messages.
+ *			Set the minimum /proc/ide/hd?/settings values for "pipeline",
+ *			 "pipeline_min", and "pipeline_max" to 1.
  *
  * Here are some words from the first releases of hd.c, which are quoted
  * in ide.c and apply here as well:
@@ -400,7 +422,7 @@
  *		sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
  */
 
-#define IDETAPE_VERSION "1.17a"
+#define IDETAPE_VERSION "1.17b"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -416,7 +438,6 @@
 #include <linux/errno.h>
 #include <linux/genhd.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/ide.h>
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
@@ -577,9 +598,10 @@
  *	whenever we sense that the pipeline is empty, until we reach
  *	the optimum value or until we reach MAX.
  *
- *	Setting the following parameter to 0 will disable the pipelined mode.
+ *	Setting the following parameter to 0 is illegal: the pipelined mode
+ *	cannot be disabled (calculate_speeds() divides by tape->max_stages.)
  */
-#define IDETAPE_MIN_PIPELINE_STAGES	200
+#define IDETAPE_MIN_PIPELINE_STAGES	  1
 #define IDETAPE_MAX_PIPELINE_STAGES	400
 #define IDETAPE_INCREASE_STAGES_RATE	 20
 
@@ -601,8 +623,8 @@
  *	is verified to be stable enough. This will make it much more
  *	esthetic.
  */
-#define IDETAPE_DEBUG_INFO		1
-#define IDETAPE_DEBUG_LOG		1
+#define IDETAPE_DEBUG_INFO		0
+#define IDETAPE_DEBUG_LOG		0
 #define IDETAPE_DEBUG_LOG_VERBOSE	0
 #define IDETAPE_DEBUG_BUGS		1
 
@@ -724,22 +746,28 @@
 	struct buffer_head *bh;
 	char *b_data;
 	int b_count;
-	byte *buffer;				/* Data buffer */
-	byte *current_position;			/* Pointer into the above buffer */
+	u8 *buffer;				/* Data buffer */
+	u8 *current_position;			/* Pointer into the above buffer */
 	ide_startstop_t (*callback) (ide_drive_t *);	/* Called when this packet command is completed */
-	byte pc_buffer[IDETAPE_PC_BUFFER_SIZE];	/* Temporary buffer */
+	u8 pc_buffer[IDETAPE_PC_BUFFER_SIZE];	/* Temporary buffer */
 	unsigned long flags;			/* Status/Action bit flags: long for set_bit */
 } idetape_pc_t;
 
 /*
  *	Packet command flag bits.
  */
-#define	PC_ABORT			0	/* Set when an error is considered normal - We won't retry */
-#define PC_WAIT_FOR_DSC			1	/* 1 When polling for DSC on a media access command */
-#define PC_DMA_RECOMMENDED		2	/* 1 when we prefer to use DMA if possible */
-#define	PC_DMA_IN_PROGRESS		3	/* 1 while DMA in progress */
-#define	PC_DMA_ERROR			4	/* 1 when encountered problem during DMA */
-#define	PC_WRITING			5	/* Data direction */
+/* Set when an error is considered normal - We won't retry */
+#define	PC_ABORT			0
+/* 1 When polling for DSC on a media access command */
+#define PC_WAIT_FOR_DSC			1
+/* 1 when we prefer to use DMA if possible */
+#define PC_DMA_RECOMMENDED		2
+/* 1 while DMA in progress */
+#define	PC_DMA_IN_PROGRESS		3
+/* 1 when encountered problem during DMA */
+#define	PC_DMA_ERROR			4
+/* Data direction */
+#define	PC_WRITING			5
 
 /*
  *	Capabilities and Mechanical Status Page
@@ -814,6 +842,7 @@
  *	REQUEST SENSE packet command result - Data Format.
  */
 typedef struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	error_code	:7;	/* Current of deferred errors */
 	unsigned	valid		:1;	/* The information field conforms to QIC-157C */
 	__u8		reserved1	:8;	/* Segment Number - Reserved */
@@ -822,6 +851,18 @@
 	unsigned	ili		:1;	/* Incorrect Length Indicator */
 	unsigned	eom		:1;	/* End Of Medium */
 	unsigned	filemark 	:1;	/* Filemark */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	unsigned	valid		:1;
+	unsigned	error_code	:7;
+	__u8		reserved1	:8;
+	unsigned	filemark	:1;
+	unsigned	eom		:1;
+	unsigned	ili		:1;
+	unsigned	reserved2_4	:1;
+	unsigned	sense_key	:4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
 	__u32		information __attribute__ ((packed));
 	__u8		asl;			/* Additional sense length (n-7) */
 	__u32		command_specific;	/* Additional command specific information */
@@ -860,12 +901,17 @@
 	 *	required since an additional packet command is needed before the
 	 *	retry, to get detailed information on what went wrong.
 	 */
-	idetape_pc_t *pc;			/* Current packet command */
-	idetape_pc_t *failed_pc; 		/* Last failed packet command */
-	idetape_pc_t pc_stack[IDETAPE_PC_STACK];/* Packet command stack */
-	int pc_stack_index;			/* Next free packet command storage space */
+	/* Current packet command */
+	idetape_pc_t *pc;
+	/* Last failed packet command */
+	idetape_pc_t *failed_pc;
+	/* Packet command stack */
+	idetape_pc_t pc_stack[IDETAPE_PC_STACK];
+	/* Next free packet command storage space */
+	int pc_stack_index;
 	struct request rq_stack[IDETAPE_PC_STACK];
-	int rq_stack_index;			/* We implement a circular array */
+	/* We implement a circular array */
+	int rq_stack_index;
 
 	/*
 	 *	DSC polling variables.
@@ -879,38 +925,48 @@
 	 *	to ide.c only one at a time.
 	 */
 	struct request *postponed_rq;
-	unsigned long dsc_polling_start;	/* The time in which we started polling for DSC */
-	struct timer_list dsc_timer;		/* Timer used to poll for dsc */
-	unsigned long best_dsc_rw_frequency;	/* Read/Write dsc polling frequency */
-	unsigned long dsc_polling_frequency;	/* The current polling frequency */
-	unsigned long dsc_timeout;		/* Maximum waiting time */
+	/* The time in which we started polling for DSC */
+	unsigned long dsc_polling_start;
+	/* Timer used to poll for dsc */
+	struct timer_list dsc_timer;
+	/* Read/Write dsc polling frequency */
+	unsigned long best_dsc_rw_frequency;
+	/* The current polling frequency */
+	unsigned long dsc_polling_frequency;
+	/* Maximum waiting time */
+	unsigned long dsc_timeout;
 
 	/*
 	 *	Read position information
 	 */
-	byte partition;
-	unsigned int first_frame_position;		/* Current block */
+	u8 partition;
+	/* Current block */
+	unsigned int first_frame_position;
 	unsigned int last_frame_position;
 	unsigned int blocks_in_buffer;
 
 	/*
 	 *	Last error information
 	 */
-	byte sense_key, asc, ascq;
+	u8 sense_key, asc, ascq;
 
 	/*
 	 *	Character device operation
 	 */
 	unsigned int minor;
-	char name[4];					/* device name */
-	idetape_chrdev_direction_t chrdev_direction;	/* Current character device data transfer direction */
+	/* device name */
+	char name[4];
+	/* Current character device data transfer direction */
+	idetape_chrdev_direction_t chrdev_direction;
 
 	/*
 	 *	Device information
 	 */
-	unsigned short tape_block_size;			/* Usually 512 or 1024 bytes */
+	/* Usually 512 or 1024 bytes */
+	unsigned short tape_block_size;
 	int user_bs_factor;
-	idetape_capabilities_page_t capabilities;	/* Copy of the tape's Capabilities and Mechanical Page */
+	/* Copy of the tape's Capabilities and Mechanical Page */
+	idetape_capabilities_page_t capabilities;
 
 	/*
 	 *	Active data transfer request parameters.
@@ -925,8 +981,10 @@
 	 *	The data buffer size is chosen based on the tape's
 	 *	recommendation.
 	 */
-	struct request *active_data_request;	/* Pointer to the request which is waiting in the device request queue */
-	int stage_size;				/* Data buffer size (chosen based on the tape's recommendation */
+	/* Pointer to the request, waiting in the device request queue */
+	struct request *active_data_request;
+	/* Data buffer size (chosen based on the tape's recommendation */
+	int stage_size;
 	idetape_stage_t *merge_stage;
 	int merge_stage_size;
 	struct buffer_head *bh;
@@ -939,19 +997,30 @@
 	 *	To accomplish non-pipelined mode, we simply set the following
 	 *	variables to zero (or NULL, where appropriate).
 	 */
-	int nr_stages;				/* Number of currently used stages */
-	int nr_pending_stages;			/* Number of pending stages */
-	int max_stages, min_pipeline, max_pipeline; /* We will not allocate more than this number of stages */
-	idetape_stage_t *first_stage;		/* The first stage which will be removed from the pipeline */
-	idetape_stage_t *active_stage;		/* The currently active stage */
-	idetape_stage_t *next_stage;		/* Will be serviced after the currently active request */
-	idetape_stage_t *last_stage;		/* New requests will be added to the pipeline here */
-	idetape_stage_t *cache_stage;		/* Optional free stage which we can use */
+	/* Number of currently used stages */
+	int nr_stages;
+	/* Number of pending stages */
+	int nr_pending_stages;
+	/* We will not allocate more than this number of stages */
+	int max_stages, min_pipeline, max_pipeline;
+	/* The first stage which will be removed from the pipeline */
+	idetape_stage_t *first_stage;
+	/* The currently active stage */
+	idetape_stage_t *active_stage;
+	/* Will be serviced after the currently active request */
+	idetape_stage_t *next_stage;
+	/* New requests will be added to the pipeline here */
+	idetape_stage_t *last_stage;
+	/* Optional free stage which we can use */
+	idetape_stage_t *cache_stage;
 	int pages_per_stage;
-	int excess_bh_size;			/* Wasted space in each stage */
+	/* Wasted space in each stage */
+	int excess_bh_size;
 
-	unsigned long flags;			/* Status/Action flags: long for set_bit */
-	spinlock_t spinlock;			/* protects the ide-tape queue */
+	/* Status/Action flags: long for set_bit */
+	unsigned long flags;
+	/* protects the ide-tape queue */
+	spinlock_t spinlock;
 
 	/*
 	 * Measures average tape speed
@@ -960,31 +1029,44 @@
 	int avg_size;
 	int avg_speed;
 
-	idetape_request_sense_result_t sense;	/* last sense information */
+	/* last sense information */
+	idetape_request_sense_result_t sense;
 
 	char vendor_id[10];
 	char product_id[18];
 	char firmware_revision[6];
 	int firmware_revision_num;
 
-	int door_locked;			/* the door is currently locked */
+	/* the door is currently locked */
+	int door_locked;
 
 	/*
 	 * OnStream flags
 	 */
-	int onstream;				/* the tape is an OnStream tape */
-	int raw;				/* OnStream raw access (32.5KB block size) */
-	int cur_frames;				/* current number of frames in internal buffer */
-	int max_frames;				/* max number of frames in internal buffer */
-	int logical_blk_num;			/* logical block number */
-	__u16 wrt_pass_cntr;			/* write pass counter */
-	__u32 update_frame_cntr;		/* update frame counter */
+	/* the tape is an OnStream tape */
+	int onstream;
+	/* OnStream raw access (32.5KB block size) */
+	int raw;
+	/* current number of frames in internal buffer */
+	int cur_frames;
+	/* max number of frames in internal buffer */
+	int max_frames;
+	/* logical block number */
+	int logical_blk_num;
+	/* write pass counter */
+	__u16 wrt_pass_cntr;
+	/* update frame counter */
+	__u32 update_frame_cntr;
 	struct completion *waiting;
-	int onstream_write_error;		/* write error recovery active */
-	int header_ok;				/* header frame verified ok */
-	int linux_media;			/* reading linux-specifc media */
+	/* write error recovery active */
+	int onstream_write_error;
+	/* header frame verified ok */
+	int header_ok;
+	/* reading linux-specifc media */
+	int linux_media;
 	int linux_media_version;
-	char application_sig[5];		/* application signature */
+	/* application signature */
+	char application_sig[5];
 	int filemark_cnt;
 	int first_mark_addr;
 	int last_mark_addr;
@@ -997,8 +1079,10 @@
 	 * Optimize the number of "buffer filling"
 	 * mode sense commands.
 	 */
-	unsigned long last_buffer_fill;		/* last time in which we issued fill cmd */
-	int req_buffer_fill;			/* buffer fill command requested */
+	/* last time in which we issued fill cmd */
+	unsigned long last_buffer_fill;
+	/* buffer fill command requested */
+	int req_buffer_fill;
 	int writes_since_buffer_fill;
 	int reads_since_buffer_fill;
 
@@ -1007,7 +1091,8 @@
 	 * be postponed, to avoid an infinite postpone
 	 * deadlock.
 	 */
-	int postpone_cnt;			/* request postpone count limit */
+	/* request postpone count limit */
+	int postpone_cnt;
 
 	/*
 	 * Measures number of frames:
@@ -1040,11 +1125,17 @@
 	 * Speed regulation negative feedback loop
 	 */
 	int speed_control;
-	int pipeline_head_speed, controlled_pipeline_head_speed, uncontrolled_pipeline_head_speed;
-	int controlled_last_pipeline_head, uncontrolled_last_pipeline_head;
-	unsigned long uncontrolled_pipeline_head_time, controlled_pipeline_head_time;
-	int controlled_previous_pipeline_head, uncontrolled_previous_pipeline_head;
-	unsigned long controlled_previous_head_time, uncontrolled_previous_head_time;
+	int pipeline_head_speed;
+	int controlled_pipeline_head_speed;
+	int uncontrolled_pipeline_head_speed;
+	int controlled_last_pipeline_head;
+	int uncontrolled_last_pipeline_head;
+	unsigned long uncontrolled_pipeline_head_time;
+	unsigned long controlled_pipeline_head_time;
+	int controlled_previous_pipeline_head;
+	int uncontrolled_previous_pipeline_head;
+	unsigned long controlled_previous_head_time;
+	unsigned long uncontrolled_previous_head_time;
 	int restart_speed_control_req;
 
         /*
@@ -1164,101 +1255,6 @@
 #define	IDETAPE_ERROR_EOD		103
 
 /*
- *	The ATAPI Status Register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned check		:1;	/* Error occurred */
-		unsigned idx		:1;	/* Reserved */
-		unsigned corr		:1;	/* Correctable error occurred */
-		unsigned drq		:1;	/* Data is request by the device */
-		unsigned dsc		:1;	/* Buffer availability / Media access command finished */
-		unsigned reserved5	:1;	/* Reserved */
-		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
-		unsigned bsy		:1;	/* The device has access to the command block */
-	} b;
-} idetape_status_reg_t;
-
-/*
- *	The ATAPI error register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned ili		:1;	/* Illegal Length Indication */
-		unsigned eom		:1;	/* End Of Media Detected */
-		unsigned abrt		:1;	/* Aborted command - As defined by ATA */
-		unsigned mcr		:1;	/* Media Change Requested - As defined by ATA */
-		unsigned sense_key	:4;	/* Sense key of the last failed packet command */
-	} b;
-} idetape_error_reg_t;
-
-/*
- *	ATAPI Feature Register
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned dma		:1;	/* Using DMA or PIO */
-		unsigned reserved321	:3;	/* Reserved */
-		unsigned reserved654	:3;	/* Reserved (Tag Type) */
-		unsigned reserved7	:1;	/* Reserved */
-	} b;
-} idetape_feature_reg_t;
-
-/*
- *	ATAPI Byte Count Register.
- */
-typedef union {
-	unsigned all			:16;
-	struct {
-		unsigned low		:8;	/* LSB */
-		unsigned high		:8;	/* MSB */
-	} b;
-} idetape_bcount_reg_t;
-
-/*
- *	ATAPI Interrupt Reason Register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
-		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
-		unsigned reserved	:6;	/* Reserved */
-	} b;
-} idetape_ireason_reg_t;
-
-/*
- *	ATAPI Drive Select Register
- */
-typedef union {	
-	unsigned all			:8;
-	struct {
-		unsigned sam_lun	:4;	/* Should be zero with ATAPI (not used) */
-		unsigned drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
-		unsigned one5		:1;	/* Should be set to 1 */
-		unsigned reserved6	:1;	/* Reserved */
-		unsigned one7		:1;	/* Should be set to 1 */
-	} b;
-} idetape_drivesel_reg_t;
-
-/*
- *	ATAPI Device Control Register
- */
-typedef union {			
-	unsigned all			:8;
-	struct {
-		unsigned zero0		:1;	/* Should be set to zero */
-		unsigned nien		:1;	/* Device interrupt is disabled (1) or enabled (0) */
-		unsigned srst		:1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
-		unsigned one3		:1;	/* Should be set to 1 */
-		unsigned reserved4567	:4;	/* Reserved */
-	} b;
-} idetape_control_reg_t;
-
-/*
  *	idetape_chrdev_t provides the link between out character device
  *	interface and our block device interface and the corresponding
  *	ide_drive_t structure.
@@ -1432,41 +1428,60 @@
  * DO NOT REMOVE, BUILDING A VERBOSE DEBUG SCHEME FOR ATAPI
  */
 
-char *idetape_sense_key_verbose (byte idetape_sense_key)
+char *idetape_sense_key_verbose (u8 idetape_sense_key)
 {
 	switch (idetape_sense_key) {
 		default: {
 			char buf[22];
-			sprintf(buf, "IDETAPE_SENSE (0x%02x)", idetape_sense_key);
+			sprintf(buf, "IDETAPE_SENSE (0x%02x)",
+				idetape_sense_key);
 			return(buf);
 		}
 
 	}
 }
 
-char *idetape_command_key_verbose (byte idetape_command_key)
+char *idetape_command_key_verbose (u8 idetape_command_key)
 {
 	switch (idetape_command_key) {
-		case IDETAPE_TEST_UNIT_READY_CMD:	return("TEST_UNIT_READY_CMD");
-		case IDETAPE_REWIND_CMD:		return("REWIND_CMD");
-		case IDETAPE_REQUEST_SENSE_CMD:		return("REQUEST_SENSE_CMD");
-		case IDETAPE_READ_CMD:			return("READ_CMD");
-		case IDETAPE_WRITE_CMD:			return("WRITE_CMD");
-		case IDETAPE_WRITE_FILEMARK_CMD:	return("WRITE_FILEMARK_CMD");
-		case IDETAPE_SPACE_CMD:			return("SPACE_CMD");
-		case IDETAPE_INQUIRY_CMD:		return("INQUIRY_CMD");
-		case IDETAPE_ERASE_CMD:			return("ERASE_CMD");
-		case IDETAPE_MODE_SENSE_CMD:		return("MODE_SENSE_CMD");
-		case IDETAPE_MODE_SELECT_CMD:		return("MODE_SELECT_CMD");
-		case IDETAPE_LOAD_UNLOAD_CMD:		return("LOAD_UNLOAD_CMD");
-		case IDETAPE_PREVENT_CMD:		return("PREVENT_CMD");
-		case IDETAPE_LOCATE_CMD:		return("LOCATE_CMD");
-		case IDETAPE_READ_POSITION_CMD:		return("READ_POSITION_CMD");
-		case IDETAPE_READ_BUFFER_CMD:		return("READ_BUFFER_CMD");
-		case IDETAPE_SET_SPEED_CMD:		return("SET_SPEED_CMD");
+		case IDETAPE_TEST_UNIT_READY_CMD:
+			return("TEST_UNIT_READY_CMD");
+		case IDETAPE_REWIND_CMD:
+			return("REWIND_CMD");
+		case IDETAPE_REQUEST_SENSE_CMD:
+			return("REQUEST_SENSE_CMD");
+		case IDETAPE_READ_CMD:
+			return("READ_CMD");
+		case IDETAPE_WRITE_CMD:
+			return("WRITE_CMD");
+		case IDETAPE_WRITE_FILEMARK_CMD:
+			return("WRITE_FILEMARK_CMD");
+		case IDETAPE_SPACE_CMD:
+			return("SPACE_CMD");
+		case IDETAPE_INQUIRY_CMD:
+			return("INQUIRY_CMD");
+		case IDETAPE_ERASE_CMD:
+			return("ERASE_CMD");
+		case IDETAPE_MODE_SENSE_CMD:
+			return("MODE_SENSE_CMD");
+		case IDETAPE_MODE_SELECT_CMD:
+			return("MODE_SELECT_CMD");
+		case IDETAPE_LOAD_UNLOAD_CMD:
+			return("LOAD_UNLOAD_CMD");
+		case IDETAPE_PREVENT_CMD:
+			return("PREVENT_CMD");
+		case IDETAPE_LOCATE_CMD:
+			return("LOCATE_CMD");
+		case IDETAPE_READ_POSITION_CMD:
+			return("READ_POSITION_CMD");
+		case IDETAPE_READ_BUFFER_CMD:
+			return("READ_BUFFER_CMD");
+		case IDETAPE_SET_SPEED_CMD:
+			return("SET_SPEED_CMD");
 		default: {
 				char buf[20];
-				sprintf(buf, "CMD (0x%02x)", idetape_command_key);
+				sprintf(buf, "CMD (0x%02x)",
+					idetape_command_key);
 				return(buf);
 			}
 	}
@@ -1482,13 +1497,13 @@
 static void idetape_write_release (struct inode *inode);
 
 /*
- *	Too bad. The drive wants to send us data which we are not ready to accept.
- *	Just throw it away.
+ * Too bad. The drive wants to send us data which we are not ready to accept.
+ * Just throw it away.
  */
 static void idetape_discard_data (ide_drive_t *drive, unsigned int bcount)
 {
 	while (bcount--)
-		IN_BYTE (IDE_DATA_REG);
+		(void) HWIF(drive)->INB(IDE_DATA_REG);
 }
 
 static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
@@ -1499,13 +1514,14 @@
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_input_buffers\n");
-			idetape_discard_data (drive, bcount);
+			printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+				__FUNCTION__);
+			idetape_discard_data(drive, bcount);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), bcount);
-		atapi_input_bytes (drive, bh->b_data + atomic_read(&bh->b_count), count);
+		count = IDE_MIN(bh->b_size - atomic_read(&bh->b_count), bcount);
+		HWIF(drive)->atapi_input_bytes(drive, bh->b_data + atomic_read(&bh->b_count), count);
 		bcount -= count;
 		atomic_add(count, &bh->b_count);
 		if (atomic_read(&bh->b_count) == bh->b_size) {
@@ -1525,12 +1541,13 @@
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_output_buffers\n");
+			printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+				__FUNCTION__);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (pc->b_count, bcount);
-		atapi_output_bytes (drive, pc->b_data, count);
+		count = IDE_MIN(pc->b_count, bcount);
+		HWIF(drive)->atapi_output_bytes(drive, pc->b_data, count);
 		bcount -= count;
 		pc->b_data += count;
 		pc->b_count -= count;
@@ -1550,16 +1567,17 @@
 	struct buffer_head *bh = pc->bh;
 	int count, bcount = pc->actually_transferred;
 
-	if (test_bit (PC_WRITING, &pc->flags))
+	if (test_bit(PC_WRITING, &pc->flags))
 		return;
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_update_buffers\n");
+			printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+				__FUNCTION__);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size, bcount);
+		count = IDE_MIN(bh->b_size, bcount);
 		atomic_set(&bh->b_count, count);
 		if (atomic_read(&bh->b_count) == bh->b_size)
 			bh = bh->b_reqnext;
@@ -1581,9 +1599,10 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 5)
-		printk (KERN_INFO "ide-tape: pc_stack_index=%d\n",tape->pc_stack_index);
+		printk(KERN_INFO "ide-tape: pc_stack_index=%d\n",
+			tape->pc_stack_index);
 #endif /* IDETAPE_DEBUG_LOG */
-	if (tape->pc_stack_index==IDETAPE_PC_STACK)
+	if (tape->pc_stack_index == IDETAPE_PC_STACK)
 		tape->pc_stack_index=0;
 	return (&tape->pc_stack[tape->pc_stack_index++]);
 }
@@ -1607,9 +1626,10 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 5)
-		printk (KERN_INFO "ide-tape: rq_stack_index=%d\n",tape->rq_stack_index);
+		printk(KERN_INFO "ide-tape: rq_stack_index=%d\n",
+			tape->rq_stack_index);
 #endif /* IDETAPE_DEBUG_LOG */
-	if (tape->rq_stack_index==IDETAPE_PC_STACK)
+	if (tape->rq_stack_index == IDETAPE_PC_STACK)
 		tape->rq_stack_index=0;
 	return (&tape->rq_stack[tape->rq_stack_index++]);
 }
@@ -1619,7 +1639,7 @@
  */
 static void idetape_init_pc (idetape_pc_t *pc)
 {
-	memset (pc->c, 0, 12);
+	memset(pc->c, 0, 12);
 	pc->retries = 0;
 	pc->flags = 0;
 	pc->request_transfer = 0;
@@ -1649,19 +1669,23 @@
 	 *	give up retrying.
 	 */
 	if (tape->debug_level >= 1)
-		printk (KERN_INFO "ide-tape: pc = %x, sense key = %x, asc = %x, ascq = %x\n",
-				pc->c[0], result->sense_key, result->asc, result->ascq);
+		printk(KERN_INFO "ide-tape: pc = %x, sense key = %x, "
+			"asc = %x, ascq = %x\n",
+			pc->c[0], result->sense_key,
+			result->asc, result->ascq);
 #if IDETAPE_DEBUG_LOG_VERBOSE
 	if (tape->debug_level >= 1)
-		printk (KERN_INFO "ide-tape: pc = %s, sense key = %x, asc = %x, ascq = %x\n",
-			idetape_command_key_verbose((byte) pc->c[0]),
+		printk (KERN_INFO "ide-tape: pc = %s, sense key = %x, "
+			"asc = %x, ascq = %x\n",
+			idetape_command_key_verbose((u8) pc->c[0]),
 			result->sense_key,
 			result->asc,
 			result->ascq);
 #endif /* IDETAPE_DEBUG_LOG_VERBOSE */
 #endif /* IDETAPE_DEBUG_LOG */
 
-	if (tape->onstream && result->sense_key == 2 && result->asc == 0x53 && result->ascq == 2) {
+	if (tape->onstream && result->sense_key == 2 &&
+	    result->asc == 0x53 && result->ascq == 2) {
 		clear_bit(PC_DMA_ERROR, &pc->flags);
 		ide_stall_queue(drive, HZ / 2);
 		return;
@@ -1671,49 +1695,33 @@
 	/*
 	 *	Correct pc->actually_transferred by asking the tape.
 	 */
-	if (test_bit (PC_DMA_ERROR, &pc->flags)) {
-		pc->actually_transferred = pc->request_transfer - tape->tape_block_size * ntohl (get_unaligned (&result->information));
-		idetape_update_buffers (pc);
+	if (test_bit(PC_DMA_ERROR, &pc->flags)) {
+		pc->actually_transferred = pc->request_transfer - tape->tape_block_size * ntohl(get_unaligned (&result->information));
+		idetape_update_buffers(pc);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	if (pc->c[0] == IDETAPE_READ_CMD && result->filemark) {
 		pc->error = IDETAPE_ERROR_FILEMARK;
-		set_bit (PC_ABORT, &pc->flags);
+		set_bit(PC_ABORT, &pc->flags);
 	}
 	if (pc->c[0] == IDETAPE_WRITE_CMD) {
-		if (result->eom || (result->sense_key == 0xd && result->asc == 0x0 && result->ascq == 0x2)) {
+		if (result->eom || (result->sense_key == 0xd &&
+		    result->asc == 0x0 && result->ascq == 0x2)) {
 			pc->error = IDETAPE_ERROR_EOD;
-			set_bit (PC_ABORT, &pc->flags);
+			set_bit(PC_ABORT, &pc->flags);
 		}
 	}
 	if (pc->c[0] == IDETAPE_READ_CMD || pc->c[0] == IDETAPE_WRITE_CMD) {
 		if (result->sense_key == 8) {
 			pc->error = IDETAPE_ERROR_EOD;
-			set_bit (PC_ABORT, &pc->flags);
+			set_bit(PC_ABORT, &pc->flags);
 		}
-		if (!test_bit (PC_ABORT, &pc->flags) && (tape->onstream || pc->actually_transferred))
+		if (!test_bit(PC_ABORT, &pc->flags) &&
+		    (tape->onstream || pc->actually_transferred))
 			pc->retries = IDETAPE_MAX_PC_RETRIES + 1;
 	}
 }
 
-static void idetape_abort_pipeline (ide_drive_t *drive)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	idetape_stage_t *stage = tape->next_stage;
-
-#if IDETAPE_DEBUG_LOG
-	if (tape->debug_level >= 4)
-		printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name);
-#endif
-	while (stage) {
-		if (stage->rq.cmd == IDETAPE_WRITE_RQ)
-			stage->rq.cmd = IDETAPE_ABORTED_WRITE_RQ;
-		else if (stage->rq.cmd == IDETAPE_READ_RQ)
-			stage->rq.cmd = IDETAPE_ABORTED_READ_RQ;
-		stage = stage->next;
-	}
-}
-
 /*
  *	idetape_active_next_stage will declare the next stage as "active".
  */
@@ -1725,11 +1733,12 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_active_next_stage\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 #if IDETAPE_DEBUG_BUGS
 	if (stage == NULL) {
-		printk (KERN_ERR "ide-tape: bug: Trying to activate a non existing stage\n");
+		printk(KERN_ERR "ide-tape: bug: Trying to activate a "
+			"non existing stage\n");
 		return;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */	
@@ -1755,10 +1764,10 @@
 	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_increase_max_pipeline_stages\n");
+		printk (KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
-	tape->max_stages += increase;
+	tape->max_stages += IDE_MAX(increase, 1);
 	tape->max_stages = IDE_MAX(tape->max_stages, tape->min_pipeline);
 	tape->max_stages = IDE_MIN(tape->max_stages, tape->max_pipeline);
 }
@@ -1776,21 +1785,21 @@
 		if (bh->b_data != NULL) {
 			size = (int) bh->b_size;
 			while (size > 0) {
-				free_page ((unsigned long) bh->b_data);
+				free_page((unsigned long) bh->b_data);
 				size -= PAGE_SIZE;
 				bh->b_data += PAGE_SIZE;
 			}
 		}
 		prev_bh = bh;
 		bh = bh->b_reqnext;
-		kfree (prev_bh);
+		kfree(prev_bh);
 	}
-	kfree (stage);
+	kfree(stage);
 }
 
 static void idetape_kfree_stage (idetape_tape_t *tape, idetape_stage_t *stage)
 {
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 }
 
 /*
@@ -1804,45 +1813,72 @@
 	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_remove_stage_head\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 #if IDETAPE_DEBUG_BUGS
 	if (tape->first_stage == NULL) {
-		printk (KERN_ERR "ide-tape: bug: tape->first_stage is NULL\n");
+		printk(KERN_ERR "ide-tape: bug: tape->first_stage is NULL\n");
 		return;		
 	}
 	if (tape->active_stage == tape->first_stage) {
-		printk (KERN_ERR "ide-tape: bug: Trying to free our active pipeline stage\n");
+		printk(KERN_ERR "ide-tape: bug: Trying to free our "
+			"active pipeline stage\n");
 		return;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 	stage = tape->first_stage;
 	tape->first_stage = stage->next;
-	idetape_kfree_stage (tape, stage);
+	idetape_kfree_stage(tape, stage);
 	tape->nr_stages--;
 	if (tape->first_stage == NULL) {
 		tape->last_stage = NULL;
 #if IDETAPE_DEBUG_BUGS
 		if (tape->next_stage != NULL)
-			printk (KERN_ERR "ide-tape: bug: tape->next_stage != NULL\n");
+			printk(KERN_ERR "ide-tape: bug: "
+				"tape->next_stage != NULL\n");
 		if (tape->nr_stages)
-			printk (KERN_ERR "ide-tape: bug: nr_stages should be 0 now\n");
+			printk(KERN_ERR "ide-tape: bug: nr_stages should "
+				"be 0 now\n");
 #endif /* IDETAPE_DEBUG_BUGS */
 	}
 }
 
+static void idetape_abort_pipeline (ide_drive_t *drive, idetape_stage_t *last_stage)
+{
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_stage_t *stage = tape->next_stage;
+	idetape_stage_t *nstage;
+
+#if IDETAPE_DEBUG_LOG
+	if (tape->debug_level >= 4)
+		printk(KERN_INFO "ide-tape: %s: %s called\n",
+			tape->name, __FUNCTION__);
+#endif
+	while (stage) {
+		nstage = stage->next;
+		idetape_kfree_stage(tape, stage);
+		--tape->nr_stages;
+		--tape->nr_pending_stages;
+		stage = nstage;
+	}
+	tape->last_stage = last_stage;
+	if (last_stage)
+		last_stage->next = NULL;
+	tape->next_stage = NULL;
+}
+
 /*
  *	idetape_end_request is used to finish servicing a request, and to
  *	insert a pending pipeline request into the main device queue.
  */
-static void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
+static int idetape_end_request (ide_drive_t *drive, int uptodate)
 {
-	ide_drive_t *drive = hwgroup->drive;
-	struct request *rq = hwgroup->rq;
+	struct request *rq = HWGROUP(drive)->rq;
 	idetape_tape_t *tape = drive->driver_data;
 	unsigned long flags;
 	int error;
 	int remove_stage = 0;
+	idetape_stage_t *active_stage;
 #if ONSTREAM_DEBUG
 	idetape_stage_t *stage;
 	os_aux_t *aux;
@@ -1851,7 +1887,7 @@
 
 #if IDETAPE_DEBUG_LOG
         if (tape->debug_level >= 4)
-	printk (KERN_INFO "ide-tape: Reached idetape_end_request\n");
+		printk (KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	switch (uptodate) {
@@ -1864,7 +1900,9 @@
 		tape->failed_pc = NULL;
 
 	spin_lock_irqsave(&tape->spinlock, flags);
-	if (tape->active_data_request == rq) {		/* The request was a pipelined data transfer request */
+	if (tape->active_data_request == rq) {
+		/* The request was a pipelined data transfer request */
+		active_stage = tape->active_stage;
 		tape->active_stage = NULL;
 		tape->active_data_request = NULL;
 		tape->nr_pending_stages--;
@@ -1884,34 +1922,40 @@
 				if (tape->first_frame_position == OS_DATA_ENDFRAME1) { 
 #if ONSTREAM_DEBUG
 					if (tape->debug_level >= 2)
-						printk("ide-tape: %s: skipping over config parition..\n", tape->name);
+						printk("ide-tape: %s: skipping over config partition.\n", tape->name);
 #endif
 					tape->onstream_write_error = OS_PART_ERROR;
-					if (tape->waiting)
+					if (tape->waiting) {
+						rq->waiting = NULL;
 						complete(tape->waiting);
+					}
 				}
 			}
 			remove_stage = 1;
 			if (error) {
-				set_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+				set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 				if (error == IDETAPE_ERROR_EOD)
-					idetape_abort_pipeline (drive);
-				if (tape->onstream && !tape->raw && error == IDETAPE_ERROR_GENERAL && tape->sense.sense_key == 3) {
-					clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+					idetape_abort_pipeline(drive, active_stage);
+				if (tape->onstream && !tape->raw &&
+				    error == IDETAPE_ERROR_GENERAL &&
+				    tape->sense.sense_key == 3) {
+					clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 					printk(KERN_ERR "ide-tape: %s: write error, enabling error recovery\n", tape->name);
 					tape->onstream_write_error = OS_WRITE_ERROR;
 					remove_stage = 0;
 					tape->nr_pending_stages++;
 					tape->next_stage = tape->first_stage;
 					rq->current_nr_sectors = rq->nr_sectors;
-					if (tape->waiting)
+					if (tape->waiting) {
+						rq->waiting = NULL;
 						complete(tape->waiting);
+					}
 				}
 			}
 		} else if (rq->cmd == IDETAPE_READ_RQ) {
 			if (error == IDETAPE_ERROR_EOD) {
-				set_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
-				idetape_abort_pipeline(drive);
+				set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
+				idetape_abort_pipeline(drive, active_stage);
 			}
 		}
 		if (tape->next_stage != NULL && !tape->onstream_write_error) {
@@ -1920,18 +1964,19 @@
 			/*
 			 *	Insert the next request into the request queue.
 			 */
-			(void) ide_do_drive_cmd (drive, tape->active_data_request, ide_end);
+			(void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
 		} else if (!error) {
 			if (!tape->onstream)
-				idetape_increase_max_pipeline_stages (drive);
+				idetape_increase_max_pipeline_stages(drive);
 		}
 	}
-	ide_end_drive_cmd (drive, 0, 0);
+	ide_end_drive_cmd(drive, 0, 0);
 	if (remove_stage)
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 	if (tape->active_data_request == NULL)
 		clear_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
 	spin_unlock_irqrestore(&tape->spinlock, flags);
+	return 0;
 }
 
 static ide_startstop_t idetape_request_sense_callback (ide_drive_t *drive)
@@ -1940,24 +1985,25 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 	if (!tape->pc->error) {
-		idetape_analyze_error (drive, (idetape_request_sense_result_t *) tape->pc->buffer);
-		idetape_end_request (1, HWGROUP (drive));
+		idetape_analyze_error(drive, (idetape_request_sense_result_t *) tape->pc->buffer);
+		idetape_end_request(drive, 1);
 	} else {
-		printk (KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n");
-		idetape_end_request (0, HWGROUP (drive));
+		printk(KERN_ERR "ide-tape: Error in REQUEST SENSE "
+			"itself - Aborting request!\n");
+		idetape_end_request(drive, 0);
 	}
 	return ide_stopped;
 }
 
 static void idetape_create_request_sense_cmd (idetape_pc_t *pc)
 {
-	idetape_init_pc (pc);	
+	idetape_init_pc(pc);	
 	pc->c[0] = IDETAPE_REQUEST_SENSE_CMD;
 	pc->c[4] = 20;
-	pc->request_transfer = 18;
+	pc->request_transfer = 20;
 	pc->callback = &idetape_request_sense_callback;
 }
 
@@ -1982,10 +2028,10 @@
  */
 static void idetape_queue_pc_head (ide_drive_t *drive,idetape_pc_t *pc,struct request *rq)
 {
-	ide_init_drive_cmd (rq);
+	ide_init_drive_cmd(rq);
 	rq->buffer = (char *) pc;
 	rq->cmd = IDETAPE_PC_RQ1;
-	(void) ide_do_drive_cmd (drive, rq, ide_preempt);
+	(void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
 /*
@@ -1998,14 +2044,14 @@
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc;
 	struct request *rq;
-	idetape_error_reg_t error;
+	atapi_error_t error;
 
-	error.all = IN_BYTE (IDE_ERROR_REG);
+	error.all = HWIF(drive)->INB(IDE_ERROR_REG);
 	pc = idetape_next_pc_storage (drive);
 	rq = idetape_next_rq_storage (drive);
-	idetape_create_request_sense_cmd (pc);
-	set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
-	idetape_queue_pc_head (drive, pc, rq);
+	idetape_create_request_sense_cmd(pc);
+	set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
+	idetape_queue_pc_head(drive, pc, rq);
 	return ide_stopped;
 }
 
@@ -2037,9 +2083,9 @@
 static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	idetape_status_reg_t status;
-	idetape_bcount_reg_t bcount;
-	idetape_ireason_reg_t ireason;
+	atapi_status_t status;
+	atapi_bcount_t bcount;
+	atapi_ireason_t ireason;
 	idetape_pc_t *pc = tape->pc;
 
 	unsigned int temp;
@@ -2050,14 +2096,16 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_pc_intr interrupt handler\n");
+		printk(KERN_INFO "ide-tape: Reached idetape_pc_intr "
+				"interrupt handler\n");
 #endif /* IDETAPE_DEBUG_LOG */	
 
-	status.all = GET_STAT();					/* Clear the interrupt */
+	/* Clear the interrupt */
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
+	if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+		if (HWIF(drive)->ide_dma_end(drive) || status.b.check) {
 			/*
 			 * A DMA error is sometimes expected. For example,
 			 * if the tape is crossing a filemark during a
@@ -2069,8 +2117,18 @@
 			 * actually transferred (we can't receive that
 			 * information from the DMA engine on most chipsets).
 			 */
+
+			/*
+			 * On the contrary, a DMA error is never expected;
+			 * it usually indicates a hardware error or abort.
+			 * If the tape crosses a filemark during a READ
+			 * command, it will issue an irq and position itself
+			 * after the filemark (not before). Only a partial
+			 * data transfer will occur, but no DMA error.
+			 * (AS, 19 Apr 2001)
+			 */
 			set_bit (PC_DMA_ERROR, &pc->flags);
-		} else if (!status.b.check) {
+		} else {
 			pc->actually_transferred = pc->request_transfer;
 			idetape_update_buffers (pc);
 		}
@@ -2081,106 +2139,144 @@
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	if (!status.b.drq) {						/* No more interrupts */
+	if (!status.b.drq) {			/* No more interrupts */
 		cmd_time = (jiffies - tape->cmd_start_time) * 1000 / HZ;
 		tape->max_cmd_time = IDE_MAX(cmd_time, tape->max_cmd_time);
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 2)
-			printk (KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred);
+			printk(KERN_INFO "ide-tape: Packet command completed, "
+				"%d bytes transferred\n",
+				pc->actually_transferred);
 #endif /* IDETAPE_DEBUG_LOG */
-		clear_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
 
-		ide__sti();	/* local CPU only */
+		local_irq_enable();
 
 #if SIMULATE_ERRORS
-		if ((pc->c[0] == IDETAPE_WRITE_CMD || pc->c[0] == IDETAPE_READ_CMD) && (++error_sim_count % 100) == 0) {
-			printk(KERN_INFO "ide-tape: %s: simulating error\n", tape->name);
+		if ((pc->c[0] == IDETAPE_WRITE_CMD ||
+		     pc->c[0] == IDETAPE_READ_CMD) &&
+		    (++error_sim_count % 100) == 0) {
+			printk(KERN_INFO "ide-tape: %s: simulating error\n",
+				tape->name);
 			status.b.check = 1;
 		}
 #endif
 		if (status.b.check && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD)
 			status.b.check = 0;
-		if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) {	/* Error detected */
+		if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {
+			/* Error detected */
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 1)
-				printk (KERN_INFO "ide-tape: %s: I/O error, ",tape->name);
+				printk(KERN_INFO "ide-tape: %s: I/O error\n",
+					tape->name);
 #endif /* IDETAPE_DEBUG_LOG */
 			if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-				printk (KERN_ERR "ide-tape: I/O error in request sense command\n");
-				return ide_do_reset (drive);
+				printk(KERN_ERR "ide-tape: I/O error in "
+					"request sense command\n");
+				return ide_do_reset(drive);
 			}
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 1)
-				printk(KERN_INFO "ide-tape: [cmd %x]: check condition\n", pc->c[0]);
+				printk(KERN_INFO "ide-tape: [cmd %x]: check "
+					"condition\n", pc->c[0]);
 #endif
-			return idetape_retry_pc (drive);				/* Retry operation */
+			/* Retry operation */
+			return idetape_retry_pc(drive);
 		}
 		pc->error = 0;
-		if (!tape->onstream && test_bit (PC_WAIT_FOR_DSC, &pc->flags) && !status.b.dsc) {	/* Media access command */
+		if (!tape->onstream &&
+		    test_bit(PC_WAIT_FOR_DSC, &pc->flags) &&
+		    !status.b.dsc) {
+			/* Media access command */
 			tape->dsc_polling_start = jiffies;
 			tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST;
 			tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
-			idetape_postpone_request (drive);		/* Allow ide.c to handle other requests */
+			/* Allow ide.c to handle other requests */
+			idetape_postpone_request(drive);
 			return ide_stopped;
 		}
 		if (tape->failed_pc == pc)
 			tape->failed_pc = NULL;
-		return pc->callback(drive);			/* Command finished - Call the callback function */
+		/* Command finished - Call the callback function */
+		return pc->callback(drive);
 	}
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n");
-		printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-		return ide_do_reset (drive);
+	if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+		printk(KERN_ERR "ide-tape: The tape wants to issue more "
+				"interrupts in DMA mode\n");
+		printk(KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
+		(void) HWIF(drive)->ide_dma_off(drive);
+		return ide_do_reset(drive);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
-	bcount.b.high = IN_BYTE (IDE_BCOUNTH_REG);			/* Get the number of bytes to transfer */
-	bcount.b.low  = IN_BYTE (IDE_BCOUNTL_REG);			/* on this interrupt */
-	ireason.all   = IN_BYTE (IDE_IREASON_REG);
+	/* Get the number of bytes to transfer */
+	bcount.b.high	= HWIF(drive)->INB(IDE_BCOUNTH_REG);
+	bcount.b.low	= HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	/* on this interrupt */
+	ireason.all	= HWIF(drive)->INB(IDE_IREASON_REG);
 
 	if (ireason.b.cod) {
-		printk (KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
-		return ide_do_reset (drive);
+		printk(KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
+		return ide_do_reset(drive);
 	}
-	if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) {	/* Hopefully, we will never get here */
-		printk (KERN_ERR "ide-tape: We wanted to %s, ", ireason.b.io ? "Write":"Read");
-		printk (KERN_ERR "ide-tape: but the tape wants us to %s !\n",ireason.b.io ? "Read":"Write");
-		return ide_do_reset (drive);
+	if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {
+		/* Hopefully, we will never get here */
+		printk(KERN_ERR "ide-tape: We wanted to %s, ",
+			ireason.b.io ? "Write":"Read");
+		printk(KERN_ERR "ide-tape: but the tape wants us to %s !\n",
+			ireason.b.io ? "Read":"Write");
+		return ide_do_reset(drive);
 	}
-	if (!test_bit (PC_WRITING, &pc->flags)) {			/* Reading - Check that we have enough space */
+	if (!test_bit(PC_WRITING, &pc->flags)) {
+		/* Reading - Check that we have enough space */
 		temp = pc->actually_transferred + bcount.all;
-		if ( temp > pc->request_transfer) {
+		if (temp > pc->request_transfer) {
 			if (temp > pc->buffer_size) {
-				printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
-				idetape_discard_data (drive, bcount.all);
-				ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+				printk(KERN_ERR "ide-tape: The tape wants to "
+					"send us more data than expected "
+					"- discarding data\n");
+				idetape_discard_data(drive, bcount.all);
+				if (HWGROUP(drive)->handler != NULL)
+					BUG();
+				ide_set_handler(drive,
+						&idetape_pc_intr,
+						IDETAPE_WAIT_CMD,
+						NULL);
 				return ide_started;
 			}
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 2)
-				printk (KERN_NOTICE "ide-tape: The tape wants to send us more data than expected - allowing transfer\n");
+				printk(KERN_NOTICE "ide-tape: The tape wants "
+					"to send us more data than expected "
+					"- allowing transfer\n");
 #endif /* IDETAPE_DEBUG_LOG */
 		}
 	}
-	if (test_bit (PC_WRITING, &pc->flags)) {
+	if (test_bit(PC_WRITING, &pc->flags)) {
 		if (pc->bh != NULL)
-			idetape_output_buffers (drive, pc, bcount.all);
+			idetape_output_buffers(drive, pc, bcount.all);
 		else
-			atapi_output_bytes (drive,pc->current_position,bcount.all);	/* Write the current buffer */
+			/* Write the current buffer */
+			HWIF(drive)->atapi_output_bytes(drive,pc->current_position,bcount.all);
 	} else {
 		if (pc->bh != NULL)
-			idetape_input_buffers (drive, pc, bcount.all);
+			idetape_input_buffers(drive, pc, bcount.all);
 		else
-			atapi_input_bytes (drive,pc->current_position,bcount.all);	/* Read the current buffer */
+			/* Read the current buffer */
+			HWIF(drive)->atapi_input_bytes(drive,pc->current_position,bcount.all);
 	}
-	pc->actually_transferred += bcount.all;					/* Update the current position */
-	pc->current_position+=bcount.all;
+	/* Update the current position */
+	pc->actually_transferred += bcount.all;
+	pc->current_position += bcount.all;
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
+		printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes "
+			"on that interrupt\n", pc->c[0], bcount.all);
 #endif
-	ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* And set the interrupt handler again */
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	/* And set the interrupt handler again */
+	ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
 	return ide_started;
 }
 
@@ -2217,9 +2313,9 @@
  *
  *	4.	When the packet command is finished, it will be checked for errors.
  *
- *	5.	In case an error was found, we queue a request sense packet command
- *		in front of the request queue and retry the operation up to
- *		IDETAPE_MAX_PC_RETRIES times.
+ *	5.	In case an error was found, we queue a request sense packet
+ *		command in front of the request queue and retry the operation
+ *		upto IDETAPE_MAX_PC_RETRIES times.
  *
  *	6.	In case no error was found, or we decided to give up and not
  *		to retry again, the callback function will be called and then
@@ -2230,108 +2326,147 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc = tape->pc;
-	idetape_ireason_reg_t ireason;
+	atapi_ireason_t ireason;
 	int retries = 100;
 	ide_startstop_t startstop;
 
-	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
-		printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
+	if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+		printk(KERN_ERR "ide-tape: Strange, packet command "
+			"initiated yet DRQ isn't asserted\n");
 		return startstop;
 	}
-	ireason.all = IN_BYTE (IDE_IREASON_REG);
+	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
 	while (retries-- && (!ireason.b.cod || ireason.b.io)) {
-		printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, retrying\n");
+		printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing "
+				"a packet command, retrying\n");
 		udelay(100);
-		ireason.all = IN_BYTE(IDE_IREASON_REG);
+		ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
 		if (retries == 0) {
-			printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, ignoring\n");
+			printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while "
+					"issuing a packet command, ignoring\n");
 			ireason.b.cod = 1;
 			ireason.b.io = 0;
 		}
 	}
 	if (!ireason.b.cod || ireason.b.io) {
-		printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n");
-		return ide_do_reset (drive);
+		printk(KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing "
+				"a packet command\n");
+		return ide_do_reset(drive);
 	}
 	tape->cmd_start_time = jiffies;
-	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* Set the interrupt routine */
-	atapi_output_bytes (drive,pc->c,12);			/* Send the actual packet */
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	/* Set the interrupt routine */
+	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	/* Begin DMA, if necessary */
+	if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags))
+		(void) (HWIF(drive)->ide_dma_begin(drive));
+#endif
+	/* Send the actual packet */
+	HWIF(drive)->atapi_output_bytes(drive, pc->c, 12);
 	return ide_started;
 }
 
 static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	idetape_bcount_reg_t bcount;
-	int dma_ok = 0;
+	atapi_feature_t feature;
+	atapi_bcount_t bcount;
 
 #if IDETAPE_DEBUG_BUGS
-	if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-		printk (KERN_ERR "ide-tape: possible ide-tape.c bug - Two request sense in serial were issued\n");
+	if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD &&
+	    pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
+		printk(KERN_ERR "ide-tape: possible ide-tape.c bug - "
+			"Two request sense in serial were issued\n");
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 
 	if (tape->failed_pc == NULL && pc->c[0] != IDETAPE_REQUEST_SENSE_CMD)
 		tape->failed_pc = pc;
-	tape->pc = pc;							/* Set the current packet command */
+	/* Set the current packet command */
+	tape->pc = pc;
 
-	if (pc->retries > IDETAPE_MAX_PC_RETRIES || test_bit (PC_ABORT, &pc->flags)) {
+	if (pc->retries > IDETAPE_MAX_PC_RETRIES ||
+	    test_bit(PC_ABORT, &pc->flags)) {
 		/*
 		 *	We will "abort" retrying a packet command in case
 		 *	a legitimate error code was received (crossing a
-		 *	filemark, or DMA error in the end of media, for
-		 *	example).
+		 *	filemark, or end of the media, for example).
 		 */
 		if (!test_bit (PC_ABORT, &pc->flags)) {
-			if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD && tape->sense_key == 2 &&
-			      tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8))) {
-				printk (KERN_ERR "ide-tape: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
-					tape->name, pc->c[0], tape->sense_key, tape->asc, tape->ascq);
-				if (tape->onstream && pc->c[0] == IDETAPE_READ_CMD && tape->sense_key == 3 && tape->asc == 0x11)  /* AJN-1: 11 should be 0x11 */
+			if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD &&
+			      tape->sense_key == 2 && tape->asc == 4 &&
+			     (tape->ascq == 1 || tape->ascq == 8))) {
+				printk(KERN_ERR "ide-tape: %s: I/O error, "
+						"pc = %2x, key = %2x, "
+						"asc = %2x, ascq = %2x\n",
+						tape->name, pc->c[0],
+						tape->sense_key, tape->asc,
+						tape->ascq);
+				if (tape->onstream &&
+				    pc->c[0] == IDETAPE_READ_CMD &&
+				    tape->sense_key == 3 &&
+				    tape->asc == 0x11)
+					/* AJN-1: 11 should be 0x11 */
 					printk(KERN_ERR "ide-tape: %s: enabling read error recovery\n", tape->name);
 			}
-			pc->error = IDETAPE_ERROR_GENERAL;		/* Giving up */
+			/* Giving up */
+			pc->error = IDETAPE_ERROR_GENERAL;
 		}
 		tape->failed_pc = NULL;
 		return pc->callback(drive);
 	}
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: Retry number - %d\n", pc->retries);
+		printk(KERN_INFO "ide-tape: Retry number - %d, cmd = %02X\n",
+				pc->retries, pc->c[0]);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	pc->retries++;
-	pc->actually_transferred = 0;					/* We haven't transferred any data yet */
-	pc->current_position=pc->buffer;
-	bcount.all=pc->request_transfer;				/* Request to transfer the entire buffer at once */
+	/* We haven't transferred any data yet */
+	pc->actually_transferred = 0;
+	pc->current_position = pc->buffer;
+	/* Request to transfer the entire buffer at once */
+	bcount.all = pc->request_transfer;
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
-		printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
+		printk(KERN_WARNING "ide-tape: DMA disabled, "
+				"reverting to PIO\n");
+		(void) HWIF(drive)->ide_dma_off(drive);
+	}
+	if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) {
+		if (test_bit(PC_WRITING, &pc->flags)) {
+			feature.b.dma = !HWIF(drive)->ide_dma_write(drive);
+		} else {
+			feature.b.dma = !HWIF(drive)->ide_dma_read(drive);
+		}
 	}
-	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok = !HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
-	OUT_BYTE (dma_ok ? 1 : 0,    IDE_FEATURE_REG);			/* Use PIO/DMA */
-	OUT_BYTE (bcount.b.high,     IDE_BCOUNTH_REG);
-	OUT_BYTE (bcount.b.low,      IDE_BCOUNTL_REG);
-	OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+	/* Use PIO/DMA */
+	HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);
+	HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
+	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
+	HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (dma_ok) {						/* Begin DMA, if necessary */
-		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
-	}
+	if (feature.b.dma)		/* Will begin DMA later */
+		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
-		ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
-		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
+		ide_set_handler(drive,
+				&idetape_transfer_pc,
+				IDETAPE_WAIT_CMD,
+				NULL);
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return ide_started;
 	} else {
-		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return idetape_transfer_pc(drive);
 	}
 }
@@ -2348,22 +2483,22 @@
 		printk (KERN_INFO "ide-tape: Reached idetape_pc_callback\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
-	idetape_end_request (tape->pc->error ? 0 : 1, HWGROUP(drive));
+	idetape_end_request(drive, tape->pc->error ? 0 : 1);
 	return ide_stopped;
 }
 
 /*
  *	A mode sense command is used to "sense" tape parameters.
  */
-static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, byte page_code)
+static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, u8 page_code)
 {
 	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_MODE_SENSE_CMD;
 	if (page_code != IDETAPE_BLOCK_DESCRIPTOR)
-		pc->c[1] = 8;			/* DBD = 1 - Don't return block descriptors */
+		pc->c[1] = 8;	/* DBD = 1 - Don't return block descriptors */
 	pc->c[2] = page_code;
-	pc->c[3] = 255;				/* Don't limit the returned information */
-	pc->c[4] = 255;				/* (We will just discard data in that case) */
+	pc->c[3] = 255;		/* Don't limit the returned information */
+	pc->c[4] = 255;		/* (We will just discard data in that case) */
 	if (page_code == IDETAPE_BLOCK_DESCRIPTOR)
 		pc->request_transfer = 12;
 	else if (page_code == IDETAPE_CAPABILITIES_PAGE)
@@ -2391,13 +2526,15 @@
 	}
 	tape->tape_still_time = (jiffies - tape->tape_still_time_begin) * 1000 / HZ;
 #if USE_IOTRACE
-	IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
+	IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head,
+			tape->tape_head, tape->minor);
 #endif
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 1)
-		printk(KERN_INFO "ide-tape: buffer fill callback, %d/%d\n", tape->cur_frames, tape->max_frames);
+		printk(KERN_INFO "ide-tape: buffer fill callback, %d/%d\n",
+			tape->cur_frames, tape->max_frames);
 #endif
-	idetape_end_request (tape->pc->error ? 0 : 1, HWGROUP(drive));
+	idetape_end_request(drive, tape->pc->error ? 0 : 1);
 	return ide_stopped;
 }
 
@@ -2429,7 +2566,8 @@
 	else if (time_after(jiffies, tape->controlled_previous_head_time))
 		tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_previous_head_time);
 
-	if (tape->nr_pending_stages < tape->max_stages /*- 1 */) { /* -1 for read mode error recovery */
+	if (tape->nr_pending_stages < tape->max_stages /*- 1 */) {
+		/* -1 for read mode error recovery */
 		if (time_after(jiffies, tape->uncontrolled_previous_head_time + 10 * HZ)) {
 			tape->uncontrolled_pipeline_head_time = jiffies;
 			tape->uncontrolled_pipeline_head_speed = (tape->pipeline_head - tape->uncontrolled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->uncontrolled_previous_head_time);
@@ -2465,15 +2603,21 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc = tape->pc;
-	idetape_status_reg_t status;
+	atapi_status_t status;
 
 	if (tape->onstream)
-		printk(KERN_INFO "ide-tape: bug: onstream, media_access_finished\n");
-	status.all = GET_STAT();
+		printk(KERN_INFO "ide-tape: bug: "
+			"onstream, media_access_finished\n");
+
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+
 	if (status.b.dsc) {
-		if (status.b.check) {					/* Error detected */
-			printk (KERN_ERR "ide-tape: %s: I/O error, ",tape->name);
-			return idetape_retry_pc (drive);			/* Retry operation */
+		if (status.b.check) {
+			/* Error detected */
+			printk(KERN_ERR "ide-tape: %s: I/O error, ",
+					tape->name);
+			/* Retry operation */
+			return idetape_retry_pc(drive);
 		}
 		pc->error = 0;
 		if (tape->failed_pc == pc)
@@ -2510,16 +2654,16 @@
 
 #if IDETAPE_DEBUG_LOG	
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_rw_callback\n");
+		printk(KERN_INFO "ide-tape: Reached idetape_rw_callback\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
 	tape->first_frame_position += blocks;
 	rq->current_nr_sectors -= blocks;
 
 	if (!tape->pc->error)
-		idetape_end_request (1, HWGROUP (drive));
+		idetape_end_request(drive, 1);
 	else
-		idetape_end_request (tape->pc->error, HWGROUP (drive));
+		idetape_end_request(drive, tape->pc->error);
 	return ide_stopped;
 }
 
@@ -2528,7 +2672,7 @@
 	struct buffer_head *p = bh;
 	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_READ_CMD;
-	put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
+	put_unaligned(htonl (length), (unsigned int *) &pc->c[1]);
 	pc->c[1] = 1;
 	pc->callback = &idetape_rw_callback;
 	pc->bh = bh;
@@ -2543,11 +2687,11 @@
 	if (!tape->onstream) {
 		pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
 		if (pc->request_transfer == tape->stage_size)
-			set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+			set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 	} else  {
 		if (length) {
 			pc->request_transfer = pc->buffer_size = 32768 + 512;
-			set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+			set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 		} else
 			pc->request_transfer = 0;
 	}
@@ -2558,7 +2702,7 @@
 	int size = 32768;
 
 	struct buffer_head *p = bh;
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_READ_BUFFER_CMD;
 	pc->c[1] = IDETAPE_RETRIEVE_FAULTY_BLOCK;
 	pc->c[7] = size >> 8;
@@ -2577,9 +2721,9 @@
 static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
 {
 	struct buffer_head *p = bh;
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_WRITE_CMD;
-	put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
+	put_unaligned(htonl (length), (unsigned int *) &pc->c[1]);
 	pc->c[1] = 1;
 	pc->callback = &idetape_rw_callback;
 	set_bit (PC_WRITING, &pc->flags);
@@ -2596,17 +2740,49 @@
 	if (!tape->onstream) {
 		pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
 		if (pc->request_transfer == tape->stage_size)
-			set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+			set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 	} else  {
 		if (length) {
 			pc->request_transfer = pc->buffer_size = 32768 + 512;
-			set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+			set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 		} else
 			pc->request_transfer = 0;
 	}
 }
 
 /*
+ * This is our end_request replacement function.
+ */
+static int idetape_do_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		add_blkdev_randomness(MAJOR(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return ret;
+}
+
+/*
  *	idetape_do_request is our request handling function.	
  */
 static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
@@ -2614,35 +2790,42 @@
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc;
 	struct request *postponed_rq = tape->postponed_rq;
-	idetape_status_reg_t status;
+	atapi_status_t status;
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 5)
-		printk (KERN_INFO "ide-tape: rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
+		printk(KERN_INFO "ide-tape: rq_status: %d, "
+			"rq_dev: %u, cmd: %d, errors: %d\n", rq->rq_status,
+			(unsigned int) rq->rq_dev, rq->cmd, rq->errors);
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+		printk(KERN_INFO "ide-tape: sector: %ld, "
+			"nr_sectors: %ld, current_nr_sectors: %ld\n",
+			rq->sector, rq->nr_sectors, rq->current_nr_sectors);
 #endif /* IDETAPE_DEBUG_LOG */
 
-	if (!IDETAPE_RQ_CMD (rq->cmd)) {
+	if (!IDETAPE_RQ_CMD(rq->cmd)) {
 		/*
 		 *	We do not support buffer cache originated requests.
 		 */
-		printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%d)\n", drive->name, rq->cmd);
-		ide_end_request (0, HWGROUP (drive));			/* Let the common code handle it */
+		printk(KERN_NOTICE "ide-tape: %s: Unsupported command in "
+			"request queue (%d)\n", drive->name, rq->cmd);
+		idetape_do_end_request(drive, 0);
 		return ide_stopped;
 	}
 
 	/*
 	 *	Retry a failed packet command
 	 */
-	if (tape->failed_pc != NULL && tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-		return idetape_issue_packet_command (drive, tape->failed_pc);
+	if (tape->failed_pc != NULL &&
+	    tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
+		return idetape_issue_packet_command(drive, tape->failed_pc);
 	}
 #if IDETAPE_DEBUG_BUGS
 	if (postponed_rq != NULL)
 		if (rq != postponed_rq) {
-			printk (KERN_ERR "ide-tape: ide-tape.c bug - Two DSC requests were queued\n");
-			idetape_end_request (0, HWGROUP (drive));
+			printk(KERN_ERR "ide-tape: ide-tape.c bug - "
+					"Two DSC requests were queued\n");
+			idetape_end_request(drive, 0);
 			return ide_stopped;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -2653,7 +2836,7 @@
 	 *	If the tape is still busy, postpone our request and service
 	 *	the other device meanwhile.
 	 */
-	status.all = GET_STAT();
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 
 	/*
 	 * The OnStream tape drive doesn't support DSC. Assume
@@ -2662,7 +2845,7 @@
 	if (tape->onstream)
 		status.b.dsc = 1;
 	if (!drive->dsc_overlap && rq->cmd != IDETAPE_PC_RQ2)
-		set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
+		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
 
 	/*
 	 * For the OnStream tape, check the current status of the tape
@@ -2674,7 +2857,8 @@
 	 */
 	if (tape->tape_still_time > 100 && tape->tape_still_time < 200)
 		tape->measure_insert_time = 1;
-	if (tape->req_buffer_fill && (rq->cmd == IDETAPE_WRITE_RQ || rq->cmd == IDETAPE_READ_RQ)) {
+	if (tape->req_buffer_fill &&
+	    (rq->cmd == IDETAPE_WRITE_RQ || rq->cmd == IDETAPE_READ_RQ)) {
 		tape->req_buffer_fill = 0;
 		tape->writes_since_buffer_fill = 0;
 		tape->reads_since_buffer_fill = 0;
@@ -2699,7 +2883,8 @@
 			tape->insert_speed > tape->max_insert_speed ) ) && rq->nr_sectors) ) ) {
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 4)
-			printk(KERN_INFO "ide-tape: postponing request, cmd %d, cur %d, max %d\n",
+			printk(KERN_INFO "ide-tape: postponing request, "
+					"cmd %d, cur %d, max %d\n",
 				rq->cmd, tape->cur_frames, tape->max_frames);
 #endif
 		if (tape->postpone_cnt++ < 500) {
@@ -2708,25 +2893,28 @@
 		}
 #if ONSTREAM_DEBUG
 		else if (tape->debug_level >= 4) 
-			printk(KERN_INFO "ide-tape: %s: postpone_cnt %d\n", tape->name, tape->postpone_cnt);
+			printk(KERN_INFO "ide-tape: %s: postpone_cnt %d\n",
+				tape->name, tape->postpone_cnt);
 #endif
 	}
-	if (!test_and_clear_bit (IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) {
+	if (!test_and_clear_bit(IDETAPE_IGNORE_DSC, &tape->flags) &&
+	    !status.b.dsc) {
 		if (postponed_rq == NULL) {
 			tape->dsc_polling_start = jiffies;
 			tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
 			tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
 		} else if ((signed long) (jiffies - tape->dsc_timeout) > 0) {
-			printk (KERN_ERR "ide-tape: %s: DSC timeout\n", tape->name);
+			printk(KERN_ERR "ide-tape: %s: DSC timeout\n",
+				tape->name);
 			if (rq->cmd == IDETAPE_PC_RQ2) {
-				idetape_media_access_finished (drive);
+				idetape_media_access_finished(drive);
 				return ide_stopped;
 			} else {
-				return ide_do_reset (drive);
+				return ide_do_reset(drive);
 			}
 		} else if (jiffies - tape->dsc_polling_start > IDETAPE_DSC_MA_THRESHOLD)
 			tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW;
-		idetape_postpone_request (drive);
+		idetape_postpone_request(drive);
 		return ide_stopped;
 	}
 	switch (rq->cmd) {
@@ -2743,8 +2931,8 @@
 				if (time_after(jiffies, tape->last_buffer_fill + 5 * HZ / 100))
 					tape->req_buffer_fill = 1;
 			}
-			pc = idetape_next_pc_storage (drive);
-			idetape_create_read_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			pc = idetape_next_pc_storage(drive);
+			idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, rq->bh);
 			break;
 		case IDETAPE_WRITE_RQ:
 			tape->buffer_head++;
@@ -2760,39 +2948,41 @@
 					tape->req_buffer_fill = 1;
 				calculate_speeds(drive);
 			}
-			pc = idetape_next_pc_storage (drive);
-			idetape_create_write_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			pc = idetape_next_pc_storage(drive);
+			idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, rq->bh);
 			break;
 		case IDETAPE_READ_BUFFER_RQ:
 			tape->postpone_cnt = 0;
-			pc = idetape_next_pc_storage (drive);
-			idetape_create_read_buffer_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			pc = idetape_next_pc_storage(drive);
+			idetape_create_read_buffer_cmd(tape, pc, rq->current_nr_sectors, rq->bh);
 			break;
 		case IDETAPE_ABORTED_WRITE_RQ:
 			rq->cmd = IDETAPE_WRITE_RQ;
-			idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
+			idetape_end_request(drive, IDETAPE_ERROR_EOD);
 			return ide_stopped;
 		case IDETAPE_ABORTED_READ_RQ:
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 2)
-				printk(KERN_INFO "ide-tape: %s: detected aborted read rq\n", tape->name);
+				printk(KERN_INFO "ide-tape: %s: detected "
+					"aborted read rq\n", tape->name);
 #endif
 			rq->cmd = IDETAPE_READ_RQ;
-			idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
+			idetape_end_request(drive, IDETAPE_ERROR_EOD);
 			return ide_stopped;
 		case IDETAPE_PC_RQ1:
 			pc = (idetape_pc_t *) rq->buffer;
 			rq->cmd = IDETAPE_PC_RQ2;
 			break;
 		case IDETAPE_PC_RQ2:
-			idetape_media_access_finished (drive);
+			idetape_media_access_finished(drive);
 			return ide_stopped;
 		default:
-			printk (KERN_ERR "ide-tape: bug in IDETAPE_RQ_CMD macro\n");
-			idetape_end_request (0, HWGROUP (drive));
+			printk(KERN_ERR "ide-tape: bug in "
+				"IDETAPE_RQ_CMD macro\n");
+			idetape_end_request(drive, 0);
 			return ide_stopped;
 	}
-	return idetape_issue_packet_command (drive, pc);
+	return idetape_issue_packet_command(drive, pc);
 }
 
 /*
@@ -2826,11 +3016,11 @@
 	int pages = tape->pages_per_stage;
 	char *b_data;
 
-	if ((stage = (idetape_stage_t *) kmalloc (sizeof (idetape_stage_t),GFP_KERNEL)) == NULL)
+	if ((stage = (idetape_stage_t *) kmalloc(sizeof(idetape_stage_t),GFP_KERNEL)) == NULL)
 		return NULL;
 	stage->next = NULL;
 
-	bh = stage->bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL);
+	bh = stage->bh = (struct buffer_head *) kmalloc(sizeof(struct buffer_head), GFP_KERNEL);
 	if (bh == NULL)
 		goto abort;
 	bh->b_reqnext = NULL;
@@ -2840,7 +3030,7 @@
 		memset(bh->b_data, 0, PAGE_SIZE);
 	bh->b_size = PAGE_SIZE;
 	atomic_set(&bh->b_count, full ? bh->b_size : 0);
-	set_bit (BH_Lock, &bh->b_state);
+	set_bit(BH_Lock, &bh->b_state);
 
 	while (--pages) {
 		if ((b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
@@ -2861,15 +3051,15 @@
 			continue;
 		}
 		prev_bh = bh;
-		if ((bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL)) == NULL) {
-			free_page ((unsigned long) b_data);
+		if ((bh = (struct buffer_head *) kmalloc(sizeof(struct buffer_head), GFP_KERNEL)) == NULL) {
+			free_page((unsigned long) b_data);
 			goto abort;
 		}
 		bh->b_reqnext = NULL;
 		bh->b_data = b_data;
 		bh->b_size = PAGE_SIZE;
 		atomic_set(&bh->b_count, full ? bh->b_size : 0);
-		set_bit (BH_Lock, &bh->b_state);
+		set_bit(BH_Lock, &bh->b_state);
 		prev_bh->b_reqnext = bh;
 	}
 	bh->b_size -= tape->excess_bh_size;
@@ -2879,7 +3069,7 @@
 		stage->aux = (os_aux_t *) (bh->b_data + bh->b_size - OS_AUX_SIZE);
 	return stage;
 abort:
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 	return NULL;
 }
 
@@ -2889,7 +3079,7 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_kmalloc_stage\n");
+		printk (KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	if (tape->nr_stages >= tape->max_stages)
@@ -2898,7 +3088,7 @@
 		tape->cache_stage = NULL;
 		return cache_stage;
 	}
-	return __idetape_kmalloc_stage (tape, 0, 0);
+	return __idetape_kmalloc_stage(tape, 0, 0);
 }
 
 static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char *buf, int n)
@@ -2909,12 +3099,13 @@
 	while (n) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_from_user\n");
+			printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+				__FUNCTION__);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), n);
-		copy_from_user (bh->b_data + atomic_read(&bh->b_count), buf, count);
+		count = IDE_MIN(bh->b_size - atomic_read(&bh->b_count), n);
+		copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count);
 		n -= count;
 		atomic_add(count, &bh->b_count);
 		buf += count;
@@ -2935,12 +3126,13 @@
 	while (n) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_to_user\n");
+			printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+				__FUNCTION__);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (tape->b_count, n);
-		copy_to_user (buf, tape->b_data, count);
+		count = IDE_MIN(tape->b_count, n);
+		copy_to_user(buf, tape->b_data, count);
 		n -= count;
 		tape->b_data += count;
 		tape->b_count -= count;
@@ -2960,9 +3152,9 @@
 	struct buffer_head *bh = tape->merge_stage->bh;
 	
 	tape->bh = bh;
-	if (tape->chrdev_direction == idetape_direction_write)
+	if (tape->chrdev_direction == idetape_direction_write) {
 		atomic_set(&bh->b_count, 0);
-	else {
+	} else {
 		tape->b_data = bh->b_data;
 		tape->b_count = atomic_read(&bh->b_count);
 	}
@@ -2973,9 +3165,12 @@
 	struct buffer_head *tmp;
 	os_aux_t *tmp_aux;
 
-	tmp = stage->bh; tmp_aux = stage->aux;
-	stage->bh = tape->merge_stage->bh; stage->aux = tape->merge_stage->aux;
-	tape->merge_stage->bh = tmp; tape->merge_stage->aux = tmp_aux;
+	tmp = stage->bh;
+	tmp_aux = stage->aux;
+	stage->bh = tape->merge_stage->bh;
+	stage->aux = tape->merge_stage->aux;
+	tape->merge_stage->bh = tmp;
+	tape->merge_stage->aux = tmp_aux;
 	idetape_init_merge_stage (tape);
 }
 
@@ -2989,10 +3184,10 @@
 	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_add_stage_tail\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 	spin_lock_irqsave(&tape->spinlock, flags);
-	stage->next=NULL;
+	stage->next = NULL;
 	if (tape->last_stage != NULL)
 		tape->last_stage->next=stage;
 	else
@@ -3058,10 +3253,13 @@
 		else
 			dat->dat_list[0].flags = OS_DAT_FLAGS_DATA;
 		dat->dat_list[0].reserved = 0;
-	} 
-	aux->filemark_cnt = ntohl(tape->filemark_cnt);		/* shouldn't this be htonl ?? */
-	aux->phys_fm = ntohl(0xffffffff);			/* shouldn't this be htonl ?? */
-	aux->last_mark_addr = ntohl(tape->last_mark_addr);	/* shouldn't this be htonl ?? */
+	}
+	/* shouldn't this be htonl ?? */
+	aux->filemark_cnt = ntohl(tape->filemark_cnt);
+	/* shouldn't this be htonl ?? */
+	aux->phys_fm = ntohl(0xffffffff);
+	/* shouldn't this be htonl ?? */
+	aux->last_mark_addr = ntohl(tape->last_mark_addr);
 }
 
 /*
@@ -3078,7 +3276,8 @@
 
 #if IDETAPE_DEBUG_BUGS
 	if (rq == NULL || !IDETAPE_RQ_CMD (rq->cmd)) {
-		printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n");
+		printk(KERN_ERR "ide-tape: bug: Trying to sleep on "
+			"non-valid request\n");
 		return;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -3086,7 +3285,7 @@
 	tape->waiting = &wait;
 	spin_unlock(&tape->spinlock);
 	wait_for_completion(&wait);
-	rq->waiting = NULL;
+	/* The stage and its struct request have been deallocated */
 	tape->waiting = NULL;
 	spin_lock_irq(&tape->spinlock);
 }
@@ -3098,35 +3297,39 @@
 	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_read_position_callback\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	if (!tape->pc->error) {
 		result = (idetape_read_position_result_t *) tape->pc->buffer;
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 2)
-			printk (KERN_INFO "ide-tape: BOP - %s\n",result->bop ? "Yes":"No");
+			printk(KERN_INFO "ide-tape: BOP - %s\n",
+				result->bop ? "Yes":"No");
 		if (tape->debug_level >= 2)
-			printk (KERN_INFO "ide-tape: EOP - %s\n",result->eop ? "Yes":"No");
+			printk(KERN_INFO "ide-tape: EOP - %s\n",
+				result->eop ? "Yes":"No");
 #endif /* IDETAPE_DEBUG_LOG */
 		if (result->bpu) {
-			printk (KERN_INFO "ide-tape: Block location is unknown to the tape\n");
-			clear_bit (IDETAPE_ADDRESS_VALID, &tape->flags);
-			idetape_end_request (0, HWGROUP (drive));
+			printk(KERN_INFO "ide-tape: Block location is "
+				"unknown to the tape\n");
+			clear_bit(IDETAPE_ADDRESS_VALID, &tape->flags);
+			idetape_end_request(drive, 0);
 		} else {
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 2)
-				printk (KERN_INFO "ide-tape: Block Location - %u\n", ntohl (result->first_block));
+				printk(KERN_INFO "ide-tape: Block Location "
+					"- %u\n", ntohl(result->first_block));
 #endif /* IDETAPE_DEBUG_LOG */
 			tape->partition = result->partition;
-			tape->first_frame_position = ntohl (result->first_block);
-			tape->last_frame_position = ntohl (result->last_block);
+			tape->first_frame_position = ntohl(result->first_block);
+			tape->last_frame_position = ntohl(result->last_block);
 			tape->blocks_in_buffer = result->blocks_in_buffer[2];
-			set_bit (IDETAPE_ADDRESS_VALID, &tape->flags);
-			idetape_end_request (1, HWGROUP (drive));
+			set_bit(IDETAPE_ADDRESS_VALID, &tape->flags);
+			idetape_end_request(drive, 1);
 		}
 	} else {
-		idetape_end_request (0, HWGROUP (drive));
+		idetape_end_request(drive, 0);
 	}
 	return ide_stopped;
 }
@@ -3143,12 +3346,12 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_WRITE_FILEMARK_CMD;
 	if (tape->onstream)
 		pc->c[1] = 1; /* Immed bit */
 	pc->c[4] = write_filemark;  /* not used for OnStream ?? */
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
@@ -3165,8 +3368,8 @@
  *	ide_do_drive_cmd from ide.c
  *	cdrom_queue_request and cdrom_queue_packet_command from ide-cd.c
  *
- *	We add a special packet command request to the tail of the request queue,
- *	and wait for it to be serviced.
+ *	We add a special packet command request to the tail of the request
+ *	queue, and wait for it to be serviced.
  *
  *	This is not to be called from within the request handling part
  *	of the driver ! We allocate here data in the stack, and it is valid
@@ -3183,17 +3386,17 @@
 {
 	struct request rq;
 
-	ide_init_drive_cmd (&rq);
+	ide_init_drive_cmd(&rq);
 	rq.buffer = (char *) pc;
 	rq.cmd = IDETAPE_PC_RQ1;
-	return ide_do_drive_cmd (drive, &rq, ide_wait);
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
 static void idetape_create_load_unload_cmd (ide_drive_t *drive, idetape_pc_t *pc,int cmd)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_LOAD_UNLOAD_CMD;
 	pc->c[4] = cmd;
 	if (tape->onstream) {
@@ -3201,7 +3404,7 @@
 		if (cmd == !IDETAPE_LU_LOAD_MASK)
 			pc->c[4] = 4;
 	}
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
@@ -3219,13 +3422,14 @@
 		if (!__idetape_queue_pc_tail(drive, &pc))
 			return 0;
 		if (tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2) {
-			idetape_create_load_unload_cmd (drive, &pc, IDETAPE_LU_LOAD_MASK);
+			idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK);
 			__idetape_queue_pc_tail(drive, &pc);
 			idetape_create_test_unit_ready_cmd(&pc);
 			if (!__idetape_queue_pc_tail(drive, &pc))
 				return 0;
 		}
-		if (!(tape->sense_key == 2 && tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8)))
+		if (!(tape->sense_key == 2 && tape->asc == 4 &&
+		    (tape->ascq == 1 || tape->ascq == 8)))
 			break;
 		current->state = TASK_INTERRUPTIBLE;
   		schedule_timeout(HZ / 10);
@@ -3241,9 +3445,13 @@
 	rc = __idetape_queue_pc_tail(drive, pc);
 	if (rc)
 		return rc;
-	if (tape->onstream && test_bit(PC_WAIT_FOR_DSC, &pc->flags))
-		rc = idetape_wait_ready(drive, 60 * 10 * HZ);   /* AJN-4: Changed from 5 to 10 minutes;
-                          because retension takes approx. 8:20 with Onstream 30GB tape */
+	if (tape->onstream && test_bit(PC_WAIT_FOR_DSC, &pc->flags)) {
+		/* AJN-4: Changed from 5 to 10 minutes;
+		 * because retension takes approx.
+		 * 8:20 with Onstream 30GB tape
+		 */
+		rc = idetape_wait_ready(drive, 60 * 10 * HZ);
+	}
 	return rc;
 }
 
@@ -3261,7 +3469,7 @@
 
 static void idetape_create_read_position_cmd (idetape_pc_t *pc)
 {
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_READ_POSITION_CMD;
 	pc->request_transfer = 20;
 	pc->callback = &idetape_read_position_callback;
@@ -3275,14 +3483,14 @@
 
 #if IDETAPE_DEBUG_LOG
         if (tape->debug_level >= 4)
-	printk (KERN_INFO "ide-tape: Reached idetape_read_position\n");
+		printk (KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
 #ifdef NO_LONGER_REQUIRED
 	idetape_flush_tape_buffers(drive);
 #endif
 	idetape_create_read_position_cmd(&pc);
-	if (idetape_queue_pc_tail (drive, &pc))
+	if (idetape_queue_pc_tail(drive, &pc))
 		return -1;
 	position = tape->first_frame_position;
 #ifdef NO_LONGER_REQUIRED
@@ -3290,7 +3498,11 @@
 		if ((position != tape->last_frame_position - tape->blocks_in_buffer) &&
 		    (position != tape->last_frame_position + tape->blocks_in_buffer)) {
 			if (tape->blocks_in_buffer == 0) {
-				printk("ide-tape: %s: correcting read position %d, %d, %d\n", tape->name, position, tape->last_frame_position, tape->blocks_in_buffer);
+				printk("ide-tape: %s: correcting read "
+					"position %d, %d, %d\n",
+					tape->name, position,
+					tape->last_frame_position,
+					tape->blocks_in_buffer);
 				position = tape->last_frame_position;
 				tape->first_frame_position = position;
 			}
@@ -3300,17 +3512,17 @@
 	return position;
 }
 
-static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, unsigned int block, byte partition, int skip)
+static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, unsigned int block, u8 partition, int skip)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_LOCATE_CMD;
 	if (tape->onstream)
 		pc->c[1] = 1; /* Immediate bit */
 	else
 		pc->c[1] = 2;
-	put_unaligned (htonl (block), (unsigned int *) &pc->c[3]);
+	put_unaligned(htonl(block), (unsigned int *) &pc->c[3]);
 	pc->c[8] = partition;
 	if (tape->onstream)
                 /*
@@ -3319,7 +3531,7 @@
                  * data in the drive to this new position!
                  */
 		pc->c[9] = skip << 7;
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
@@ -3345,11 +3557,15 @@
 
 	if (tape->chrdev_direction != idetape_direction_read)
 		return 0;
+	cnt = tape->merge_stage_size / tape->tape_block_size;
+	if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags))
+		++cnt;		/* Filemarks count as 1 sector */
 	tape->merge_stage_size = 0;
 	if (tape->merge_stage != NULL) {
-		__idetape_kfree_stage (tape->merge_stage);
+		__idetape_kfree_stage(tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
+	clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 	tape->chrdev_direction = idetape_direction_none;
 	
 	if (tape->first_stage == NULL)
@@ -3357,13 +3573,18 @@
 
 	spin_lock_irqsave(&tape->spinlock, flags);
 	tape->next_stage = NULL;
-	if (idetape_pipeline_active (tape))
+	if (idetape_pipeline_active(tape))
 		idetape_wait_for_request(drive, tape->active_data_request);
 	spin_unlock_irqrestore(&tape->spinlock, flags);
 
-	cnt = tape->nr_stages - tape->nr_pending_stages;
-	while (tape->first_stage != NULL)
-		idetape_remove_stage_head (drive);
+	while (tape->first_stage != NULL) {
+		struct request *rq_ptr = &tape->first_stage->rq;
+
+		cnt += rq_ptr->nr_sectors - rq_ptr->current_nr_sectors; 
+		if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
+			++cnt;
+		idetape_remove_stage_head(drive);
+	}
 	tape->nr_pending_stages = 0;
 	tape->max_stages = tape->min_pipeline;
 	return cnt;
@@ -3378,7 +3599,7 @@
  *	of the request queue and wait for their completion.
  *	
  */
-static int idetape_position_tape (ide_drive_t *drive, unsigned int block, byte partition, int skip)
+static int idetape_position_tape (ide_drive_t *drive, unsigned int block, u8 partition, int skip)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int retval;
@@ -3387,13 +3608,13 @@
 	if (tape->chrdev_direction == idetape_direction_read)
 		__idetape_discard_read_pipeline(drive);
 	idetape_wait_ready(drive, 60 * 5 * HZ);
-	idetape_create_locate_cmd (drive, &pc, block, partition, skip);
-	retval = idetape_queue_pc_tail (drive, &pc);
+	idetape_create_locate_cmd(drive, &pc, block, partition, skip);
+	retval = idetape_queue_pc_tail(drive, &pc);
 	if (retval)
 		return (retval);
 
-	idetape_create_read_position_cmd (&pc);
-	return (idetape_queue_pc_tail (drive, &pc));
+	idetape_create_read_position_cmd(&pc);
+	return (idetape_queue_pc_tail(drive, &pc));
 }
 
 static void idetape_discard_read_pipeline (ide_drive_t *drive, int restore_position)
@@ -3407,11 +3628,13 @@
 		position = idetape_read_position(drive);
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: address %u, nr_stages %d\n", position, cnt);
+			printk(KERN_INFO "ide-tape: address %u, nr_stages %d\n",
+				position, cnt);
 #endif
 		seek = position > cnt ? position - cnt : 0;
 		if (idetape_position_tape(drive, seek, 0, 0)) {
-			printk(KERN_INFO "ide-tape: %s: position_tape failed in discard_pipeline()\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: position_tape "
+				"failed in discard_pipeline()\n", tape->name);
 			return;
 		}
 	}
@@ -3421,7 +3644,7 @@
 {
 	idetape_pc_t pc;
 
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_BUFFER_FILLING_PAGE);
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_BUFFER_FILLING_PAGE);
 	pc.callback = idetape_onstream_buffer_fill_callback;
 	(void) idetape_queue_pc_tail(drive, &pc);
 }
@@ -3437,29 +3660,30 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: idetape_queue_rw_tail: cmd=%d\n",cmd);
+		printk(KERN_INFO "ide-tape: %s: cmd=%d\n", __FUNCTION__, cmd);
 #endif /* IDETAPE_DEBUG_LOG */
 #if IDETAPE_DEBUG_BUGS
 	if (idetape_pipeline_active (tape)) {
-		printk (KERN_ERR "ide-tape: bug: the pipeline is active in idetape_queue_rw_tail\n");
+		printk(KERN_ERR "ide-tape: bug: the pipeline is active in %s\n",
+			__FUNCTION__);
 		return (0);
 	}
 #endif /* IDETAPE_DEBUG_BUGS */	
 
-	ide_init_drive_cmd (&rq);
+	ide_init_drive_cmd(&rq);
 	rq.bh = bh;
 	rq.cmd = cmd;
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
 	if (tape->onstream)
 		tape->postpone_cnt = 600;
-	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
+	(void) ide_do_drive_cmd(drive, &rq, ide_wait);
 
 	if (cmd != IDETAPE_READ_RQ && cmd != IDETAPE_WRITE_RQ)
 		return 0;
 
 	if (tape->merge_stage)
-		idetape_init_merge_stage (tape);
+		idetape_init_merge_stage(tape);
 	if (rq.errors == IDETAPE_ERROR_GENERAL)
 		return -EIO;
 	return (tape->tape_block_size * (blocks-rq.current_nr_sectors));
@@ -3517,7 +3741,8 @@
 	idetape_update_stats(drive);
 #if ONSTREAM_DEBUG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: %s: frames left in buffer: %d\n", tape->name, tape->cur_frames);
+		printk(KERN_INFO "ide-tape: %s: frames left in buffer: %d\n",
+			tape->name, tape->cur_frames);
 #endif
 }
 
@@ -3578,12 +3803,12 @@
 
 	if (tape->next_stage == NULL)
 		return;
-	if (!idetape_pipeline_active (tape)) {
+	if (!idetape_pipeline_active(tape)) {
 		if (tape->onstream_write_error)
 			idetape_onstream_write_error_recovery(drive);
 		set_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
-		idetape_active_next_stage (drive);
-		(void) ide_do_drive_cmd (drive, tape->active_data_request, ide_end);
+		idetape_active_next_stage(drive);
+		(void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
 	}
 }
 
@@ -3599,41 +3824,41 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_REWIND_CMD;
 	if (tape->onstream)
 		pc->c[1] = 1;
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
 static void idetape_create_mode_select_cmd (idetape_pc_t *pc, int length)
 {
-	idetape_init_pc (pc);
-	set_bit (PC_WRITING, &pc->flags);
+	idetape_init_pc(pc);
+	set_bit(PC_WRITING, &pc->flags);
 	pc->c[0] = IDETAPE_MODE_SELECT_CMD;
 	pc->c[1] = 0x10;
-	put_unaligned (htons(length), (unsigned short *) &pc->c[3]);
+	put_unaligned(htons(length), (unsigned short *) &pc->c[3]);
 	pc->request_transfer = 255;
 	pc->callback = &idetape_pc_callback;
 }
 
 static void idetape_create_erase_cmd (idetape_pc_t *pc)
 {
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_ERASE_CMD;
 	pc->c[1] = 1;
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
-static void idetape_create_space_cmd (idetape_pc_t *pc,int count,byte cmd)
+static void idetape_create_space_cmd (idetape_pc_t *pc,int count,u8 cmd)
 {
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_SPACE_CMD;
-	put_unaligned (htonl (count), (unsigned int *) &pc->c[1]);
+	put_unaligned(htonl (count), (unsigned int *) &pc->c[1]);
 	pc->c[1] = cmd;
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
@@ -3662,48 +3887,70 @@
 		return 1;
 	}
 	if (rq->errors == IDETAPE_ERROR_GENERAL) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, read error\n", tape->name, tape->first_frame_position);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"read error\n", tape->name, tape->first_frame_position);
 		return 0;
 	}
 	if (rq->errors == IDETAPE_ERROR_EOD) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, eod\n", tape->name, tape->first_frame_position);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, eod\n",
+			tape->name, tape->first_frame_position);
 		return 0;
 	}
 	if (ntohl(aux->format_id) != 0) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, format_id %u\n", tape->name, tape->first_frame_position, ntohl(aux->format_id));
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"format_id %u\n", tape->name,
+			tape->first_frame_position, ntohl(aux->format_id));
 		return 0;
 	}
 	if (memcmp(aux->application_sig, tape->application_sig, 4) != 0) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, incorrect application signature\n", tape->name, tape->first_frame_position);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"incorrect application signature\n",
+			tape->name, tape->first_frame_position);
 		return 0;
 	}
 	if (aux->frame_type != OS_FRAME_TYPE_DATA &&
 	    aux->frame_type != OS_FRAME_TYPE_EOD &&
 	    aux->frame_type != OS_FRAME_TYPE_MARKER) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, frame type %x\n", tape->name, tape->first_frame_position, aux->frame_type);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, frame "
+			"type %x\n", tape->name,
+			tape->first_frame_position, aux->frame_type);
 		return 0;
 	}
 	if (par->partition_num != OS_DATA_PARTITION) {
 		if (!tape->linux_media || tape->linux_media_version != 2) {
-			printk(KERN_INFO "ide-tape: %s: skipping frame %d, partition num %d\n", tape->name, tape->first_frame_position, par->partition_num);
+			printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+				"partition num %d\n", tape->name,
+				tape->first_frame_position, par->partition_num);
 			return 0;
 		}
 	}
 	if (par->par_desc_ver != OS_PARTITION_VERSION) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, partition version %d\n", tape->name, tape->first_frame_position, par->par_desc_ver);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"partition version %d\n", tape->name,
+			tape->first_frame_position, par->par_desc_ver);
 		return 0;
 	}
 	if (ntohs(par->wrt_pass_cntr) != tape->wrt_pass_cntr) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, wrt_pass_cntr %d (expected %d)(logical_blk_num %u)\n", tape->name, tape->first_frame_position, ntohs(par->wrt_pass_cntr), tape->wrt_pass_cntr, ntohl(aux->logical_blk_num));
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"wrt_pass_cntr %d (expected %d)(logical_blk_num %u)\n",
+			tape->name, tape->first_frame_position,
+			ntohs(par->wrt_pass_cntr), tape->wrt_pass_cntr,
+			ntohl(aux->logical_blk_num));
 		return 0;
 	}
 	if (aux->frame_seq_num != aux->logical_blk_num) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, seq != logical\n", tape->name, tape->first_frame_position);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"seq != logical\n", tape->name,
+			tape->first_frame_position);
 		return 0;
 	}
-	if (logical_blk_num != -1 && ntohl(aux->logical_blk_num) != logical_blk_num) {
+	if (logical_blk_num != -1 &&
+	     ntohl(aux->logical_blk_num) != logical_blk_num) {
 		if (!quiet)
-			printk(KERN_INFO "ide-tape: %s: skipping frame %d, logical_blk_num %u (expected %d)\n", tape->name, tape->first_frame_position, ntohl(aux->logical_blk_num), logical_blk_num);
+			printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+				"logical_blk_num %u (expected %d)\n",
+				tape->name, tape->first_frame_position,
+				ntohl(aux->logical_blk_num), logical_blk_num);
 		return 0;
 	}
 	if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
@@ -3746,7 +3993,7 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_add_chrdev_write_request\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
      	/*
@@ -3755,31 +4002,32 @@
 	 */
 	while ((new_stage = idetape_kmalloc_stage (tape)) == NULL) {
 		spin_lock_irqsave(&tape->spinlock, flags);
-		if (idetape_pipeline_active (tape)) {
+		if (idetape_pipeline_active(tape)) {
 			idetape_wait_for_request(drive, tape->active_data_request);
 			spin_unlock_irqrestore(&tape->spinlock, flags);
 		} else {
 			spin_unlock_irqrestore(&tape->spinlock, flags);
-			idetape_insert_pipeline_into_queue (drive);
-			if (idetape_pipeline_active (tape))
+			idetape_insert_pipeline_into_queue(drive);
+			if (idetape_pipeline_active(tape))
 				continue;
 			/*
 			 *	Linux is short on memory. Fallback to
 			 *	non-pipelined operation mode for this request.
 			 */
-			return idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
+			return idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
 		}
 	}
 	rq = &new_stage->rq;
-	ide_init_drive_cmd (rq);
+	ide_init_drive_cmd(rq);
 	rq->cmd = IDETAPE_WRITE_RQ;
-	rq->sector = tape->first_frame_position;	/* Doesn't actually matter - We always assume sequential access */
+	/* Doesn't actually matter - We always assume sequential access */
+	rq->sector = tape->first_frame_position;
 	rq->nr_sectors = rq->current_nr_sectors = blocks;
 
 	idetape_switch_buffers (tape, new_stage);
 	idetape_init_stage(drive, new_stage, OS_FRAME_TYPE_DATA, tape->logical_blk_num);
 	tape->logical_blk_num++;
-	idetape_add_stage_tail (drive, new_stage);
+	idetape_add_stage_tail(drive, new_stage);
 	tape->pipeline_head++;
 #if USE_IOTRACE
 	IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
@@ -3813,10 +4061,11 @@
 		} else if (tape->onstream) {
 			idetape_update_stats(drive);
 			if (tape->cur_frames > 5)
-				idetape_insert_pipeline_into_queue (drive);
+				idetape_insert_pipeline_into_queue(drive);
 		}
 	}
-	if (test_and_clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags))		/* Return a deferred error */
+	if (test_and_clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
+		/* Return a deferred error */
 		return -EIO;
 	return blocks;
 }
@@ -3831,7 +4080,7 @@
 	unsigned long flags;
 
 	while (tape->next_stage || idetape_pipeline_active(tape)) {
-		idetape_insert_pipeline_into_queue (drive);
+		idetape_insert_pipeline_into_queue(drive);
 		spin_lock_irqsave(&tape->spinlock, flags);
 		if (idetape_pipeline_active(tape))
 			idetape_wait_for_request(drive, tape->active_data_request);
@@ -3847,11 +4096,12 @@
 	
 #if IDETAPE_DEBUG_BUGS
 	if (tape->chrdev_direction != idetape_direction_write) {
-		printk (KERN_ERR "ide-tape: bug: Trying to empty write pipeline, but we are not writing.\n");
+		printk(KERN_ERR "ide-tape: bug: Trying to empty write "
+			"pipeline, but we are not writing.\n");
 		return;
 	}
 	if (tape->merge_stage_size > tape->stage_size) {
-		printk (KERN_ERR "ide-tape: bug: merge_buffer too big\n");
+		printk(KERN_ERR "ide-tape: bug: merge_buffer too big\n");
 		tape->merge_stage_size = tape->stage_size;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -3878,15 +4128,15 @@
 				bh = bh->b_reqnext;
 			}
 		}
-		(void) idetape_add_chrdev_write_request (drive, blocks);
+		(void) idetape_add_chrdev_write_request(drive, blocks);
 		tape->merge_stage_size = 0;
 	}
-	idetape_wait_for_pipeline (drive);
+	idetape_wait_for_pipeline(drive);
 	if (tape->merge_stage != NULL) {
-		__idetape_kfree_stage (tape->merge_stage);
+		__idetape_kfree_stage(tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
-	clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+	clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 	tape->chrdev_direction = idetape_direction_none;
 
 	/*
@@ -3897,10 +4147,14 @@
 	 */
 	tape->max_stages = tape->min_pipeline;
 #if IDETAPE_DEBUG_BUGS
-	if (tape->first_stage != NULL || tape->next_stage != NULL || tape->last_stage != NULL || tape->nr_stages != 0) {
-		printk (KERN_ERR "ide-tape: ide-tape pipeline bug, "
-		"first_stage %p, next_stage %p, last_stage %p, nr_stages %d\n",
-		tape->first_stage, tape->next_stage, tape->last_stage, tape->nr_stages);
+	if (tape->first_stage != NULL ||
+	    tape->next_stage != NULL ||
+	    tape->last_stage != NULL ||
+	    tape->nr_stages != 0) {
+		printk(KERN_ERR "ide-tape: ide-tape pipeline bug, "
+			"first_stage %p, next_stage %p, last_stage %p, "
+			"nr_stages %d\n", tape->first_stage,
+			tape->next_stage, tape->last_stage, tape->nr_stages);
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 }
@@ -3928,14 +4182,16 @@
 	int bytes_read;
 	int blocks = tape->capabilities.ctl;
 
-	if (tape->chrdev_direction != idetape_direction_read) {		/* Initialize read operation */
+	/* Initialize read operation */
+	if (tape->chrdev_direction != idetape_direction_read) {
 		if (tape->chrdev_direction == idetape_direction_write) {
-			idetape_empty_write_pipeline (drive);
-			idetape_flush_tape_buffers (drive);
+			idetape_empty_write_pipeline(drive);
+			idetape_flush_tape_buffers(drive);
 		}
 #if IDETAPE_DEBUG_BUGS
 		if (tape->merge_stage || tape->merge_stage_size) {
-			printk (KERN_ERR "ide-tape: merge_stage_size should be 0 now\n");
+			printk(KERN_ERR "ide-tape: merge_stage_size "
+				"should be 0 now\n");
 			tape->merge_stage_size = 0;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -3949,9 +4205,9 @@
 		 *	is switched from completion mode to buffer available
 		 *	mode.
 		 */
-		bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bh);
+		bytes_read = idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bh);
 		if (bytes_read < 0) {
-			kfree (tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 			tape->chrdev_direction = idetape_direction_none;
 			return bytes_read;
@@ -3959,18 +4215,19 @@
 	}
 	if (tape->restart_speed_control_req)
 		idetape_restart_speed_control(drive);
-	ide_init_drive_cmd (&rq);
+	ide_init_drive_cmd(&rq);
 	rq.cmd = IDETAPE_READ_RQ;
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
-	if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) && tape->nr_stages <= max_stages) {
-		new_stage = idetape_kmalloc_stage (tape);
+	if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) &&
+	    tape->nr_stages < max_stages) {
+		new_stage = idetape_kmalloc_stage(tape);
 		while (new_stage != NULL) {
 			new_stage->rq = rq;
-			idetape_add_stage_tail (drive, new_stage);
+			idetape_add_stage_tail(drive, new_stage);
 			if (tape->nr_stages >= max_stages)
 				break;
-			new_stage = idetape_kmalloc_stage (tape);
+			new_stage = idetape_kmalloc_stage(tape);
 		}
 	}
 	if (!idetape_pipeline_active(tape)) {
@@ -3979,11 +4236,11 @@
 			tape->insert_time = jiffies;
 			tape->insert_size = 0;
 			tape->insert_speed = 0;
-			idetape_insert_pipeline_into_queue (drive);
+			idetape_insert_pipeline_into_queue(drive);
 		} else if (tape->onstream) {
 			idetape_update_stats(drive);
 			if (tape->cur_frames < tape->max_frames - 5)
-				idetape_insert_pipeline_into_queue (drive);
+				idetape_insert_pipeline_into_queue(drive);
 		}
 	}
 	return 0;
@@ -4000,7 +4257,9 @@
 	 */
 	while (1) {
 		if (cnt++ > 1000) {   /* AJN: was 100 */
-			printk(KERN_INFO "ide-tape: %s: couldn't find logical block %d, aborting\n", tape->name, logical_blk_num);
+			printk(KERN_INFO "ide-tape: %s: couldn't find "
+				"logical block %d, aborting\n",
+				tape->name, logical_blk_num);
 			return 0;
 		}
 		idetape_initiate_read(drive, max_stages);
@@ -4012,21 +4271,31 @@
 #endif
 				clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 				position = idetape_read_position(drive);
-				printk(KERN_INFO "ide-tape: %s: blank block detected at %d\n", tape->name, position);
+				printk(KERN_INFO "ide-tape: %s: blank block "
+					"detected at %d\n", tape->name,
+					position);
 				if (position >= 3000 && position < 3080)
-					position += 32;  /* Why is this check and number ??? MM */
-				if (position >= OS_DATA_ENDFRAME1 && position < 3000)
+					/* Why is this check and number ??? MM */
+					position += 32;
+				if (position >= OS_DATA_ENDFRAME1 &&
+				    position < 3000)
 					position = 3000;
 				else
 					/*
-					 * compensate for write errors that generally skip 80 frames,
-					 * expect around 20 read errors in a row...
+					 * compensate for write errors that
+					 * generally skip 80 frames, expect
+					 * around 20 read errors in a row...
 					 */
 					position += 60;
-				if (position >= OS_DATA_ENDFRAME1 && position < 3000)
+				if (position >= OS_DATA_ENDFRAME1 &&
+				    position < 3000)
 					position = 3000;
 				printk(KERN_INFO "ide-tape: %s: positioning tape to block %d\n", tape->name, position);
-				if (position == 3000)  /* seems to be needed to correctly position at block 3000 MM */
+
+				/* seems to be needed to correctly position
+				 * at block 3000 MM
+				 */
+				if (position == 3000)
 					idetape_position_tape(drive, 0, 0, 0);
 				idetape_position_tape(drive, position, 0, 0);
 				cnt += 40;
@@ -4069,10 +4338,17 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_add_chrdev_read_request, %d blocks\n", blocks);
+		printk(KERN_INFO "ide-tape: Reached %s, %d blocks\n",
+			__FUNCTION__, blocks);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	/*
+	 * If we are at a filemark, return a read length of 0
+	 */
+	if (test_bit(IDETAPE_FILEMARK, &tape->flags))
+		return 0;
+
+	/*
 	 * Wait for the next logical block to be available at the head
 	 * of the pipeline
 	 */
@@ -4083,38 +4359,35 @@
 		}
 		if (test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
 		 	return 0;
-		return idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh);
+		return idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh);
 	}
 	rq_ptr = &tape->first_stage->rq;
 	bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors);
 	rq_ptr->nr_sectors = rq_ptr->current_nr_sectors = 0;
 
 
-	if (tape->onstream && !tape->raw && tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
+	if (tape->onstream && !tape->raw &&
+	    tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: %s: EOD reached\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: EOD reached\n",
+				tape->name);
 #endif
 		return 0;
 	}
 	if (rq_ptr->errors == IDETAPE_ERROR_EOD)
 		return 0;
-	if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK) {
-		idetape_switch_buffers (tape, tape->first_stage);
-		set_bit (IDETAPE_FILEMARK, &tape->flags);
-#if USE_IOTRACE
-		IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
-#endif
-		calculate_speeds(drive);
-	} else {
-		idetape_switch_buffers (tape, tape->first_stage);
+	else {
+		idetape_switch_buffers(tape, tape->first_stage);
 		if (rq_ptr->errors == IDETAPE_ERROR_GENERAL) {
 #if ONSTREAM_DEBUG
 			if (tape->debug_level >= 1)
-				printk(KERN_INFO "ide-tape: error detected, bytes_read %d\n", bytes_read);
+				printk(KERN_INFO "ide-tape: error detected, "
+					"bytes_read %d\n", bytes_read);
 #endif
 		}
-		clear_bit (IDETAPE_FILEMARK, &tape->flags);
+		if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
+			set_bit(IDETAPE_FILEMARK, &tape->flags);
 		spin_lock_irqsave(&tape->spinlock, flags);
 		idetape_remove_stage_head (drive);
 		spin_unlock_irqrestore(&tape->spinlock, flags);
@@ -4126,9 +4399,10 @@
 		calculate_speeds(drive);
 	}
 #if IDETAPE_DEBUG_BUGS
-	if (bytes_read > blocks*tape->tape_block_size) {
-		printk (KERN_ERR "ide-tape: bug: trying to return more bytes than requested\n");
-		bytes_read=blocks*tape->tape_block_size;
+	if (bytes_read > blocks * tape->tape_block_size) {
+		printk(KERN_ERR "ide-tape: bug: trying to return more "
+			"bytes than requested\n");
+		bytes_read = blocks * tape->tape_block_size;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 	return (bytes_read);
@@ -4142,16 +4416,16 @@
 	
 	while (bcount) {
 		bh = tape->merge_stage->bh;
-		count = IDE_MIN (tape->stage_size, bcount);
+		count = IDE_MIN(tape->stage_size, bcount);
 		bcount -= count;
 		blocks = count / tape->tape_block_size;
 		while (count) {
 			atomic_set(&bh->b_count, IDE_MIN (count, bh->b_size));
-			memset (bh->b_data, 0, atomic_read(&bh->b_count));
+			memset(bh->b_data, 0, atomic_read(&bh->b_count));
 			count -= atomic_read(&bh->b_count);
 			bh = bh->b_reqnext;
 		}
-		idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
+		idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
 	}
 }
 
@@ -4162,7 +4436,7 @@
 	struct request *rq;
 	int size = 0;
 
-	idetape_wait_for_pipeline (drive);
+	idetape_wait_for_pipeline(drive);
 	stage = tape->first_stage;
 	while (stage != NULL) {
 		rq = &stage->rq;
@@ -4187,16 +4461,16 @@
 	idetape_tape_t *tape = drive->driver_data;
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: Reached idetape_rewind_tape\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */	
 	
-	idetape_create_rewind_cmd (drive, &pc);
-	retval = idetape_queue_pc_tail (drive, &pc);
+	idetape_create_rewind_cmd(drive, &pc);
+	retval = idetape_queue_pc_tail(drive, &pc);
 	if (retval)
 		return retval;
 
-	idetape_create_read_position_cmd (&pc);
-	retval = idetape_queue_pc_tail (drive, &pc);
+	idetape_create_read_position_cmd(&pc);
+	retval = idetape_queue_pc_tail(drive, &pc);
 	if (retval)
 		return retval;
 	tape->logical_blk_num = 0;
@@ -4218,7 +4492,7 @@
 
 #if IDETAPE_DEBUG_LOG	
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_blkdev_ioctl\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 	switch (cmd) {
 		case 0x0340:
@@ -4248,7 +4522,7 @@
 {
 	MOD_INC_USE_COUNT;
 #if ONSTREAM_DEBUG
-        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_blkdev_open\n");
+        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in %s\n", __FUNCTION__);
 #endif
 	return 0;
 }
@@ -4257,7 +4531,7 @@
 {
 	MOD_DEC_USE_COUNT;
 #if ONSTREAM_DEBUG
-        printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_blkdev_release\n");
+        printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in %s\n", __FUNCTION__);
 #endif
 }
 
@@ -4268,7 +4542,7 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 	if (tape != NULL)
-		set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
+		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
 }
 
 /*
@@ -4291,7 +4565,8 @@
 	unsigned long flags;
 
 	if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_bwd\n", tape->name);
+		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk "
+			"num in space_filemarks_bwd\n", tape->name);
 		return -EIO;
 	}
 	while (cnt != mt_count) {
@@ -4300,16 +4575,20 @@
 			return -EIO;
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: positioning to last mark at %d\n", last_mark_addr);
+			printk(KERN_INFO "ide-tape: positioning to last "
+			"mark at %d\n", last_mark_addr);
 #endif
 		idetape_position_tape(drive, last_mark_addr, 0, 0);
 		cnt++;
 		if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-			printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: couldn't get logical "
+				"blk num in space_filemarks\n", tape->name);
 			return -EIO;
 		}
 		if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-			printk(KERN_INFO "ide-tape: %s: expected to find marker at block %d, not found\n", tape->name, last_mark_addr);
+			printk(KERN_INFO "ide-tape: %s: expected to find "
+				"marker at block %d, not found\n",
+				tape->name, last_mark_addr);
 			return -EIO;
 		}
 	}
@@ -4334,12 +4613,14 @@
 	unsigned long flags;
 
 	if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwd\n", tape->name);
+		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk "
+			"num in space_filemarks_fwd\n", tape->name);
 		return -EIO;
 	}
 	while (1) {
 		if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-			printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: couldn't get logical "
+				"blk num in space_filemarks\n", tape->name);
 			return -EIO;
 		}
 		if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_MARKER)
@@ -4347,19 +4628,20 @@
 		if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
 #if ONSTREAM_DEBUG
 			if (tape->debug_level >= 2)
-				printk(KERN_INFO "ide-tape: %s: space_fwd: EOD reached\n", tape->name);
+				printk(KERN_INFO "ide-tape: %s: space_fwd: "
+					"EOD reached\n", tape->name);
 #endif
 			return -EIO;
 		}
 		if (cnt == mt_count)
 			break;
 		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 		spin_unlock_irqrestore(&tape->spinlock, flags);
 	}
 	if (mt_op == MTFSF) {
 		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 		tape->logical_blk_num++;
 		spin_unlock_irqrestore(&tape->spinlock, flags);
 	}
@@ -4377,7 +4659,8 @@
 	unsigned long flags;
 
 	if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwd\n", tape->name);
+		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk "
+			"num in space_filemarks_fwd\n", tape->name);
 		return -EIO;
 	}
 
@@ -4390,22 +4673,27 @@
 		if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
 #if ONSTREAM_DEBUG
 			if (tape->debug_level >= 2)
-				printk(KERN_INFO "ide-tape: %s: space_fwd: EOD reached\n", tape->name);
+				printk(KERN_INFO "ide-tape: %s: space_fwd: "
+					"EOD reached\n", tape->name);
 #endif
 			return -EIO;
 		}
 		if (ntohl(tape->first_stage->aux->filemark_cnt) == 0) {
 			if (tape->first_mark_addr == -1) {
-				printk(KERN_INFO "ide-tape: %s: reverting to slow filemark space\n", tape->name);
+				printk(KERN_INFO "ide-tape: %s: reverting to "
+					"slow filemark space\n", tape->name);
 				return idetape_onstream_space_over_filemarks_forward_slow(drive, mt_op, mt_count);
 			}
 			idetape_position_tape(drive, tape->first_mark_addr, 0, 0);
 			if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-				printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwd_fast\n", tape->name);
+				printk(KERN_INFO "ide-tape: %s: couldn't get "
+					"logical blk num in %s\n",							__FUNCTION__, tape->name);
 				return -EIO;
 			}
 			if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-				printk(KERN_INFO "ide-tape: %s: expected to find filemark at %d\n", tape->name, tape->first_mark_addr);
+				printk(KERN_INFO "ide-tape: %s: expected to "
+					"find filemark at %d\n",
+					tape->name, tape->first_mark_addr);
 				return -EIO;
 			}
 		} else {
@@ -4418,7 +4706,8 @@
 	while (cnt != mt_count) {
 		next_mark_addr = ntohl(tape->first_stage->aux->next_mark_addr);
 		if (!next_mark_addr || next_mark_addr > tape->eod_frame_addr) {
-			printk(KERN_INFO "ide-tape: %s: reverting to slow filemark space\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: reverting to slow "
+				"filemark space\n", tape->name);
 			return idetape_onstream_space_over_filemarks_forward_slow(drive, mt_op, mt_count - cnt);
 #if ONSTREAM_DEBUG
 		} else if (tape->debug_level >= 2) {
@@ -4428,17 +4717,20 @@
 		idetape_position_tape(drive, next_mark_addr, 0, 0);
 		cnt++;
 		if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-			printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: couldn't get logical "
+				"blk num in space_filemarks\n", tape->name);
 			return -EIO;
 		}
 		if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-			printk(KERN_INFO "ide-tape: %s: expected to find marker at block %d, not found\n", tape->name, next_mark_addr);
+			printk(KERN_INFO "ide-tape: %s: expected to find "
+				"marker at block %d, not found\n",
+				tape->name, next_mark_addr);
 			return -EIO;
 		}
 	}
 	if (mt_op == MTFSF) {
 		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 		tape->logical_blk_num++;
 		spin_unlock_irqrestore(&tape->spinlock, flags);
 	}
@@ -4478,6 +4770,14 @@
 		tape->restart_speed_control_req = 1;
 		return retval;
 	}
+ 
+	if (mt_count == 0)
+		return 0;
+	if (MTBSF == mt_op || MTBSFM == mt_op) {
+		if (!tape->capabilities.sprev)
+			return -EIO;
+		mt_count = - mt_count;
+	}
 
 	if (tape->chrdev_direction == idetape_direction_read) {
 		/*
@@ -4485,28 +4785,36 @@
 		 *	filemarks.
 		 */
 		tape->merge_stage_size = 0;
-		clear_bit (IDETAPE_FILEMARK, &tape->flags);
+		if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags))
+			++count;
 		while (tape->first_stage != NULL) {
-			idetape_wait_first_stage(drive);
-			if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
-				count++;
 			if (count == mt_count) {
-				switch (mt_op) {
-					case MTFSF:
-						spin_lock_irqsave(&tape->spinlock, flags);
-						idetape_remove_stage_head (drive);
-						spin_unlock_irqrestore(&tape->spinlock, flags);
-					case MTFSFM:
-						return (0);
-					default:
-						break;
-				}
+				if (mt_op == MTFSFM)
+					set_bit(IDETAPE_FILEMARK, &tape->flags);
+				return 0;
 			}
 			spin_lock_irqsave(&tape->spinlock, flags);
-			idetape_remove_stage_head (drive);
-			spin_unlock_irqrestore(&tape->spinlock, flags);
+			if (tape->first_stage == tape->active_stage) {
+				/*
+				 *	We have reached the active stage in the read pipeline.
+				 *	There is no point in allowing the drive to continue
+				 *	reading any farther, so we stop the pipeline.
+				 *
+				 *	This section should be moved to a separate subroutine,
+				 *	because a similar function is performed in
+				 *	__idetape_discard_read_pipeline(), for example.
+				 */
+				tape->next_stage = NULL;
+				spin_unlock_irqrestore(&tape->spinlock, flags);
+				idetape_wait_first_stage(drive);
+				tape->next_stage = tape->first_stage->next;
+			} else
+				spin_unlock_irqrestore(&tape->spinlock, flags);
+			if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
+				++count;
+			idetape_remove_stage_head(drive);
 		}
-		idetape_discard_read_pipeline (drive, 1);
+		idetape_discard_read_pipeline(drive, 0);
 	}
 
 	/*
@@ -4515,27 +4823,20 @@
 	 */
 	switch (mt_op) {
 		case MTFSF:
-			idetape_create_space_cmd (&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
-			return (idetape_queue_pc_tail (drive, &pc));
-		case MTFSFM:
-			if (!tape->capabilities.sprev)
-				return (-EIO);
-			retval = idetape_space_over_filemarks (drive, MTFSF, mt_count-count);
-			if (retval) return (retval);
-			return (idetape_space_over_filemarks (drive, MTBSF, 1));
 		case MTBSF:
-			if (!tape->capabilities.sprev)
-				return (-EIO);
-			idetape_create_space_cmd (&pc,-(mt_count+count),IDETAPE_SPACE_OVER_FILEMARK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_create_space_cmd(&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
+			return (idetape_queue_pc_tail(drive, &pc));
+		case MTFSFM:
 		case MTBSFM:
 			if (!tape->capabilities.sprev)
 				return (-EIO);
-			retval = idetape_space_over_filemarks (drive, MTBSF, mt_count+count);
+			retval = idetape_space_over_filemarks(drive, MTFSF, mt_count-count);
 			if (retval) return (retval);
-			return (idetape_space_over_filemarks (drive, MTFSF, 1));
+			count = (MTBSFM == mt_op ? 1 : -1);
+			return (idetape_space_over_filemarks(drive, MTFSF, count));
 		default:
-			printk (KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
+			printk(KERN_ERR "ide-tape: MTIO operation %d not "
+				"supported\n", mt_op);
 			return (-EIO);
 	}
 }
@@ -4562,7 +4863,7 @@
 				    size_t count, loff_t *ppos)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
 	ssize_t bytes_read,temp, actually_read = 0, rc;
 
@@ -4571,17 +4872,21 @@
 		return -ENXIO;
 	}
 	if (tape->onstream && (count != tape->tape_block_size)) {
-		printk(KERN_ERR "ide-tape: %s: use %d bytes as block size (%Zd used)\n", tape->name, tape->tape_block_size, count);
+		printk(KERN_ERR "ide-tape: %s: use %d bytes as block size "
+			"(%Zd used)\n", tape->name,
+			tape->tape_block_size, count);
 		return -EINVAL;
 	}
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_chrdev_read, count %Zd\n", count);
+		printk (KERN_INFO "ide-tape: Reached %s, count %Zd\n",
+			__FUNCTION__, count);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	if (tape->chrdev_direction != idetape_direction_read) {
-		if (test_bit (IDETAPE_DETECT_BS, &tape->flags))
-			if (count > tape->tape_block_size && (count % tape->tape_block_size) == 0)
+		if (test_bit(IDETAPE_DETECT_BS, &tape->flags))
+			if (count > tape->tape_block_size &&
+			    (count % tape->tape_block_size) == 0)
 				tape->user_bs_factor = count / tape->tape_block_size;
 	}
 	if ((rc = idetape_initiate_read(drive, tape->max_stages)) < 0)
@@ -4589,42 +4894,45 @@
 	if (count == 0)
 		return (0);
 	if (tape->merge_stage_size) {
-		actually_read = IDE_MIN (tape->merge_stage_size, count);
-		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, actually_read);
+		actually_read = IDE_MIN(tape->merge_stage_size, count);
+		idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read);
 		buf += actually_read;
 		tape->merge_stage_size -= actually_read;
 		count -= actually_read;
 	}
 	while (count >= tape->stage_size) {
-		bytes_read = idetape_add_chrdev_read_request (drive, tape->capabilities.ctl);
+		bytes_read = idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
 		if (bytes_read <= 0)
 			goto finish;
-		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, bytes_read);
+		idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read);
 		buf += bytes_read;
 		count -= bytes_read;
 		actually_read += bytes_read;
 	}
 	if (count) {
-		bytes_read=idetape_add_chrdev_read_request (drive, tape->capabilities.ctl);
+		bytes_read=idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
 		if (bytes_read <= 0)
 			goto finish;
-		temp = IDE_MIN (count, bytes_read);
-		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, temp);
+		temp = IDE_MIN(count, bytes_read);
+		idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp);
 		actually_read += temp;
 		tape->merge_stage_size = bytes_read-temp;
 	}
 finish:
-	if (!actually_read && test_bit (IDETAPE_FILEMARK, &tape->flags)) {
+	if (!actually_read && test_bit(IDETAPE_FILEMARK, &tape->flags)) {
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: %s: spacing over filemark\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: spacing over "
+				"filemark\n", tape->name);
 #endif
 		idetape_space_over_filemarks (drive, MTFSF, 1);
 		return 0;
 	}
-	if (tape->onstream && !actually_read && test_and_clear_bit(IDETAPE_READ_ERROR, &tape->flags)) {
-		printk(KERN_ERR "ide-tape: %s: unrecovered read error on logical block number %d, skipping\n",
-					tape->name, tape->logical_blk_num);
+	if (tape->onstream && !actually_read &&
+	    test_and_clear_bit(IDETAPE_READ_ERROR, &tape->flags)) {
+		printk(KERN_ERR "ide-tape: %s: unrecovered read error on "
+			"logical block number %d, skipping\n",
+			tape->name, tape->logical_blk_num);
 		tape->logical_blk_num++;
 		return -EIO;
 	}
@@ -4649,21 +4957,25 @@
 	position = idetape_read_position(drive);
 #if ONSTREAM_DEBUG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: current position (2) %d, lblk %d\n", position, tape->logical_blk_num);
+		printk(KERN_INFO "ide-tape: current position (2) %d, "
+			"lblk %d\n", position, tape->logical_blk_num);
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: current position (2) tape block %d\n", tape->last_frame_position);
+		printk(KERN_INFO "ide-tape: current position (2) tape "
+			"block %d\n", tape->last_frame_position);
 #endif
 	idetape_position_tape(drive, last_mark_addr, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't read last marker\n", tape->name);
-		__idetape_kfree_stage (stage);
+	if (!idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, 1, stage->bh)) {
+		printk(KERN_INFO "ide-tape: %s: couldn't read last marker\n",
+			tape->name);
+		__idetape_kfree_stage(stage);
 		idetape_position_tape(drive, position, 0, 0);
 		return;
 	}
 	aux = stage->aux;
 	if (aux->frame_type != OS_FRAME_TYPE_MARKER) {
-		printk(KERN_INFO "ide-tape: %s: expected to find marker at addr %d\n", tape->name, last_mark_addr);
-		__idetape_kfree_stage (stage);
+		printk(KERN_INFO "ide-tape: %s: expected to find marker "
+			"at addr %d\n", tape->name, last_mark_addr);
+		__idetape_kfree_stage(stage);
 		idetape_position_tape(drive, position, 0, 0);
 		return;
 	}
@@ -4673,13 +4985,14 @@
 #endif
 	aux->next_mark_addr = htonl(next_mark_addr);
 	idetape_position_tape(drive, last_mark_addr, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't write back marker frame at %d\n", tape->name, last_mark_addr);
-		__idetape_kfree_stage (stage);
+	if (!idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+		printk(KERN_INFO "ide-tape: %s: couldn't write back marker "
+			"frame at %d\n", tape->name, last_mark_addr);
+		__idetape_kfree_stage(stage);
 		idetape_position_tape(drive, position, 0, 0);
 		return;
 	}
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 	idetape_flush_tape_buffers (drive);
 	idetape_position_tape(drive, position, 0, 0);
 	return;
@@ -4702,18 +5015,20 @@
 #if ONSTREAM_DEBUG
 	printk(KERN_INFO "write_filler: positioning failed it returned %d\n", rc);
 #endif
-	if (rc != 0) 
-		return;	/* don't write fillers if we cannot position the tape. */
+	if (rc != 0)
+		/* don't write fillers if we cannot position the tape. */
+		return;
 
 	strcpy(stage->bh->b_data, "Filler");
 	while (cnt--) {
-		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
-			printk(KERN_INFO "ide-tape: %s: write_filler: couldn't write header frame\n", tape->name);
-			__idetape_kfree_stage (stage);
+		if (!idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+			printk(KERN_INFO "ide-tape: %s: write_filler: "
+				"couldn't write header frame\n", tape->name);
+			__idetape_kfree_stage(stage);
 			return;
 		}
 	}
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 }
 
 static void __idetape_write_header (ide_drive_t *drive, int block, int cnt)
@@ -4741,14 +5056,14 @@
 	header.partition.eod_frame_addr = htonl(tape->eod_frame_addr);
 	memcpy(stage->bh->b_data, &header, sizeof(header));
 	while (cnt--) {
-		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+		if (!idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
 			printk(KERN_INFO "ide-tape: %s: couldn't write header frame\n", tape->name);
-			__idetape_kfree_stage (stage);
+			__idetape_kfree_stage(stage);
 			return;
 		}
 	}
-	__idetape_kfree_stage (stage);
-	idetape_flush_tape_buffers (drive);
+	__idetape_kfree_stage(stage);
+	idetape_flush_tape_buffers(drive);
 }
 
 static void idetape_write_header (ide_drive_t *drive, int locate_eod)
@@ -4767,7 +5082,9 @@
 	if (locate_eod) {
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: %s: locating back to eod frame addr %d\n", tape->name, tape->eod_frame_addr);
+			printk(KERN_INFO "ide-tape: %s: locating back to "
+				"eod frame addr %d\n", tape->name,
+				tape->eod_frame_addr);
 #endif
 		idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
 	}
@@ -4777,7 +5094,7 @@
 				     size_t count, loff_t *ppos)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
 	ssize_t retval, actually_written = 0;
 	int position;
@@ -4794,13 +5111,14 @@
 
 	if (tape->onstream) {
 		if (count != tape->tape_block_size) {
-			printk(KERN_ERR "ide-tape: %s: chrdev_write: use %d bytes as block size (%Zd used)\n",
-					tape->name, tape->tape_block_size, count);
+			printk(KERN_ERR "ide-tape: %s: chrdev_write: "
+				"use %d bytes as block size (%Zd used)\n",
+				tape->name, tape->tape_block_size, count);
 			return -EINVAL;
 		}
 		/*
-		 * Check if we reach the end of the tape. Just assume the whole pipeline
-		 * is filled with write requests!
+		 * Check if we reach the end of the tape. Just assume the whole
+		 * pipeline is filled with write requests!
 		 */
 		if (tape->first_frame_position + tape->nr_stages >= tape->capacity - OS_EW)  {
 #if ONSTREAM_DEBUG
@@ -4812,19 +5130,20 @@
 		}
 	}
 
-	if (tape->chrdev_direction != idetape_direction_write) {	/* Initialize write operation */
+	/* Initialize write operation */
+	if (tape->chrdev_direction != idetape_direction_write) {
 		if (tape->chrdev_direction == idetape_direction_read)
-			idetape_discard_read_pipeline (drive, 1);
+			idetape_discard_read_pipeline(drive, 1);
 #if IDETAPE_DEBUG_BUGS
 		if (tape->merge_stage || tape->merge_stage_size) {
-			printk (KERN_ERR "ide-tape: merge_stage_size should be 0 now\n");
+			printk(KERN_ERR "ide-tape: merge_stage_size should be 0 now\n");
 			tape->merge_stage_size = 0;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		if ((tape->merge_stage = __idetape_kmalloc_stage (tape, 0, 0)) == NULL)
+		if ((tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0)) == NULL)
 			return -ENOMEM;
 		tape->chrdev_direction = idetape_direction_write;
-		idetape_init_merge_stage (tape);
+		idetape_init_merge_stage(tape);
 
 		if (tape->onstream) {
 			position = idetape_read_position(drive);
@@ -4860,9 +5179,9 @@
 		 *	is switched from completion mode to buffer available
 		 *	mode.
 		 */
-		retval = idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bh);
+		retval = idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bh);
 		if (retval < 0) {
-			kfree (tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 			tape->chrdev_direction = idetape_direction_none;
 			return retval;
@@ -4879,35 +5198,35 @@
 	if (tape->merge_stage_size) {
 #if IDETAPE_DEBUG_BUGS
 		if (tape->merge_stage_size >= tape->stage_size) {
-			printk (KERN_ERR "ide-tape: bug: merge buffer too big\n");
+			printk(KERN_ERR "ide-tape: bug: merge buffer too big\n");
 			tape->merge_stage_size = 0;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		actually_written = IDE_MIN (tape->stage_size - tape->merge_stage_size, count);
-		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, actually_written);
+		actually_written = IDE_MIN(tape->stage_size - tape->merge_stage_size, count);
+		idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written);
 		buf += actually_written;
 		tape->merge_stage_size += actually_written;
 		count -= actually_written;
 
 		if (tape->merge_stage_size == tape->stage_size) {
 			tape->merge_stage_size = 0;
-			retval = idetape_add_chrdev_write_request (drive, tape->capabilities.ctl);
+			retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
 			if (retval <= 0)
 				return (retval);
 		}
 	}
 	while (count >= tape->stage_size) {
-		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, tape->stage_size);
+		idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size);
 		buf += tape->stage_size;
 		count -= tape->stage_size;
-		retval = idetape_add_chrdev_write_request (drive, tape->capabilities.ctl);
+		retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
 		actually_written += tape->stage_size;
 		if (retval <= 0)
 			return (retval);
 	}
 	if (count) {
-		actually_written+=count;
-		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, count);
+		actually_written += count;
+		idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count);
 		tape->merge_stage_size += count;
 	}
 	return (actually_written);
@@ -4920,19 +5239,20 @@
 	idetape_pc_t pc;
 
 	if (!tape->onstream) {
-		idetape_create_write_filemark_cmd(drive, &pc, 1);	/* Write a filemark */
-		if (idetape_queue_pc_tail (drive, &pc)) {
-			printk (KERN_ERR "ide-tape: Couldn't write a filemark\n");
+		/* Write a filemark */
+		idetape_create_write_filemark_cmd(drive, &pc, 1);
+		if (idetape_queue_pc_tail(drive, &pc)) {
+			printk(KERN_ERR "ide-tape: Couldn't write a filemark\n");
 			return -EIO;
 		}
 	} else if (!tape->raw) {
 		last_mark_addr = idetape_read_position(drive);
-		tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
+		tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
 		if (tape->merge_stage != NULL) {
 			idetape_init_stage(drive, tape->merge_stage, OS_FRAME_TYPE_MARKER, tape->logical_blk_num);
-			idetape_pad_zeros (drive, tape->stage_size);
+			idetape_pad_zeros(drive, tape->stage_size);
 			tape->logical_blk_num++;
-			__idetape_kfree_stage (tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 		}
 		if (tape->filemark_cnt)
@@ -4950,11 +5270,11 @@
 
 	if (!tape->onstream || tape->raw)
 		return;
-	tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
+	tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
 	if (tape->merge_stage != NULL) {
 		tape->eod_frame_addr = idetape_read_position(drive);
 		idetape_init_stage(drive, tape->merge_stage, OS_FRAME_TYPE_EOD, tape->logical_blk_num);
-		idetape_pad_zeros (drive, tape->stage_size);
+		idetape_pad_zeros(drive, tape->stage_size);
 		__idetape_kfree_stage (tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
@@ -4989,7 +5309,9 @@
 error:
 	tape->speed_control = speed_control;
 	tape->restart_speed_control_req = 1;
-	printk(KERN_INFO "ide-tape: %s: couldn't seek to logical block %d (at %d), %d retries\n", tape->name, logical_blk_num, tape->logical_blk_num, retries);
+	printk(KERN_INFO "ide-tape: %s: couldn't seek to logical block %d "
+		"(at %d), %d retries\n", tape->name, logical_blk_num,
+		tape->logical_blk_num, retries);
 	return -EIO;
 ok:
 	tape->speed_control = speed_control;
@@ -5068,7 +5390,8 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 1)
-		printk (KERN_INFO "ide-tape: Handling MTIOCTOP ioctl: mt_op=%d, mt_count=%d\n",mt_op,mt_count);
+		printk(KERN_INFO "ide-tape: Handling MTIOCTOP "
+			"ioctl: mt_op=%d, mt_count=%d\n", mt_op, mt_count);
 #endif /* IDETAPE_DEBUG_LOG */
 	/*
 	 *	Commands which need our pipelined read-ahead stages.
@@ -5080,41 +5403,41 @@
 		case MTBSFM:
 			if (!mt_count)
 				return (0);
-			return (idetape_space_over_filemarks (drive,mt_op,mt_count));
+			return (idetape_space_over_filemarks(drive,mt_op,mt_count));
 		default:
 			break;
 	}
 	switch (mt_op) {
 		case MTWEOF:
-			idetape_discard_read_pipeline (drive, 1);
+			idetape_discard_read_pipeline(drive, 1);
 			for (i = 0; i < mt_count; i++) {
 				retval = idetape_write_filemark(drive);
 				if (retval) return retval;
 			}
 			return (0);
 		case MTREW:
-			idetape_discard_read_pipeline (drive, 0);
+			idetape_discard_read_pipeline(drive, 0);
 			if (idetape_rewind_tape(drive))
 				return -EIO;
 			if (tape->onstream && !tape->raw)
 				return idetape_position_tape(drive, OS_DATA_STARTFRAME1, 0, 0);
 			return 0;
 		case MTLOAD:
-			idetape_discard_read_pipeline (drive, 0);
-			idetape_create_load_unload_cmd (drive, &pc, IDETAPE_LU_LOAD_MASK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_discard_read_pipeline(drive, 0);
+			idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTUNLOAD:
 		case MTOFFL:
-			idetape_discard_read_pipeline (drive, 0);
-			idetape_create_load_unload_cmd (drive, &pc,!IDETAPE_LU_LOAD_MASK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_discard_read_pipeline(drive, 0);
+			idetape_create_load_unload_cmd(drive, &pc,!IDETAPE_LU_LOAD_MASK);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTNOP:
-			idetape_discard_read_pipeline (drive, 0);
-			return (idetape_flush_tape_buffers (drive));
+			idetape_discard_read_pipeline(drive, 0);
+			return (idetape_flush_tape_buffers(drive));
 		case MTRETEN:
-			idetape_discard_read_pipeline (drive, 0);
-			idetape_create_load_unload_cmd (drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_discard_read_pipeline(drive, 0);
+			idetape_create_load_unload_cmd(drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTEOM:
 			if (tape->onstream) {
 #if ONSTREAM_DEBUG
@@ -5128,8 +5451,8 @@
 					return -EIO;
 				return 0;
 			}
-			idetape_create_space_cmd (&pc, 0, IDETAPE_SPACE_TO_EOD);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTERASE:
 			if (tape->onstream) {
 				tape->eod_frame_addr = OS_DATA_STARTFRAME1;
@@ -5137,7 +5460,7 @@
 				tape->first_mark_addr = tape->last_mark_addr = -1;
 				idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
 				idetape_write_eod(drive);
-				idetape_flush_tape_buffers (drive);
+				idetape_flush_tape_buffers(drive);
 				idetape_write_header(drive, 0);
 				/*
 				 * write filler frames to the unused frames...
@@ -5145,13 +5468,13 @@
 				 */
 				idetape_write_filler(drive, OS_DATA_STARTFRAME1 - 10, 10);
 				idetape_write_filler(drive, OS_DATA_ENDFRAME1, 10);
-				idetape_flush_tape_buffers (drive);
-				(void) idetape_rewind_tape (drive);
+				idetape_flush_tape_buffers(drive);
+				(void) idetape_rewind_tape(drive);
 				return 0;
 			}
-			(void) idetape_rewind_tape (drive);
-			idetape_create_erase_cmd (&pc);
-			return (idetape_queue_pc_tail (drive, &pc));
+			(void) idetape_rewind_tape(drive);
+			idetape_create_erase_cmd(&pc);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTSETBLK:
 			if (tape->onstream) {
 				if (mt_count != tape->tape_block_size) {
@@ -5164,21 +5487,21 @@
 				if (mt_count < tape->tape_block_size || mt_count % tape->tape_block_size)
 					return -EIO;
 				tape->user_bs_factor = mt_count / tape->tape_block_size;
-				clear_bit (IDETAPE_DETECT_BS, &tape->flags);
+				clear_bit(IDETAPE_DETECT_BS, &tape->flags);
 			} else
-				set_bit (IDETAPE_DETECT_BS, &tape->flags);
+				set_bit(IDETAPE_DETECT_BS, &tape->flags);
 			return 0;
 		case MTSEEK:
 			if (!tape->onstream || tape->raw) {
-				idetape_discard_read_pipeline (drive, 0);
-				return idetape_position_tape (drive, mt_count * tape->user_bs_factor, tape->partition, 0);
+				idetape_discard_read_pipeline(drive, 0);
+				return idetape_position_tape(drive, mt_count * tape->user_bs_factor, tape->partition, 0);
 			}
 			return idetape_seek_logical_blk(drive, mt_count);
 		case MTSETPART:
-			idetape_discard_read_pipeline (drive, 0);
+			idetape_discard_read_pipeline(drive, 0);
 			if (tape->onstream)
 				return -EIO;
-			return (idetape_position_tape (drive, 0, mt_count, 0));
+			return (idetape_position_tape(drive, 0, mt_count, 0));
 		case MTFSR:
 		case MTBSR:
 			if (tape->onstream) {
@@ -5187,26 +5510,26 @@
 				if (mt_op == MTFSR)
 					return idetape_seek_logical_blk(drive, tape->logical_blk_num + mt_count);
 				else {
-					idetape_discard_read_pipeline (drive, 0);
+					idetape_discard_read_pipeline(drive, 0);
 					return idetape_seek_logical_blk(drive, tape->logical_blk_num - mt_count);
 				}
 			}
 		case MTLOCK:
 			if (!idetape_create_prevent_cmd(drive, &pc, 1))
 				return 0;
-			retval = idetape_queue_pc_tail (drive, &pc);
+			retval = idetape_queue_pc_tail(drive, &pc);
 			if (retval) return retval;
 			tape->door_locked = DOOR_EXPLICITLY_LOCKED;
 			return 0;
 		case MTUNLOCK:
 			if (!idetape_create_prevent_cmd(drive, &pc, 0))
 				return 0;
-			retval = idetape_queue_pc_tail (drive, &pc);
+			retval = idetape_queue_pc_tail(drive, &pc);
 			if (retval) return retval;
 			tape->door_locked = DOOR_UNLOCKED;
 			return 0;
 		default:
-			printk (KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
+			printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
 			return (-EIO);
 	}
 }
@@ -5236,7 +5559,7 @@
  */
 static int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
-	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
 	struct mtop mtop;
 	struct mtget mtget;
@@ -5245,30 +5568,30 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_chrdev_ioctl, cmd=%u\n",cmd);
+		printk(KERN_INFO "ide-tape: Reached idetape_chrdev_ioctl, cmd=%u\n",cmd);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	tape->restart_speed_control_req = 1;
 	if (tape->chrdev_direction == idetape_direction_write) {
-		idetape_empty_write_pipeline (drive);
-		idetape_flush_tape_buffers (drive);
+		idetape_empty_write_pipeline(drive);
+		idetape_flush_tape_buffers(drive);
 	}
 	if (cmd == MTIOCGET || cmd == MTIOCPOS) {
-		block_offset = idetape_pipeline_size (drive) / (tape->tape_block_size * tape->user_bs_factor);
+		block_offset = idetape_pipeline_size(drive) / (tape->tape_block_size * tape->user_bs_factor);
 		if ((position = idetape_read_position(drive)) < 0)
 			return -EIO;
 	}
 	switch (cmd) {
 		case MTIOCTOP:
-			if (copy_from_user ((char *) &mtop, (char *) arg, sizeof (struct mtop)))
+			if (copy_from_user((char *) &mtop, (char *) arg, sizeof (struct mtop)))
 				return -EFAULT;
-			return (idetape_mtioctop (drive,mtop.mt_op,mtop.mt_count));
+			return (idetape_mtioctop(drive,mtop.mt_op,mtop.mt_count));
 		case MTIOCGET:
-			memset (&mtget, 0, sizeof (struct mtget));
+			memset(&mtget, 0, sizeof (struct mtget));
 			mtget.mt_type = MT_ISSCSI2;
-			if (!tape->onstream || tape->raw)
+			if (!tape->onstream || tape->raw) {
 				mtget.mt_blkno = position / tape->user_bs_factor - block_offset;
-			else {
+			} else {
 				if (!idetape_get_logical_blk(drive, -1, 10, 0))
 					mtget.mt_blkno = -1;
 				else
@@ -5297,8 +5620,8 @@
 			return 0;
 		default:
 			if (tape->chrdev_direction == idetape_direction_read)
-				idetape_discard_read_pipeline (drive, 1);
-			return (idetape_blkdev_ioctl (drive,inode,file,cmd,arg));
+				idetape_discard_read_pipeline(drive, 1);
+			return (idetape_blkdev_ioctl(drive,inode,file,cmd,arg));
 	}
 }
 
@@ -5318,7 +5641,7 @@
 	tape->wrt_pass_cntr = 0;
 	tape->eod_frame_addr = OS_DATA_STARTFRAME1;
 	tape->first_mark_addr = tape->last_mark_addr = -1;
-	stage = __idetape_kmalloc_stage (tape, 0, 0);
+	stage = __idetape_kmalloc_stage(tape, 0, 0);
 	if (stage == NULL)
 		return 0;
 #if ONSTREAM_DEBUG
@@ -5326,16 +5649,17 @@
 		printk(KERN_INFO "ide-tape: %s: reading header\n", tape->name);
 #endif
 	idetape_position_tape(drive, block, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't read header frame\n", tape->name);
-		__idetape_kfree_stage (stage);
+	if (!idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, 1, stage->bh)) {
+		printk(KERN_INFO "ide-tape: %s: couldn't read header frame\n",
+			tape->name);
+		__idetape_kfree_stage(stage);
 		return 0;
 	}
 	header = (os_header_t *) stage->bh->b_data;
 	aux = stage->aux;
 	if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0) {
 		printk(KERN_INFO "ide-tape: %s: invalid header identification string\n", tape->name);
-		__idetape_kfree_stage (stage);
+		__idetape_kfree_stage(stage);
 		return 0;
 	}
 	if (header->major_rev != 1 || (header->minor_rev > OS_ADR_MINREV))
@@ -5354,17 +5678,21 @@
 		tape->linux_media = 1;
 		tape->linux_media_version = tape->application_sig[3] - '0';
 		if (tape->linux_media_version != 3)
-			printk(KERN_INFO "ide-tape: %s: Linux media version %d detected (current 3)\n",
-					 tape->name, tape->linux_media_version);
+			printk(KERN_INFO "ide-tape: %s: Linux media version "
+				"%d detected (current 3)\n",
+				 tape->name, tape->linux_media_version);
 	} else {
-		printk(KERN_INFO "ide-tape: %s: non Linux media detected (%s)\n", tape->name, tape->application_sig);
+		printk(KERN_INFO "ide-tape: %s: non Linux media detected "
+			"(%s)\n", tape->name, tape->application_sig);
 		tape->linux_media = 0;
 	}
 #if ONSTREAM_DEBUG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: %s: detected write pass counter %d, eod frame addr %d\n", tape->name, tape->wrt_pass_cntr, tape->eod_frame_addr);
+		printk(KERN_INFO "ide-tape: %s: detected write pass "
+			"counter %d, eod frame addr %d\n", tape->name,
+			tape->wrt_pass_cntr, tape->eod_frame_addr);
 #endif
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 	return 1;
 }
 
@@ -5385,7 +5713,8 @@
 	for (block = 0xbae; block < 0xbb3; block++) /* 2990 - 2994 */
 		if (__idetape_analyze_headers(drive, block))
 			goto ok;
-	printk(KERN_ERR "ide-tape: %s: failed to find valid ADRL header\n", tape->name);
+	printk(KERN_ERR "ide-tape: %s: failed to find valid ADRL header\n",
+		tape->name);
 	return 0;
 ok:
 	if (position < OS_DATA_STARTFRAME1)
@@ -5403,23 +5732,23 @@
 	ide_drive_t *drive;
 	idetape_tape_t *tape;
 	idetape_pc_t pc;
-	unsigned int minor=MINOR (inode->i_rdev);
+	unsigned int minor = MINOR(inode->i_rdev);
 			
 #if IDETAPE_DEBUG_LOG
 	printk (KERN_INFO "ide-tape: Reached idetape_chrdev_open\n");
 #endif /* IDETAPE_DEBUG_LOG */
 	
-	if ((drive = get_drive_ptr (inode->i_rdev)) == NULL)
+	if ((drive = get_drive_ptr(inode->i_rdev)) == NULL)
 		return -ENXIO;
 	tape = drive->driver_data;
 
-	if (test_and_set_bit (IDETAPE_BUSY, &tape->flags))
+	if (test_and_set_bit(IDETAPE_BUSY, &tape->flags))
 		return -EBUSY;
 	MOD_INC_USE_COUNT;
 	if (!tape->onstream) {	
 		idetape_read_position(drive);
-		if (!test_bit (IDETAPE_ADDRESS_VALID, &tape->flags))
-			(void) idetape_rewind_tape (drive);
+		if (!test_bit(IDETAPE_ADDRESS_VALID, &tape->flags))
+			(void) idetape_rewind_tape(drive);
 	} else {
 		if (minor & 64) {
 			tape->tape_block_size = tape->stage_size = 32768 + 512;
@@ -5436,14 +5765,16 @@
 		MOD_DEC_USE_COUNT;
 		return -EBUSY;
 	}
-	idetape_read_position(drive);
+	if (tape->onstream)
+		idetape_read_position(drive);
 	MOD_DEC_USE_COUNT;
-	clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+	if (tape->chrdev_direction != idetape_direction_read)
+		clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 
 	if (tape->chrdev_direction == idetape_direction_none) {
 		MOD_INC_USE_COUNT;
 		if (idetape_create_prevent_cmd(drive, &pc, 1)) {
-			if (!idetape_queue_pc_tail (drive, &pc)) {
+			if (!idetape_queue_pc_tail(drive, &pc)) {
 				if (tape->door_locked != DOOR_EXPLICITLY_LOCKED)
 					tape->door_locked = DOOR_LOCKED;
 			}
@@ -5458,22 +5789,22 @@
 
 static void idetape_write_release (struct inode *inode)
 {
-	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
-	unsigned int minor=MINOR (inode->i_rdev);
+	unsigned int minor = MINOR(inode->i_rdev);
 
-	idetape_empty_write_pipeline (drive);
-	tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
+	idetape_empty_write_pipeline(drive);
+	tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
 	if (tape->merge_stage != NULL) {
-		idetape_pad_zeros (drive, tape->tape_block_size * (tape->user_bs_factor - 1));
-		__idetape_kfree_stage (tape->merge_stage);
+		idetape_pad_zeros(drive, tape->tape_block_size * (tape->user_bs_factor - 1));
+		__idetape_kfree_stage(tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
 	idetape_write_filemark(drive);
 	idetape_write_eod(drive);
-	idetape_flush_tape_buffers (drive);
+	idetape_flush_tape_buffers(drive);
 	idetape_write_header(drive, minor >= 128);
-	idetape_flush_tape_buffers (drive);
+	idetape_flush_tape_buffers(drive);
 
 	return;
 }
@@ -5483,16 +5814,16 @@
  */
 static int idetape_chrdev_release (struct inode *inode, struct file *filp)
 {
-	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape;
 	idetape_pc_t pc;
-	unsigned int minor=MINOR (inode->i_rdev);
+	unsigned int minor = MINOR(inode->i_rdev);
 
 	lock_kernel();
 	tape = drive->driver_data;
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_chrdev_release\n");
+		printk(KERN_INFO "ide-tape: Reached idetape_chrdev_release\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
 	if (tape->chrdev_direction == idetape_direction_write) {
@@ -5500,25 +5831,26 @@
 	}
 	if (tape->chrdev_direction == idetape_direction_read) {
 		if (minor < 128)
-			idetape_discard_read_pipeline (drive, 1);
+			idetape_discard_read_pipeline(drive, 1);
 		else
-			idetape_wait_for_pipeline (drive);
+			idetape_wait_for_pipeline(drive);
 	}
 	if (tape->cache_stage != NULL) {
-		__idetape_kfree_stage (tape->cache_stage);
+		__idetape_kfree_stage(tape->cache_stage);
 		tape->cache_stage = NULL;
 	}
 	if (minor < 128)
-		(void) idetape_rewind_tape (drive);
+		(void) idetape_rewind_tape(drive);
 	if (tape->chrdev_direction == idetape_direction_none) {
-		if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) {
-			if (idetape_create_prevent_cmd(drive, &pc, 0))
-				if (!idetape_queue_pc_tail (drive, &pc))
+		if (tape->door_locked == DOOR_LOCKED) {
+			if (idetape_create_prevent_cmd(drive, &pc, 0)) {
+				if (!idetape_queue_pc_tail(drive, &pc))
 					tape->door_locked = DOOR_UNLOCKED;
+			}
 		}
 		MOD_DEC_USE_COUNT;
 	}
-	clear_bit (IDETAPE_BUSY, &tape->flags);
+	clear_bit(IDETAPE_BUSY, &tape->flags);
 	unlock_kernel();
 	return 0;
 }
@@ -5545,107 +5877,107 @@
 	*((unsigned short *) &gcw) = id->config;
 
 #if IDETAPE_DEBUG_INFO
-	printk (KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
-	printk (KERN_INFO "ide-tape: Protocol Type: ");
+	printk(KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
+	printk(KERN_INFO "ide-tape: Protocol Type: ");
 	switch (gcw.protocol) {
-		case 0: case 1: printk (KERN_INFO "ATA\n");break;
-		case 2:	printk (KERN_INFO "ATAPI\n");break;
-		case 3: printk (KERN_INFO "Reserved (Unknown to ide-tape)\n");break;
+		case 0: case 1: printk("ATA\n");break;
+		case 2:	printk("ATAPI\n");break;
+		case 3: printk("Reserved (Unknown to ide-tape)\n");break;
 	}
-	printk (KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);	
+	printk(KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);	
 	switch (gcw.device_type) {
-		case 0: printk (KERN_INFO "Direct-access Device\n");break;
-		case 1: printk (KERN_INFO "Streaming Tape Device\n");break;
-		case 2: case 3: case 4: printk (KERN_INFO "Reserved\n");break;
-		case 5: printk (KERN_INFO "CD-ROM Device\n");break;
-		case 6: printk (KERN_INFO "Reserved\n");
-		case 7: printk (KERN_INFO "Optical memory Device\n");break;
-		case 0x1f: printk (KERN_INFO "Unknown or no Device type\n");break;
-		default: printk (KERN_INFO "Reserved\n");
+		case 0: printk("Direct-access Device\n");break;
+		case 1: printk("Streaming Tape Device\n");break;
+		case 2: case 3: case 4: printk("Reserved\n");break;
+		case 5: printk("CD-ROM Device\n");break;
+		case 6: printk("Reserved\n");
+		case 7: printk("Optical memory Device\n");break;
+		case 0x1f: printk("Unknown or no Device type\n");break;
+		default: printk("Reserved\n");
 	}
-	printk (KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n");	
-	printk (KERN_INFO "ide-tape: Command Packet DRQ Type: ");
+	printk(KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n");	
+	printk(KERN_INFO "ide-tape: Command Packet DRQ Type: ");
 	switch (gcw.drq_type) {
-		case 0: printk (KERN_INFO "Microprocessor DRQ\n");break;
-		case 1: printk (KERN_INFO "Interrupt DRQ\n");break;
-		case 2: printk (KERN_INFO "Accelerated DRQ\n");break;
-		case 3: printk (KERN_INFO "Reserved\n");break;
+		case 0: printk("Microprocessor DRQ\n");break;
+		case 1: printk("Interrupt DRQ\n");break;
+		case 2: printk("Accelerated DRQ\n");break;
+		case 3: printk("Reserved\n");break;
 	}
-	printk (KERN_INFO "ide-tape: Command Packet Size: ");
+	printk(KERN_INFO "ide-tape: Command Packet Size: ");
 	switch (gcw.packet_size) {
-		case 0: printk (KERN_INFO "12 bytes\n");break;
-		case 1: printk (KERN_INFO "16 bytes\n");break;
-		default: printk (KERN_INFO "Reserved\n");break;
-	}
-	printk (KERN_INFO "ide-tape: Model: %.40s\n",id->model);
-	printk (KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev);
-	printk (KERN_INFO "ide-tape: Serial Number: %.20s\n",id->serial_no);
-	printk (KERN_INFO "ide-tape: Write buffer size: %d bytes\n",id->buf_size*512);
-	printk (KERN_INFO "ide-tape: DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
-	printk (KERN_INFO "ide-tape: LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
-	printk (KERN_INFO "ide-tape: IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
-	printk (KERN_INFO "ide-tape: IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
-	printk (KERN_INFO "ide-tape: ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
-	printk (KERN_INFO "ide-tape: PIO Cycle Timing Category: %d\n",id->tPIO);
-	printk (KERN_INFO "ide-tape: DMA Cycle Timing Category: %d\n",id->tDMA);
-	printk (KERN_INFO "ide-tape: Single Word DMA supported modes: ");
+		case 0: printk("12 bytes\n");break;
+		case 1: printk("16 bytes\n");break;
+		default: printk("Reserved\n");break;
+	}
+	printk(KERN_INFO "ide-tape: Model: %.40s\n",id->model);
+	printk(KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev);
+	printk(KERN_INFO "ide-tape: Serial Number: %.20s\n",id->serial_no);
+	printk(KERN_INFO "ide-tape: Write buffer size: %d bytes\n",id->buf_size*512);
+	printk(KERN_INFO "ide-tape: DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
+	printk(KERN_INFO "ide-tape: LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
+	printk(KERN_INFO "ide-tape: IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
+	printk(KERN_INFO "ide-tape: IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
+	printk(KERN_INFO "ide-tape: ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
+	printk(KERN_INFO "ide-tape: PIO Cycle Timing Category: %d\n",id->tPIO);
+	printk(KERN_INFO "ide-tape: DMA Cycle Timing Category: %d\n",id->tDMA);
+	printk(KERN_INFO "ide-tape: Single Word DMA supported modes: ");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_1word & mask)
-			printk (KERN_INFO "%d ",i);
+			printk("%d ",i);
 		if (id->dma_1word & (mask << 8))
-			printk (KERN_INFO "(active) ");
+			printk("(active) ");
 	}
-	printk (KERN_INFO "\n");
-	printk (KERN_INFO "ide-tape: Multi Word DMA supported modes: ");
+	printk("\n");
+	printk(KERN_INFO "ide-tape: Multi Word DMA supported modes: ");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_mword & mask)
-			printk (KERN_INFO "%d ",i);
+			printk("%d ",i);
 		if (id->dma_mword & (mask << 8))
-			printk (KERN_INFO "(active) ");
+			printk("(active) ");
 	}
-	printk (KERN_INFO "\n");
+	printk("\n");
 	if (id->field_valid & 0x0002) {
-		printk (KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None");
-		printk (KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
+		printk(KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None");
+		printk(KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
 		if (id->eide_dma_min == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_dma_min);
+			printk("%d ns\n",id->eide_dma_min);
 
-		printk (KERN_INFO "ide-tape: Manufacturer\'s Recommended Multi-word cycle: ");
+		printk(KERN_INFO "ide-tape: Manufacturer\'s Recommended Multi-word cycle: ");
 		if (id->eide_dma_time == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_dma_time);
+			printk("%d ns\n",id->eide_dma_time);
 
-		printk (KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: ");
+		printk(KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: ");
 		if (id->eide_pio == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_pio);
+			printk("%d ns\n",id->eide_pio);
 
-		printk (KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: ");
+		printk(KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: ");
 		if (id->eide_pio_iordy == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_pio_iordy);
+			printk("%d ns\n",id->eide_pio_iordy);
 		
 	} else
-		printk (KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
+		printk(KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
 #endif /* IDETAPE_DEBUG_INFO */
 
 	/* Check that we can support this device */
 
 	if (gcw.protocol !=2 )
-		printk (KERN_ERR "ide-tape: Protocol is not ATAPI\n");
+		printk(KERN_ERR "ide-tape: Protocol is not ATAPI\n");
 	else if (gcw.device_type != 1)
-		printk (KERN_ERR "ide-tape: Device type is not set to tape\n");
+		printk(KERN_ERR "ide-tape: Device type is not set to tape\n");
 	else if (!gcw.removable)
-		printk (KERN_ERR "ide-tape: The removable flag is not set\n");
+		printk(KERN_ERR "ide-tape: The removable flag is not set\n");
 	else if (gcw.packet_size != 0) {
-		printk (KERN_ERR "ide-tape: Packet size is not 12 bytes long\n");
+		printk(KERN_ERR "ide-tape: Packet size is not 12 bytes long\n");
 		if (gcw.packet_size == 1)
-			printk (KERN_ERR "ide-tape: Sorry, padding to 16 bytes is still not supported\n");
+			printk(KERN_ERR "ide-tape: Sorry, padding to 16 bytes is still not supported\n");
 	} else
 		return 1;
 	return 0;
@@ -5672,8 +6004,8 @@
 	pc.buffer[4 + 5] = vendor[3];
 	pc.buffer[4 + 6] = 0;
 	pc.buffer[4 + 7] = 0;
-	if (idetape_queue_pc_tail (drive, &pc))
-		printk (KERN_ERR "ide-tape: Couldn't set vendor name to %s\n", vendor);
+	if (idetape_queue_pc_tail(drive, &pc))
+		printk(KERN_ERR "ide-tape: Couldn't set vendor name to %s\n", vendor);
 
 }
 
@@ -5694,8 +6026,8 @@
 	pc.buffer[4 + 1] = 2;
 	pc.buffer[4 + 2] = 4;
 	pc.buffer[4 + 3] = retries;
-	if (idetape_queue_pc_tail (drive, &pc))
-		printk (KERN_ERR "ide-tape: Couldn't set retries to %d\n", retries);
+	if (idetape_queue_pc_tail(drive, &pc))
+		printk(KERN_ERR "ide-tape: Couldn't set retries to %d\n", retries);
 }
 #endif
 
@@ -5711,9 +6043,9 @@
 	/*
 	 * Get the current block size from the block size mode page
 	 */
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_BLOCK_SIZE_PAGE);
-	if (idetape_queue_pc_tail (drive, &pc))
-		printk (KERN_ERR "ide-tape: can't get tape block size mode page\n");
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_SIZE_PAGE);
+	if (idetape_queue_pc_tail(drive, &pc))
+		printk(KERN_ERR "ide-tape: can't get tape block size mode page\n");
 	header = (idetape_mode_parameter_header_t *) pc.buffer;
 	bs = (idetape_block_size_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
 
@@ -5733,8 +6065,8 @@
 	bs->record32 = 0;
 	bs->record32_5 = 1;
 	idetape_create_mode_select_cmd(&pc, sizeof(*header) + sizeof(*bs));
-	if (idetape_queue_pc_tail (drive, &pc))
-		printk (KERN_ERR "ide-tape: Couldn't set tape block size mode page\n");
+	if (idetape_queue_pc_tail(drive, &pc))
+		printk(KERN_ERR "ide-tape: Couldn't set tape block size mode page\n");
 
 #if ONSTREAM_DEBUG
 	/*
@@ -5756,8 +6088,8 @@
 	idetape_inquiry_result_t *inquiry;
 	
 	idetape_create_inquiry_cmd(&pc);
-	if (idetape_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name);
+	if (idetape_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name);
 		return;
 	}
 	inquiry = (idetape_inquiry_result_t *) pc.buffer;
@@ -5809,9 +6141,9 @@
 	idetape_mode_parameter_header_t *header;
 	onstream_tape_paramtr_page_t *prm;
 	
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_PARAMTR_PAGE);
-	if (idetape_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-tape: Can't get tape parameters page - probably no tape inserted in onstream drive\n");
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_PARAMTR_PAGE);
+	if (idetape_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-tape: Can't get tape parameters page - probably no tape inserted in onstream drive\n");
 		return;
 	}
 	header = (idetape_mode_parameter_header_t *) pc.buffer;
@@ -5819,7 +6151,7 @@
 
         tape->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
         if (debug) {
-	    printk (KERN_INFO "ide-tape: %s <-> %s: Tape length %dMB (%d frames/track, %d tracks = %d blocks, density: %dKbpi)\n",
+	    printk(KERN_INFO "ide-tape: %s <-> %s: Tape length %dMB (%d frames/track, %d tracks = %d blocks, density: %dKbpi)\n",
                drive->name, tape->name, tape->capacity/32, ntohs(prm->segtrk), ntohs(prm->trks), tape->capacity, prm->density);
         }
 
@@ -5838,20 +6170,22 @@
 	idetape_mode_parameter_header_t *header;
 	idetape_capabilities_page_t *capabilities;
 	
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_CAPABILITIES_PAGE);
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_CAPABILITIES_PAGE);
 	if (idetape_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-tape: Can't get tape parameters - assuming some default values\n");
-		tape->tape_block_size = 512; tape->capabilities.ctl = 52;
-		tape->capabilities.speed = 450; tape->capabilities.buffer_size = 6 * 52;
+		printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming some default values\n");
+		tape->tape_block_size = 512;
+		tape->capabilities.ctl = 52;
+		tape->capabilities.speed = 450;
+		tape->capabilities.buffer_size = 6 * 52;
 		return;
 	}
 	header = (idetape_mode_parameter_header_t *) pc.buffer;
 	capabilities = (idetape_capabilities_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
 
-	capabilities->max_speed = ntohs (capabilities->max_speed);
-	capabilities->ctl = ntohs (capabilities->ctl);
-	capabilities->speed = ntohs (capabilities->speed);
-	capabilities->buffer_size = ntohs (capabilities->buffer_size);
+	capabilities->max_speed = ntohs(capabilities->max_speed);
+	capabilities->ctl = ntohs(capabilities->ctl);
+	capabilities->speed = ntohs(capabilities->speed);
+	capabilities->buffer_size = ntohs(capabilities->buffer_size);
 
 	if (!capabilities->speed) {
 		printk(KERN_INFO "ide-tape: %s: overriding capabilities->speed (assuming 650KB/sec)\n", drive->name);
@@ -5871,33 +6205,33 @@
 		tape->tape_block_size = 32768;
 
 #if IDETAPE_DEBUG_INFO
-	printk (KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n");
-	printk (KERN_INFO "ide-tape: Mode Parameter Header:\n");
-	printk (KERN_INFO "ide-tape: Mode Data Length - %d\n",header->mode_data_length);
-	printk (KERN_INFO "ide-tape: Medium Type - %d\n",header->medium_type);
-	printk (KERN_INFO "ide-tape: Device Specific Parameter - %d\n",header->dsp);
-	printk (KERN_INFO "ide-tape: Block Descriptor Length - %d\n",header->bdl);
+	printk(KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n");
+	printk(KERN_INFO "ide-tape: Mode Parameter Header:\n");
+	printk(KERN_INFO "ide-tape: Mode Data Length - %d\n",header->mode_data_length);
+	printk(KERN_INFO "ide-tape: Medium Type - %d\n",header->medium_type);
+	printk(KERN_INFO "ide-tape: Device Specific Parameter - %d\n",header->dsp);
+	printk(KERN_INFO "ide-tape: Block Descriptor Length - %d\n",header->bdl);
 	
-	printk (KERN_INFO "ide-tape: Capabilities and Mechanical Status Page:\n");
-	printk (KERN_INFO "ide-tape: Page code - %d\n",capabilities->page_code);
-	printk (KERN_INFO "ide-tape: Page length - %d\n",capabilities->page_length);
-	printk (KERN_INFO "ide-tape: Read only - %s\n",capabilities->ro ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports error correction - %s\n",capabilities->ecc ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports 32768 bytes block size / Restricted byte count for PIO transfers - %s\n",capabilities->blk32768 ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Maximum supported speed in KBps - %d\n",capabilities->max_speed);
-	printk (KERN_INFO "ide-tape: Continuous transfer limits in blocks - %d\n",capabilities->ctl);
-	printk (KERN_INFO "ide-tape: Current speed in KBps - %d\n",capabilities->speed);	
-	printk (KERN_INFO "ide-tape: Buffer size - %d\n",capabilities->buffer_size*512);
+	printk(KERN_INFO "ide-tape: Capabilities and Mechanical Status Page:\n");
+	printk(KERN_INFO "ide-tape: Page code - %d\n",capabilities->page_code);
+	printk(KERN_INFO "ide-tape: Page length - %d\n",capabilities->page_length);
+	printk(KERN_INFO "ide-tape: Read only - %s\n",capabilities->ro ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports error correction - %s\n",capabilities->ecc ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports 32768 bytes block size / Restricted byte count for PIO transfers - %s\n",capabilities->blk32768 ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Maximum supported speed in KBps - %d\n",capabilities->max_speed);
+	printk(KERN_INFO "ide-tape: Continuous transfer limits in blocks - %d\n",capabilities->ctl);
+	printk(KERN_INFO "ide-tape: Current speed in KBps - %d\n",capabilities->speed);	
+	printk(KERN_INFO "ide-tape: Buffer size - %d\n",capabilities->buffer_size*512);
 #endif /* IDETAPE_DEBUG_INFO */
 }
 
@@ -5913,9 +6247,9 @@
 	idetape_mode_parameter_header_t *header;
 	idetape_parameter_block_descriptor_t *block_descrp;
 	
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_BLOCK_DESCRIPTOR);
-	if (idetape_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-tape: Can't get block descriptor\n");
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR);
+	if (idetape_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-tape: Can't get block descriptor\n");
 		if (tape->tape_block_size == 0) {
 			printk(KERN_WARNING "ide-tape: Cannot deal with zero block size, assume 32k\n");
 			tape->tape_block_size =  32768;
@@ -5926,9 +6260,10 @@
 	block_descrp = (idetape_parameter_block_descriptor_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t));
 	tape->tape_block_size =( block_descrp->length[0]<<16) + (block_descrp->length[1]<<8) + block_descrp->length[2];
 #if IDETAPE_DEBUG_INFO
-	printk (KERN_INFO "ide-tape: Adjusted block size - %d\n", tape->tape_block_size);
+	printk(KERN_INFO "ide-tape: Adjusted block size - %d\n", tape->tape_block_size);
 #endif /* IDETAPE_DEBUG_INFO */
 }
+
 static void idetape_add_settings (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
@@ -5937,9 +6272,9 @@
  *			drive	setting name	read/write	ioctl	ioctl		data type	min			max			mul_factor			div_factor			data pointer				set function
  */
 	ide_add_setting(drive,	"buffer",	SETTING_READ,	-1,	-1,		TYPE_SHORT,	0,			0xffff,			1,				2,				&tape->capabilities.buffer_size,	NULL);
-	ide_add_setting(drive,	"pipeline_min",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			0xffff,			tape->stage_size / 1024,	1,				&tape->min_pipeline,			NULL);
-	ide_add_setting(drive,	"pipeline",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_stages,			NULL);
-	ide_add_setting(drive,	"pipeline_max",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_pipeline,			NULL);
+	ide_add_setting(drive,	"pipeline_min",	SETTING_RW,	-1,	-1,		TYPE_INT,	1,			0xffff,			tape->stage_size / 1024,	1,				&tape->min_pipeline,			NULL);
+	ide_add_setting(drive,	"pipeline",	SETTING_RW,	-1,	-1,		TYPE_INT,	1,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_stages,			NULL);
+	ide_add_setting(drive,	"pipeline_max",	SETTING_RW,	-1,	-1,		TYPE_INT,	1,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_pipeline,			NULL);
 	ide_add_setting(drive,	"pipeline_used",SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			tape->stage_size / 1024,	1,				&tape->nr_stages,			NULL);
 	ide_add_setting(drive,	"pipeline_pending",SETTING_READ,-1,	-1,		TYPE_INT,	0,			0xffff,			tape->stage_size / 1024,	1,				&tape->nr_pending_stages,		NULL);
 	ide_add_setting(drive,	"speed",	SETTING_READ,	-1,	-1,		TYPE_SHORT,	0,			0xffff,			1,				1,				&tape->capabilities.speed,		NULL);
@@ -5984,29 +6319,24 @@
 	int stage_size;
 	struct sysinfo si;
 
-	memset (tape, 0, sizeof (idetape_tape_t));
+	memset(tape, 0, sizeof (idetape_tape_t));
 	spin_lock_init(&tape->spinlock);
 	drive->driver_data = tape;
-	drive->ready_stat = 0;			/* An ATAPI device ignores DRDY */
+	/* An ATAPI device ignores DRDY */
+	drive->ready_stat = 0;
 	if (strstr(drive->id->model, "OnStream DI-"))
 		tape->onstream = 1;
-	drive->dsc_overlap = 1;
-#ifdef CONFIG_BLK_DEV_IDEPCI
-	if (!tape->onstream && HWIF(drive)->pci_dev != NULL) {
-		/*
-		 * These two ide-pci host adapters appear to need DSC overlap disabled.
-		 * This probably needs further analysis.
-		 */
-		if ((HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) ||
-		    (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) {
-			printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n", tape->name);
-		    	drive->dsc_overlap = 0;
-		}
+	drive->dsc_overlap = (HWIF(drive)->no_dsc) ? 0 : 1;
+	if (HWIF(drive)->no_dsc) {
+		printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n",
+			tape->name);
+		drive->dsc_overlap = 0;
 	}
-#endif /* CONFIG_BLK_DEV_IDEPCI */
 	tape->drive = drive;
 	tape->minor = minor;
-	tape->name[0] = 'h'; tape->name[1] = 't'; tape->name[2] = '0' + minor;
+	tape->name[0] = 'h';
+	tape->name[1] = 't';
+	tape->name[2] = '0' + minor;
 	tape->chrdev_direction = idetape_direction_none;
 	tape->pc = tape->pc_stack;
 	tape->max_insert_speed = 10000;
@@ -6044,7 +6374,7 @@
 	 *	Select the "best" DSC read/write polling frequency
 	 *	and pipeline size.
 	 */
-	speed = IDE_MAX (tape->capabilities.speed, tape->capabilities.max_speed);
+	speed = IDE_MAX(tape->capabilities.speed, tape->capabilities.max_speed);
 
 	tape->max_stages = speed * 1000 * 10 / tape->stage_size;
 
@@ -6052,10 +6382,13 @@
 	 * 	Limit memory use for pipeline to 10% of physical memory
 	 */
 	si_meminfo(&si);
-	if ( tape->max_stages * tape->stage_size > si.totalram * si.mem_unit / 10)
+	if (tape->max_stages * tape->stage_size > si.totalram * si.mem_unit / 10)
 		tape->max_stages = si.totalram * si.mem_unit / (10 * tape->stage_size);
-	tape->min_pipeline = tape->max_stages;
-	tape->max_pipeline = tape->max_stages * 2;
+	tape->max_stages   = IDE_MIN(tape->max_stages, IDETAPE_MAX_PIPELINE_STAGES);
+	tape->min_pipeline = IDE_MIN(tape->max_stages, IDETAPE_MIN_PIPELINE_STAGES);
+	tape->max_pipeline = IDE_MIN(tape->max_stages * 2, IDETAPE_MAX_PIPELINE_STAGES);
+	if (tape->max_stages == 0)
+		tape->max_stages = tape->min_pipeline = tape->max_pipeline = 1;
 
 	t1 = (tape->stage_size * HZ) / (speed * 1000);
 	tmid = (tape->capabilities.buffer_size * 32 * HZ) / (speed * 125);
@@ -6070,11 +6403,15 @@
 	 *	Ensure that the number we got makes sense; limit
 	 *	it within IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX.
 	 */
-	tape->best_dsc_rw_frequency = IDE_MAX (IDE_MIN (t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN);
-	printk (KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, %dkB pipeline, %lums tDSC%s\n",
-		drive->name, tape->name, tape->capabilities.speed, (tape->capabilities.buffer_size * 512) / tape->stage_size,
-		tape->stage_size / 1024, tape->max_stages * tape->stage_size / 1024,
-		tape->best_dsc_rw_frequency * 1000 / HZ, drive->using_dma ? ", DMA":"");
+	tape->best_dsc_rw_frequency = IDE_MAX(IDE_MIN(t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN);
+	printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, "
+		"%dkB pipeline, %lums tDSC%s\n",
+		drive->name, tape->name, tape->capabilities.speed,
+		(tape->capabilities.buffer_size * 512) / tape->stage_size,
+		tape->stage_size / 1024,
+		tape->max_stages * tape->stage_size / 1024,
+		tape->best_dsc_rw_frequency * 1000 / HZ,
+		drive->using_dma ? ", DMA":"");
 
 	idetape_add_settings(drive);
 }
@@ -6085,24 +6422,24 @@
 	int minor = tape->minor;
 	unsigned long flags;
 
-	save_flags (flags);	/* all CPUs (overkill?) */
-	cli();			/* all CPUs (overkill?) */
-	if (test_bit (IDETAPE_BUSY, &tape->flags) || tape->first_stage != NULL || tape->merge_stage_size || drive->usage) {
-		restore_flags(flags);	/* all CPUs (overkill?) */
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (test_bit(IDETAPE_BUSY, &tape->flags) || drive->usage ||
+	    tape->first_stage != NULL || tape->merge_stage_size) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		return 1;
 	}
 	idetape_chrdevs[minor].drive = NULL;
-	restore_flags (flags);	/* all CPUs (overkill?) */
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	DRIVER(drive)->busy = 0;
-	(void) ide_unregister_subdriver (drive);
+	(void) ide_unregister_subdriver(drive);
 	drive->driver_data = NULL;
-	devfs_unregister (tape->de_r);
-	devfs_unregister (tape->de_n);
-	kfree (tape);
+	devfs_unregister(tape->de_r);
+	devfs_unregister(tape->de_n);
+	kfree(tape);
 	for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++)
 		if (idetape_chrdevs[minor].drive != NULL)
 			return 0;
-	devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
+	devfs_unregister_chrdev(IDETAPE_MAJOR, "ht");
 	idetape_chrdev_present = 0;
 	return 0;
 }
@@ -6132,7 +6469,8 @@
 
 #endif
 
-int idetape_reinit(ide_drive_t *drive);
+int idetape_init (void);
+int idetape_attach(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -6142,13 +6480,21 @@
 	version:		IDETAPE_VERSION,
 	media:			ide_tape,
 	busy:			1,
+#ifdef CONFIG_IDEDMA_ONLYDISK
+	supports_dma:		0,
+#else
 	supports_dma:		1,
+#endif
 	supports_dsc_overlap: 	1,
 	cleanup:		idetape_cleanup,
 	standby:		NULL,
+	suspend:		NULL,
+	resume:			NULL,
 	flushcache:		NULL,
 	do_request:		idetape_do_request,
 	end_request:		idetape_end_request,
+	sense:			NULL,
+	error:			NULL,
 	ioctl:			idetape_blkdev_ioctl,
 	open:			idetape_blkdev_open,
 	release:		idetape_blkdev_release,
@@ -6156,13 +6502,14 @@
 	revalidate:		NULL,
 	pre_reset:		idetape_pre_reset,
 	capacity:		NULL,
+	special:		NULL,
 	proc:			idetape_proc,
-	reinit:			idetape_reinit,
+	init:			idetape_init,
+	attach:			idetape_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 };
 
-int idetape_init (void);
 static ide_module_t idetape_module = {
 	IDE_DRIVER_MODULE,
 	idetape_init,
@@ -6182,90 +6529,62 @@
 	release:	idetape_chrdev_release,
 };
 
-int idetape_reinit (ide_drive_t *drive)
+int idetape_attach (ide_drive_t *drive)
 {
-#if 0
 	idetape_tape_t *tape;
-	int minor, failed = 0, supported = 0;
-/* DRIVER(drive)->busy++; */
+	int minor = 0, ret = 0;
+
 	MOD_INC_USE_COUNT;
-#if ONSTREAM_DEBUG
-        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
-#endif
-	if (!idetape_chrdev_present)
-		for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
-			idetape_chrdevs[minor].drive = NULL;
 
-	if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) {
-		ide_register_module (&idetape_module);
-		MOD_DEC_USE_COUNT;
-#if ONSTREAM_DEBUG
-		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
-#endif
-		return 0;
-	}
-	if (!idetape_chrdev_present &&
-	    devfs_register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) {
-		printk (KERN_ERR "ide-tape: Failed to register character device interface\n");
-		MOD_DEC_USE_COUNT;
-#if ONSTREAM_DEBUG
-		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
-#endif
-		return -EBUSY;
-	}
-	do {
-		if (!idetape_identify_device (drive, drive->id)) {
-			printk (KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name);
-			continue;
-		}
-		if (drive->scsi) {
-			if (strstr(drive->id->model, "OnStream DI-30")) {
-				printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model);
-			} else {
-				printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name);
-				continue;
-			}
-		}
-		tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
-		if (tape == NULL) {
-			printk (KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
-			continue;
-		}
-		if (ide_register_subdriver (drive, &idetape_driver, IDE_SUBDRIVER_VERSION)) {
-			printk (KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
-			kfree (tape);
-			continue;
-		}
-		for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
-		idetape_setup (drive, tape, minor);
-		idetape_chrdevs[minor].drive = drive;
-		tape->de_r =
-		    devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
+	if (!idetape_identify_device(drive, drive->id)) {
+		printk(KERN_ERR "ide-tape: %s: not supported by this "
+			"version of ide-tape\n", drive->name);
+			ret = 1;
+			goto bye_game_over;
+	}
+	if (drive->scsi) {
+		if (strstr(drive->id->model, "OnStream DI-30")) {
+			printk("ide-tape: ide-scsi emulation is not "
+				"supported for %s.\n", drive->id->model);
+		} else {
+			printk("ide-tape: passing drive %s to ide-scsi "
+				"emulation.\n", drive->name);
+			ret = 1;
+			goto bye_game_over;
+		}
+	}
+	tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
+	if (tape == NULL) {
+		printk(KERN_ERR "ide-tape: %s: Can't allocate a "
+			"tape structure\n", drive->name);
+		ret = 1;
+		goto bye_game_over;
+	}
+	if (ide_register_subdriver(drive,
+			&idetape_driver, IDE_SUBDRIVER_VERSION)) {
+		printk(KERN_ERR "ide-tape: %s: Failed to register the "
+				"driver with ide.c\n", drive->name);
+		kfree(tape);
+		ret = 1;
+		goto bye_game_over;
+	}
+	for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
+	idetape_setup (drive, tape, minor);
+	idetape_chrdevs[minor].drive = drive;
+	tape->de_r = devfs_register(drive->de, "mt", DEVFS_FL_DEFAULT,
 				    HWIF(drive)->major, minor,
 				    S_IFCHR | S_IRUGO | S_IWUGO,
 				    &idetape_fops, NULL);
-		tape->de_n =
-		    devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
+	tape->de_n = devfs_register(drive->de, "mtn", DEVFS_FL_DEFAULT,
 				    HWIF(drive)->major, minor + 128,
 				    S_IFCHR | S_IRUGO | S_IWUGO,
 				    &idetape_fops, NULL);
-		devfs_register_tape (tape->de_r);
-		supported++; failed--;
-	} while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL);
-	if (!idetape_chrdev_present && !supported) {
-		devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
-	} else
-		idetape_chrdev_present = 1;
-	ide_register_module (&idetape_module);
+	devfs_register_tape(tape->de_r);
+
+bye_game_over:
 	MOD_DEC_USE_COUNT;
-#if ONSTREAM_DEBUG
-	printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
-#endif
 
-	return 0;
-#else
-	return 1;
-#endif
+	return ret;
 }
 
 MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
@@ -6278,94 +6597,118 @@
 
 	for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++) {
 		drive = idetape_chrdevs[minor].drive;
-		if (drive != NULL && idetape_cleanup (drive))
-		printk (KERN_ERR "ide-tape: %s: cleanup_module() called while still busy\n", drive->name);
+		if (drive != NULL && idetape_cleanup(drive))
+			printk(KERN_ERR "ide-tape: %s: cleanup_module() "
+				"called while still busy\n", drive->name);
 	}
+#ifdef CONFIG_PROC_FS
+	if (drive->proc)
+		ide_remove_proc_entries(drive->proc, idetape_proc);
+#endif
+
 	ide_unregister_module(&idetape_module);
 }
 
-/*
- *	idetape_init will register the driver for each tape.
- */
 int idetape_init (void)
 {
+#ifdef CLASSIC_BUILTINS_METHOD
 	ide_drive_t *drive;
 	idetape_tape_t *tape;
 	int minor, failed = 0, supported = 0;
 /* DRIVER(drive)->busy++; */
 	MOD_INC_USE_COUNT;
 #if ONSTREAM_DEBUG
-        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
+	printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
 #endif
 	if (!idetape_chrdev_present)
 		for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
 			idetape_chrdevs[minor].drive = NULL;
-
-	if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) {
-		ide_register_module (&idetape_module);
+	if ((drive = ide_scan_devices(ide_tape, idetape_driver.name,
+			NULL, failed++)) == NULL) {
+		ide_register_module(&idetape_module);
 		MOD_DEC_USE_COUNT;
 #if ONSTREAM_DEBUG
-		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in "
+			"idetape_init\n");
 #endif
 		return 0;
 	}
 	if (!idetape_chrdev_present &&
-	    devfs_register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) {
-		printk (KERN_ERR "ide-tape: Failed to register character device interface\n");
+	    devfs_register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) {
+		printk(KERN_ERR "ide-tape: Failed to register character "
+			"device interface\n");
 		MOD_DEC_USE_COUNT;
 #if ONSTREAM_DEBUG
-		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in "
+			"idetape_init\n");
 #endif
 		return -EBUSY;
 	}
 	do {
-		if (!idetape_identify_device (drive, drive->id)) {
-			printk (KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name);
+		if (!idetape_identify_device(drive, drive->id)) {
+			printk(KERN_ERR "ide-tape: %s: not supported by this "
+				"version of ide-tape\n", drive->name);
 			continue;
 		}
 		if (drive->scsi) {
 			if (strstr(drive->id->model, "OnStream DI-")) {
-				printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model);
+				printk("ide-tape: ide-scsi emulation is not "
+					"supported for %s.\n",
+					drive->id->model);
 			} else {
-				printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name);
+				printk("ide-tape: passing drive %s to "
+					"ide-scsi emulation.\n", drive->name);
 				continue;
 			}
 		}
 		tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
 		if (tape == NULL) {
-			printk (KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
+			printk(KERN_ERR "ide-tape: %s: Can't allocate a tape "
+				"structure\n", drive->name);
 			continue;
 		}
-		if (ide_register_subdriver (drive, &idetape_driver, IDE_SUBDRIVER_VERSION)) {
-			printk (KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
-			kfree (tape);
+		if (ide_register_subdriver(drive,
+				&idetape_driver, IDE_SUBDRIVER_VERSION)) {
+			printk(KERN_ERR "ide-tape: %s: Failed to register the "
+				"driver with ide.c\n", drive->name);
+			kfree(tape);
 			continue;
 		}
 		for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
-		idetape_setup (drive, tape, minor);
+		idetape_setup(drive, tape, minor);
 		idetape_chrdevs[minor].drive = drive;
 		tape->de_r =
-		    devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
+		    devfs_register(drive->de, "mt", DEVFS_FL_DEFAULT,
 				    HWIF(drive)->major, minor,
 				    S_IFCHR | S_IRUGO | S_IWUGO,
 				    &idetape_fops, NULL);
 		tape->de_n =
-		    devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
+		    devfs_register(drive->de, "mtn", DEVFS_FL_DEFAULT,
 				    HWIF(drive)->major, minor + 128,
 				    S_IFCHR | S_IRUGO | S_IWUGO,
 				    &idetape_fops, NULL);
-		devfs_register_tape (tape->de_r);
-		supported++; failed--;
-	} while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL);
+		devfs_register_tape(tape->de_r);
+		supported++;
+		failed--;
+	} while ((drive = ide_scan_devices(ide_tape,
+			idetape_driver.name, NULL, failed++)) != NULL);
 	if (!idetape_chrdev_present && !supported) {
-		devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
+		devfs_unregister_chrdev(IDETAPE_MAJOR, "ht");
 	} else
 		idetape_chrdev_present = 1;
-	ide_register_module (&idetape_module);
+#else /* ! CLASSIC_BUILTINS_METHOD */
+	int minor = 0;
+
+	if (idetape_chrdev_present)
+		return 0;
+	idetape_chrdev_present = 1;
+	for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
+		idetape_chrdevs[minor].drive = NULL;
+	devfs_register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops);
+	MOD_INC_USE_COUNT;
+#endif /* CLASSIC_BUILTINS_METHOD */
+	ide_register_module(&idetape_module);
 	MOD_DEC_USE_COUNT;
-#if ONSTREAM_DEBUG
-	printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
-#endif
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-taskfile.c linux-2.4.21/drivers/ide/ide-taskfile.c
--- linux-2.4.20/drivers/ide/ide-taskfile.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide-taskfile.c	2002-12-18 18:58:03.000000000 +0000
@@ -1,12 +1,29 @@
 /*
- * linux/drivers/ide/ide-taskfile.c	Version 0.20	Oct 11, 2000
+ * linux/drivers/ide/ide-taskfile.c	Version 0.33	April 11, 2002
  *
- *  Copyright (C) 2000		Michael Cornwell <cornwell@acm.org>
- *  Copyright (C) 2000		Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (C) 2000-2002	Michael Cornwell <cornwell@acm.org>
+ *  Copyright (C) 2000-2002	Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (C) 2001-2002	Klaus Smolin
+ *					IBM Storage Technology Division
  *
- *  May be copied or modified under the terms of the GNU General Public License
+ *  The big the bad and the ugly.
  *
- * IDE_DEBUG(__LINE__);
+ *  Problems to be fixed because of BH interface or the lack therefore.
+ *
+ *  Fill me in stupid !!!
+ *
+ *  HOST:
+ *	General refers to the Controller and Driver "pair".
+ *  DATA HANDLER:
+ *	Under the context of Linux it generally refers to an interrupt handler.
+ *	However, it correctly describes the 'HOST'
+ *  DATA BLOCK:
+ *	The amount of data needed to be transfered as predefined in the
+ *	setup of the device.
+ *  STORAGE ATOMIC:
+ *	The 'DATA BLOCK' associated to the 'DATA HANDLER', and can be as
+ *	small as a single sector or as large as the entire command block
+ *	request.
  */
 
 #include <linux/config.h>
@@ -34,27 +51,50 @@
 #include <asm/io.h>
 #include <asm/bitops.h>
 
-#ifdef CONFIG_IDE_TASKFILE_IO
-#  define __TASKFILE__IO
-#else /* CONFIG_IDE_TASKFILE_IO */
-#  undef __TASKFILE__IO
-#endif /* CONFIG_IDE_TASKFILE_IO */
-
 #define DEBUG_TASKFILE	0	/* unset when fixed */
 
 #if DEBUG_TASKFILE
-#define DTF(x...) printk(##x)
+#define DTF(x...) printk(x)
 #else
 #define DTF(x...)
 #endif
 
+/*
+ *
+ */
+#define task_rq_offset(rq) \
+	(((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE)
+
+/*
+ * for now, taskfile requests are special :/
+ *
+ * However, upon the creation of the atapi version of packet_command
+ * data-phase ISR plus it own diagnostics and extensions for direct access
+ * (ioctl,read,write,rip,stream -- atapi), the kmap/kunmap for PIO will
+ * come localized.
+ */
+inline char *task_map_rq (struct request *rq, unsigned long *flags)
+{
+	if (rq->bh)
+		return ide_map_buffer(rq, flags);
+	return rq->buffer + task_rq_offset(rq);
+}
+
+inline void task_unmap_rq (struct request *rq, char *buf, unsigned long *flags)
+{
+	if (rq->bh)
+		ide_unmap_buffer(buf, flags);
+}
+
 inline u32 task_read_24 (ide_drive_t *drive)
 {
-	return	(IN_BYTE(IDE_HCYL_REG)<<16) |
-		(IN_BYTE(IDE_LCYL_REG)<<8) |
-		 IN_BYTE(IDE_SECTOR_REG);
+	return	(HWIF(drive)->INB(IDE_HCYL_REG)<<16) |
+		(HWIF(drive)->INB(IDE_LCYL_REG)<<8) |
+		 HWIF(drive)->INB(IDE_SECTOR_REG);
 }
 
+EXPORT_SYMBOL(task_read_24);
+
 static void ata_bswap_data (void *buffer, int wcount)
 {
 	u16 *p = buffer;
@@ -65,381 +105,178 @@
 	}
 }
 
-#if SUPPORT_VLB_SYNC
-/*
- * Some localbus EIDE interfaces require a special access sequence
- * when using 32-bit I/O instructions to transfer data.  We call this
- * the "vlb_sync" sequence, which consists of three successive reads
- * of the sector count register location, with interrupts disabled
- * to ensure that the reads all happen together.
- */
-static inline void task_vlb_sync (ide_ioreg_t port) {
-	(void) inb (port);
-	(void) inb (port);
-	(void) inb (port);
-}
-#endif /* SUPPORT_VLB_SYNC */
-
-/*
- * This is used for most PIO data transfers *from* the IDE interface
- */
-void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	byte io_32bit = drive->io_32bit;
-
-	if (io_32bit) {
-#if SUPPORT_VLB_SYNC
-		if (io_32bit & 2) {
-			unsigned long flags;
-			__save_flags(flags);	/* local CPU only */
-			__cli();		/* local CPU only */
-			task_vlb_sync(IDE_NSECTOR_REG);
-			insl(IDE_DATA_REG, buffer, wcount);
-			__restore_flags(flags);	/* local CPU only */
-		} else
-#endif /* SUPPORT_VLB_SYNC */
-			insl(IDE_DATA_REG, buffer, wcount);
-	} else {
-#if SUPPORT_SLOW_DATA_PORTS
-		if (drive->slow) {
-			unsigned short *ptr = (unsigned short *) buffer;
-			while (wcount--) {
-				*ptr++ = inw_p(IDE_DATA_REG);
-				*ptr++ = inw_p(IDE_DATA_REG);
-			}
-		} else
-#endif /* SUPPORT_SLOW_DATA_PORTS */
-			insw(IDE_DATA_REG, buffer, wcount<<1);
-	}
-}
-
-/*
- * This is used for most PIO data transfers *to* the IDE interface
- */
-void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	byte io_32bit = drive->io_32bit;
-
-	if (io_32bit) {
-#if SUPPORT_VLB_SYNC
-		if (io_32bit & 2) {
-			unsigned long flags;
-			__save_flags(flags);	/* local CPU only */
-			__cli();		/* local CPU only */
-			task_vlb_sync(IDE_NSECTOR_REG);
-			outsl(IDE_DATA_REG, buffer, wcount);
-			__restore_flags(flags);	/* local CPU only */
-		} else
-#endif /* SUPPORT_VLB_SYNC */
-			outsl(IDE_DATA_REG, buffer, wcount);
-	} else {
-#if SUPPORT_SLOW_DATA_PORTS
-		if (drive->slow) {
-			unsigned short *ptr = (unsigned short *) buffer;
-			while (wcount--) {
-				outw_p(*ptr++, IDE_DATA_REG);
-				outw_p(*ptr++, IDE_DATA_REG);
-			}
-		} else
-#endif /* SUPPORT_SLOW_DATA_PORTS */
-			outsw(IDE_DATA_REG, buffer, wcount<<1);
-	}
-}
-
 
-static inline void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+void taskfile_input_data (ide_drive_t *drive, void *buffer, u32 wcount)
 {
-	ata_input_data(drive, buffer, wcount);
+	HWIF(drive)->ata_input_data(drive, buffer, wcount);
 	if (drive->bswap)
 		ata_bswap_data(buffer, wcount);
 }
 
-static inline void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+EXPORT_SYMBOL(taskfile_input_data);
+
+void taskfile_output_data (ide_drive_t *drive, void *buffer, u32 wcount)
 {
 	if (drive->bswap) {
 		ata_bswap_data(buffer, wcount);
-		ata_output_data(drive, buffer, wcount);
+		HWIF(drive)->ata_output_data(drive, buffer, wcount);
 		ata_bswap_data(buffer, wcount);
 	} else {
-		ata_output_data(drive, buffer, wcount);
+		HWIF(drive)->ata_output_data(drive, buffer, wcount);
 	}
 }
 
-ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
-{
-	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
-	hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
-	struct hd_driveid *id = drive->id;
-	byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
-
-	/* (ks/hs): Moved to start, do not use for multiple out commands */
-	if (task->handler != task_mulout_intr) {
-		if (IDE_CONTROL_REG)
-			OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
-		SELECT_MASK(HWIF(drive), drive, 0);
-	}
-
-	if ((id->command_set_2 & 0x0400) &&
-	    (id->cfs_enable_2 & 0x0400) &&
-	    (drive->addressing == 1)) {
-		OUT_BYTE(hobfile->feature, IDE_FEATURE_REG);
-		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
-		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
-		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
-		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
-	}
-
-	OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
-	OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
-	/* refers to number of sectors to transfer */
-	OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
-	/* refers to sector offset or start sector */
-	OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
-	OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
-
-	OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
-	if (task->handler != NULL) {
-#if 0
-		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
-		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-		/*
-		 * warning check for race between handler and prehandler for
-		 * writing first block of data.  however since we are well
-		 * inside the boundaries of the seek, we should be okay.
-		 */
-		if (task->prehandler != NULL) {
-			return task->prehandler(drive, task->rq);
-		}
-#else
-		ide_startstop_t startstop;
-
-		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
-		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-
-		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
-			printk(KERN_ERR "%s: no DRQ after issuing %s\n",
-				drive->name,
-				drive->mult_count ? "MULTWRITE" : "WRITE");
-			return startstop;
-		}
-		/* (ks/hs): Fixed Multi Write */
-		if ((taskfile->command != WIN_MULTWRITE) &&
-		    (taskfile->command != WIN_MULTWRITE_EXT)) {
-			struct request *rq = HWGROUP(drive)->rq;
-		/* For Write_sectors we need to stuff the first sector */
-			taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
-			rq->current_nr_sectors--;
-		} else {
-		/* Stuff first sector(s) by implicitly calling the handler */
-			if (!(drive_is_ready(drive))) {
-			/* FIXME: Replace hard-coded 100, error handling? */
-				int i;
-				for (i=0; i<100; i++) {
-					if (drive_is_ready(drive))
-						break;
-				}
-			}
-			return task->handler(drive);
-		}
-#endif
-	} else {
-		/* for dma commands we down set the handler */
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
-	}
-
-	return ide_started;
-}
+EXPORT_SYMBOL(taskfile_output_data);
 
-void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler)
+int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf)
 {
-	struct hd_driveid *id = drive->id;
-	byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
-
-	/* (ks/hs): Moved to start, do not use for multiple out commands */
-	if (*handler != task_mulout_intr) {
-		if (IDE_CONTROL_REG)
-			OUT_BYTE(drive->ctl, IDE_CONTROL_REG);  /* clear nIEN */
-		SELECT_MASK(HWIF(drive), drive, 0);
-	}
-
-	if ((id->command_set_2 & 0x0400) &&
-	    (id->cfs_enable_2 & 0x0400) &&
-	    (drive->addressing == 1)) {
-		OUT_BYTE(hobfile->feature, IDE_FEATURE_REG);
-		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
-		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
-		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
-		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
-	}
+	ide_task_t args;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
+	if (drive->media == ide_disk)
+		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_IDENTIFY;
+	else
+		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_PIDENTIFY;
+	args.command_type			= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, buf);
+}
 
-	OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
-	OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
-	/* refers to number of sectors to transfer */
-	OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
-	/* refers to sector offset or start sector */
-	OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
-	OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+EXPORT_SYMBOL(taskfile_lib_get_identify);
 
-	OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
-	if (handler != NULL) {
-		ide_set_handler (drive, handler, WAIT_CMD, NULL);
-		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-	} else {
-		/* for dma commands we down set the handler */
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
-	}
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+void debug_taskfile (ide_drive_t *drive, ide_task_t *args)
+{
+	printk(KERN_INFO "%s: ", drive->name);
+//	printk("TF.0=x%02x ", args->tfRegister[IDE_DATA_OFFSET]);
+	printk("TF.1=x%02x ", args->tfRegister[IDE_FEATURE_OFFSET]);
+	printk("TF.2=x%02x ", args->tfRegister[IDE_NSECTOR_OFFSET]);
+	printk("TF.3=x%02x ", args->tfRegister[IDE_SECTOR_OFFSET]);
+	printk("TF.4=x%02x ", args->tfRegister[IDE_LCYL_OFFSET]);
+	printk("TF.5=x%02x ", args->tfRegister[IDE_HCYL_OFFSET]);
+	printk("TF.6=x%02x ", args->tfRegister[IDE_SELECT_OFFSET]);
+	printk("TF.7=x%02x\n", args->tfRegister[IDE_COMMAND_OFFSET]);
+	printk(KERN_INFO "%s: ", drive->name);
+//	printk("HTF.0=x%02x ", args->hobRegister[IDE_DATA_OFFSET_HOB]);
+	printk("HTF.1=x%02x ", args->hobRegister[IDE_FEATURE_OFFSET_HOB]);
+	printk("HTF.2=x%02x ", args->hobRegister[IDE_NSECTOR_OFFSET_HOB]);
+	printk("HTF.3=x%02x ", args->hobRegister[IDE_SECTOR_OFFSET_HOB]);
+	printk("HTF.4=x%02x ", args->hobRegister[IDE_LCYL_OFFSET_HOB]);
+	printk("HTF.5=x%02x ", args->hobRegister[IDE_HCYL_OFFSET_HOB]);
+	printk("HTF.6=x%02x ", args->hobRegister[IDE_SELECT_OFFSET_HOB]);
+	printk("HTF.7=x%02x\n", args->hobRegister[IDE_CONTROL_OFFSET_HOB]);
 }
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
 
-#if 0
-ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
+ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
 {
-	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
-	hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
-	struct hd_driveid *id = drive->id;
-
-	/*
-	 * (KS) Check taskfile in/out flags.
-	 * If set, then execute as it is defined.
-	 * If not set, then define default settings.
-	 * The default values are:
-	 *	write and read all taskfile registers (except data) 
-	 *	write and read the hob registers (sector,nsector,lcyl,hcyl)
-	 */
-	if (task->tf_out_flags.all == 0) {
-		task->tf_out_flags.all = IDE_TASKFILE_STD_OUT_FLAGS;
-		if ((id->command_set_2 & 0x0400) &&
-		    (id->cfs_enable_2 & 0x0400) &&
-		    (drive->addressing == 1)) {
-			task->tf_out_flags.all != (IDE_HOB_STD_OUT_FLAGS << 8);
-		}
-        }
-
-	if (task->tf_in_flags.all == 0) {
-		task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
-		if ((id->command_set_2 & 0x0400) &&
-		    (id->cfs_enable_2 & 0x0400) &&
-		    (drive->addressing == 1)) {
-			task->tf_in_flags.all  != (IDE_HOB_STD_IN_FLAGS  << 8);
-		}
-        }
-
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
-	SELECT_MASK(HWIF(drive), drive, 0);
-
-	if (task->tf_out_flags.b.data) {
-		unsigned short data =  taskfile->data + (hobfile->data << 8);
-		OUT_WORD (data, IDE_DATA_REG);
-	}
-
-	/* (KS) send hob registers first */
-	if (task->tf_out_flags.b.nsector_hob)
-		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
-	if (task->tf_out_flags.b.sector_hob)
-		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
-	if (task->tf_out_flags.b.lcyl_hob)
-		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
-	if (task->tf_out_flags.b.hcyl_hob)
-		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
+	ide_hwif_t *hwif	= HWIF(drive);
+	task_struct_t *taskfile	= (task_struct_t *) task->tfRegister;
+	hob_struct_t *hobfile	= (hob_struct_t *) task->hobRegister;
+	u8 HIHI			= (drive->addressing == 1) ? 0xE0 : 0xEF;
 
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+	void debug_taskfile(drive, task);
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
 
-	/* (KS) Send now the standard registers */
-	if (task->tf_out_flags.b.error_feature)
-		OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
-	/* refers to number of sectors to transfer */
-	if (task->tf_out_flags.b.nsector)
-		OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
-	/* refers to sector offset or start sector */
-	if (task->tf_out_flags.b.sector)
-		OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
-	if (task->tf_out_flags.b.lcyl)
-		OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
-	if (task->tf_out_flags.b.hcyl)
-		OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
+	if (IDE_CONTROL_REG) {
+		/* clear nIEN */
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	}
+	SELECT_MASK(drive, 0);
+
+	if (drive->addressing == 1) {
+		hwif->OUTB(hobfile->feature, IDE_FEATURE_REG);
+		hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
+		hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
+		hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);
+		hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);
+	}
+
+	hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);
+	hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
+	hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
+	hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
+	hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
 
-        /*
-	 * (KS) Do not modify the specified taskfile. We want to have a
-	 * universal pass through, so we must execute ALL specified values.
-	 *
-	 * (KS) The drive head register is mandatory.
-	 * Don't care about the out flags !
-	 */
-	OUT_BYTE(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
+	hwif->OUTB((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
 	if (task->handler != NULL) {
-#if 0
-		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
-		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-		/*
-		 * warning check for race between handler and prehandler for
-		 * writing first block of data.  however since we are well
-		 * inside the boundaries of the seek, we should be okay.
-		 */
-		if (task->prehandler != NULL) {
+		ide_set_handler(drive, task->handler, WAIT_WORSTCASE, NULL);
+		hwif->OUTB(taskfile->command, IDE_COMMAND_REG);
+		if (task->prehandler != NULL)
 			return task->prehandler(drive, task->rq);
-		}
-#else
-		ide_startstop_t startstop;
-
-		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
-
-		/*
-		 * (KS) The drive command register is also mandatory.
-		 * Don't care about the out flags !
-		 */
-		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-
-		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
-			printk(KERN_ERR "%s: no DRQ after issuing %s\n",
-				drive->name,
-				drive->mult_count ? "MULTWRITE" : "WRITE");
-			return startstop;
-		}
-		/* (ks/hs): Fixed Multi Write */
-		if ((taskfile->command != WIN_MULTWRITE) &&
-		    (taskfile->command != WIN_MULTWRITE_EXT)) {
-			struct request *rq = HWGROUP(drive)->rq;
-		/* For Write_sectors we need to stuff the first sector */
-			taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
-			rq->current_nr_sectors--;
+		return ide_started;
+	}
+	/* for dma commands we down set the handler */
+#if 0
+	if (blk_fs_request(task->rq) && drive->using_dma) {
+		if (rq_data_dir(task->rq) == READ) {
+			if (hwif->ide_dma_read(drive))
+				return ide_stopped;
 		} else {
-		/* Stuff first sector(s) by implicitly calling the handler */
-			if (!(drive_is_ready(drive))) {
-			/* FIXME: Replace hard-coded 100, error handling? */
-				int i;
-				for (i=0; i<100; i++) {
-					if (drive_is_ready(drive))
-						break;
-				}
-			}
-			return task->handler(drive);
+			if (hwif->ide_dma_write(drive))
+				return ide_stopped;
 		}
-#endif
 	} else {
-		/* for dma commands we down set the handler */
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
-	}
+		if (!drive->using_dma && (task->handler == NULL))
+			return ide_stopped;
 
+		switch(taskfile->command) {
+			case WIN_WRITEDMA_ONCE:
+			case WIN_WRITEDMA:
+			case WIN_WRITEDMA_EXT:
+				hwif->ide_dma_write(drive);
+				break;
+			case WIN_READDMA_ONCE:
+			case WIN_READDMA:
+			case WIN_READDMA_EXT:
+			case WIN_IDENTIFY_DMA:
+				hwif->ide_dma_read(drive);
+				break;
+			default:
+				if (task->handler == NULL)
+					return ide_stopped;
+		}
+	}
 	return ide_started;
-}
+#else
+	switch(taskfile->command) {
+		case WIN_WRITEDMA_ONCE:
+		case WIN_WRITEDMA:
+		case WIN_WRITEDMA_EXT:
+			if (drive->using_dma && !(hwif->ide_dma_write(drive)));
+				return ide_started;
+		case WIN_READDMA_ONCE:
+		case WIN_READDMA:
+		case WIN_READDMA_EXT:
+		case WIN_IDENTIFY_DMA:
+			if (drive->using_dma && !(hwif->ide_dma_read(drive)));
+				return ide_started;
+		default:
+			break;
+	}
+	return ide_stopped;
 #endif
+}
+
+EXPORT_SYMBOL(do_rw_taskfile);
 
-#if 0
 /*
  * Error reporting, in human readable form (luxurious, but a memory hog).
  */
-byte taskfile_dump_status (ide_drive_t *drive, const char *msg, byte stat)
+u8 taskfile_dump_status (ide_drive_t *drive, const char *msg, u8 stat)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long flags;
-	byte err = 0;
+	u8 err = 0;
 
-	__save_flags (flags);	/* local CPU only */
-	ide__sti();		/* local CPU only */
+	local_irq_set(flags);
 	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
 #if FANCY_STATUS_DUMPS
 	printk(" { ");
-	if (stat & BUSY_STAT)
+	if (stat & BUSY_STAT) {
 		printk("Busy ");
-	else {
+	} else {
 		if (stat & READY_STAT)	printk("DriveReady ");
 		if (stat & WRERR_STAT)	printk("DeviceFault ");
 		if (stat & SEEK_STAT)	printk("SeekComplete ");
@@ -452,61 +289,66 @@
 #endif  /* FANCY_STATUS_DUMPS */
 	printk("\n");
 	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
-		err = GET_ERR();
+		err = hwif->INB(IDE_ERROR_REG);
 		printk("%s: %s: error=0x%02x", drive->name, msg, err);
 #if FANCY_STATUS_DUMPS
-		if (drive->media == ide_disk) {
-			printk(" { ");
-			if (err & ABRT_ERR)	printk("DriveStatusError ");
-			if (err & ICRC_ERR)	printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector ");
-			if (err & ECC_ERR)	printk("UncorrectableError ");
-			if (err & ID_ERR)	printk("SectorIdNotFound ");
-			if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
-			if (err & MARK_ERR)	printk("AddrMarkNotFound ");
-			printk("}");
-			if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
-				if ((drive->id->command_set_2 & 0x0400) &&
-				    (drive->id->cfs_enable_2 & 0x0400) &&
-				    (drive->addressing == 1)) {
-					__u64 sectors = 0;
-					u32 low = 0, high = 0;
-					low = task_read_24(drive);
-					OUT_BYTE(0x80, IDE_CONTROL_REG);
-					high = task_read_24(drive);
-					sectors = ((__u64)high << 24) | low;
-					printk(", LBAsect=%lld", sectors);
+		if (drive->media == ide_disk)
+			goto media_out;
+
+		printk(" { ");
+		if (err & ABRT_ERR)	printk("DriveStatusError ");
+		if (err & ICRC_ERR)	printk("Bad%s", (err & ABRT_ERR) ? "CRC " : "Sector ");
+		if (err & ECC_ERR)	printk("UncorrectableError ");
+		if (err & ID_ERR)	printk("SectorIdNotFound ");
+		if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
+		if (err & MARK_ERR)	printk("AddrMarkNotFound ");
+		printk("}");
+		if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR ||
+		    (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+			if (drive->addressing == 1) {
+				u64 sectors = 0;
+				u32 high = 0;
+				u32 low = task_read_24(drive);
+				hwif->OUTB(0x80, IDE_CONTROL_REG);
+				high = task_read_24(drive);
+				sectors = ((u64)high << 24) | low;
+				printk(", LBAsect=%lld", sectors);
+			} else {
+				u8 cur  = hwif->INB(IDE_SELECT_REG);
+				u8 low  = hwif->INB(IDE_LCYL_REG);
+				u8 high = hwif->INB(IDE_HCYL_REG);
+				u8 sect = hwif->INB(IDE_SECTOR_REG);
+				/* using LBA? */
+				if (cur & 0x40) {
+					printk(", LBAsect=%d", (u32)
+						((cur&0xf)<<24)|(high<<16)|
+						(low<<8)|sect);
 				} else {
-					byte cur = IN_BYTE(IDE_SELECT_REG);
-					if (cur & 0x40) {	/* using LBA? */
-						printk(", LBAsect=%ld", (unsigned long)
-						 ((cur&0xf)<<24)
-						 |(IN_BYTE(IDE_HCYL_REG)<<16)
-						 |(IN_BYTE(IDE_LCYL_REG)<<8)
-						 | IN_BYTE(IDE_SECTOR_REG));
-					} else {
-						printk(", CHS=%d/%d/%d",
-						  (IN_BYTE(IDE_HCYL_REG)<<8) +
-						   IN_BYTE(IDE_LCYL_REG),
-						  cur & 0xf,
-						  IN_BYTE(IDE_SECTOR_REG));
-					}
+					printk(", CHS=%d/%d/%d",
+						((high<<8) + low),
+						(cur & 0xf), sect);
 				}
-				if (HWGROUP(drive)->rq)
-					printk(", sector=%llu", (__u64) HWGROUP(drive)->rq->sector);
 			}
+			if (HWGROUP(drive)->rq)
+				printk(", sector=%lu",
+					HWGROUP(drive)->rq->sector);
 		}
+media_out:
 #endif  /* FANCY_STATUS_DUMPS */
 		printk("\n");
 	}
-	__restore_flags (flags);	/* local CPU only */
+	local_irq_restore(flags);
 	return err;
 }
 
+EXPORT_SYMBOL(taskfile_dump_status);
+
 /*
  * Clean up after success/failure of an explicit taskfile operation.
  */
-void ide_end_taskfile (ide_drive_t *drive, byte stat, byte err)
+void ide_end_taskfile (ide_drive_t *drive, u8 stat, u8 err)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long flags;
 	struct request *rq;
 	ide_task_t *args;
@@ -519,28 +361,39 @@
 
 	command = args->tfRegister[IDE_COMMAND_OFFSET];
 
-	rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+	if (rq->errors == 0)
+		rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
 
+	if (args->tf_in_flags.b.data) {
+		u16 data = hwif->INW(IDE_DATA_REG);
+		args->tfRegister[IDE_DATA_OFFSET] = (data) & 0xFF;
+		args->hobRegister[IDE_DATA_OFFSET_HOB]	= (data >> 8) & 0xFF;
+	}
 	args->tfRegister[IDE_ERROR_OFFSET]   = err;
-	args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
-	args->tfRegister[IDE_SECTOR_OFFSET]  = IN_BYTE(IDE_SECTOR_REG);
-	args->tfRegister[IDE_LCYL_OFFSET]    = IN_BYTE(IDE_LCYL_REG);
-	args->tfRegister[IDE_HCYL_OFFSET]    = IN_BYTE(IDE_HCYL_REG);
-	args->tfRegister[IDE_SELECT_OFFSET]  = IN_BYTE(IDE_SELECT_REG);
+	args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG);
+	args->tfRegister[IDE_SECTOR_OFFSET]  = hwif->INB(IDE_SECTOR_REG);
+	args->tfRegister[IDE_LCYL_OFFSET]    = hwif->INB(IDE_LCYL_REG);
+	args->tfRegister[IDE_HCYL_OFFSET]    = hwif->INB(IDE_HCYL_REG);
+	args->tfRegister[IDE_SELECT_OFFSET]  = hwif->INB(IDE_SELECT_REG);
 	args->tfRegister[IDE_STATUS_OFFSET]  = stat;
 	if ((drive->id->command_set_2 & 0x0400) &&
 	    (drive->id->cfs_enable_2 & 0x0400) &&
 	    (drive->addressing == 1)) {
-		OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
-		args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
-		args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
-		args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = IN_BYTE(IDE_SECTOR_REG);
-		args->hobRegister[IDE_LCYL_OFFSET_HOB]    = IN_BYTE(IDE_LCYL_REG);
-		args->hobRegister[IDE_HCYL_OFFSET_HOB]    = IN_BYTE(IDE_HCYL_REG);
+		hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
+		args->hobRegister[IDE_FEATURE_OFFSET_HOB] = hwif->INB(IDE_FEATURE_REG);
+		args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = hwif->INB(IDE_NSECTOR_REG);
+		args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = hwif->INB(IDE_SECTOR_REG);
+		args->hobRegister[IDE_LCYL_OFFSET_HOB]    = hwif->INB(IDE_LCYL_REG);
+		args->hobRegister[IDE_HCYL_OFFSET_HOB]    = hwif->INB(IDE_HCYL_REG);
 	}
 
+#if 0
 /*	taskfile_settings_update(drive, args, command); */
 
+	if (args->posthandler != NULL)
+		args->posthandler(drive, args);
+#endif
+
 	spin_lock_irqsave(&io_request_lock, flags);
 	blkdev_dequeue_request(rq);
 	HWGROUP(drive)->rq = NULL;
@@ -548,6 +401,8 @@
 	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
+EXPORT_SYMBOL(ide_end_taskfile);
+
 /*
  * try_to_flush_leftover_data() is invoked in response to a drive
  * unexpectedly having its DRQ_STAT bit set.  As an alternative to
@@ -565,53 +420,68 @@
 		u32 buffer[16];
 		unsigned int wcount = (i > 16) ? 16 : i;
 		i -= wcount;
-		taskfile_input_data (drive, buffer, wcount);
+		taskfile_input_data(drive, buffer, wcount);
 	}
 }
 
+EXPORT_SYMBOL(task_try_to_flush_leftover_data);
+
 /*
  * taskfile_error() takes action based on the error returned by the drive.
  */
-ide_startstop_t taskfile_error (ide_drive_t *drive, const char *msg, byte stat)
+ide_startstop_t taskfile_error (ide_drive_t *drive, const char *msg, u8 stat)
 {
+	ide_hwif_t *hwif;
 	struct request *rq;
-	byte err;
+	u8 err;
 
         err = taskfile_dump_status(drive, msg, stat);
 	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
 		return ide_stopped;
+
+	hwif = HWIF(drive);
 	/* retry only "normal" I/O: */
 	if (rq->cmd == IDE_DRIVE_TASKFILE) {
 		rq->errors = 1;
 		ide_end_taskfile(drive, stat, err);
 		return ide_stopped;
 	}
-	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
+		/* other bits are useless when BUSY */
 		rq->errors |= ERROR_RESET;
 	} else {
-		if (drive->media == ide_disk && (stat & ERR_STAT)) {
+		if (drive->media != ide_disk)
+			goto media_out;
+		if (stat & ERR_STAT) {
 			/* err has different meaning on cdrom and tape */
 			if (err == ABRT_ERR) {
-				if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
-					return ide_stopped;	/* some newer drives don't support WIN_SPECIFY */
-			} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) {
-				drive->crc_count++;	/* UDMA crc error -- just retry the operation */
-			} else if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */
+				if (drive->select.b.lba &&
+				    (hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY))
+					/* some newer drives don't
+					 * support WIN_SPECIFY
+					 */
+					return ide_stopped;
+			} else if ((err & BAD_CRC) == BAD_CRC) {
+				/* UDMA crc error -- just retry the operation */
+				drive->crc_count++;
+			} else if (err & (BBD_ERR | ECC_ERR)) {
+				/* retries won't help these */
 				rq->errors = ERROR_MAX;
-			else if (err & TRK0_ERR)	/* help it find track zero */
-                                rq->errors |= ERROR_RECAL;
+			} else if (err & TRK0_ERR) {
+				/* help it find track zero */
+				rq->errors |= ERROR_RECAL;
+			}
                 }
-                if ((stat & DRQ_STAT) && rq->cmd != WRITE)
+media_out:
+                if ((stat & DRQ_STAT) && rq_data_dir(rq) != WRITE)
                         task_try_to_flush_leftover_data(drive);
 	}
-	if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
-		OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);	/* force an abort */
-
+	if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) {
+		/* force an abort */
+		hwif->OUTB(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG);
+	}
 	if (rq->errors >= ERROR_MAX) {
-		if (drive->driver != NULL)
-			DRIVER(drive)->end_request(0, HWGROUP(drive));
-		else
-			ide_end_request(0, HWGROUP(drive));
+		DRIVER(drive)->end_request(drive, 0);
 	} else {
 		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
 			++rq->errors;
@@ -623,20 +493,18 @@
 	}
 	return ide_stopped;
 }
-#endif
 
-/*
- * Handler for special commands without a data phase from ide-disk
- */
+EXPORT_SYMBOL(taskfile_error);
 
 /*
  * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
  */
 ide_startstop_t set_multmode_intr (ide_drive_t *drive)
 {
-	byte stat;
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 stat;
 
-	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) {
+	if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {
 		drive->mult_count = drive->mult_req;
 	} else {
 		drive->mult_req = drive->mult_count = 0;
@@ -646,282 +514,373 @@
 	return ide_stopped;
 }
 
+EXPORT_SYMBOL(set_multmode_intr);
+
 /*
  * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
  */
 ide_startstop_t set_geometry_intr (ide_drive_t *drive)
 {
-	byte stat;
+	ide_hwif_t *hwif = HWIF(drive);
+	int retries = 5;
+	u8 stat;
+
+	while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+		udelay(10);
 
-	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT))
+	if (OK_STAT(stat, READY_STAT, BAD_STAT))
 		return ide_stopped;
 
 	if (stat & (ERR_STAT|DRQ_STAT))
-		return ide_error(drive, "set_geometry_intr", stat);
+		return DRIVER(drive)->error(drive, "set_geometry_intr", stat);
 
-	ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL);
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &set_geometry_intr, WAIT_WORSTCASE, NULL);
 	return ide_started;
 }
 
+EXPORT_SYMBOL(set_geometry_intr);
+
 /*
  * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
  */
 ide_startstop_t recal_intr (ide_drive_t *drive)
 {
-	byte stat = GET_STAT();
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 stat;
 
-	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
-		return ide_error(drive, "recal_intr", stat);
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), READY_STAT, BAD_STAT))
+		return DRIVER(drive)->error(drive, "recal_intr", stat);
 	return ide_stopped;
 }
 
+EXPORT_SYMBOL(recal_intr);
+
 /*
  * Handler for commands without a data phase
  */
 ide_startstop_t task_no_data_intr (ide_drive_t *drive)
 {
 	ide_task_t *args	= HWGROUP(drive)->rq->special;
-	byte stat		= GET_STAT();
-
-	ide__sti();	/* local CPU only */
-
-	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
-		return ide_error(drive, "task_no_data_intr", stat); /* calls ide_end_drive_cmd */
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat;
 
+	local_irq_enable();
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {
+		DTF("%s: command opcode 0x%02x\n", drive->name,
+			args->tfRegister[IDE_COMMAND_OFFSET]);
+		return DRIVER(drive)->error(drive, "task_no_data_intr", stat);
+		/* calls ide_end_drive_cmd */
+	}
 	if (args)
-		ide_end_drive_cmd (drive, stat, GET_ERR());
+		ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
 
 	return ide_stopped;
 }
 
+EXPORT_SYMBOL(task_no_data_intr);
+
 /*
- * Handler for command with PIO data-in phase
+ * Handler for command with PIO data-in phase, READ
+ */
+/*
+ * FIXME before 2.4 enable ...
+ *	DATA integrity issue upon error. <andre@linux-ide.org>
  */
 ide_startstop_t task_in_intr (ide_drive_t *drive)
 {
-	byte stat		= GET_STAT();
-	byte io_32bit		= drive->io_32bit;
 	struct request *rq	= HWGROUP(drive)->rq;
+	ide_hwif_t *hwif	= HWIF(drive);
 	char *pBuf		= NULL;
+	u8 stat;
+	unsigned long flags;
 
-	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
-			return ide_error(drive, "task_in_intr", stat);
+#if 0
+			DTF("%s: attempting to recover last " \
+				"sector counter status=0x%02x\n",
+				drive->name, stat);
+			/*
+			 * Expect a BUG BOMB if we attempt to rewind the
+			 * offset in the BH aka PAGE in the current BLOCK
+			 * segment.  This is different than the HOST segment.
+			 */
+#endif
+			if (!rq->bh)
+				rq->current_nr_sectors++;
+			return DRIVER(drive)->error(drive, "task_in_intr", stat);
 		}
 		if (!(stat & BUSY_STAT)) {
 			DTF("task_in_intr to Soon wait for next interrupt\n");
-			ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
+			if (HWGROUP(drive)->handler == NULL)
+				ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
 			return ide_started;  
 		}
 	}
-	DTF("stat: %02x\n", stat);
-	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-	DTF("Read: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
-
-	drive->io_32bit = 0;
-	taskfile_input_data(drive, pBuf, SECTOR_WORDS);
-	drive->io_32bit = io_32bit;
-
-	if (--rq->current_nr_sectors <= 0) {
-		/* (hs): swapped next 2 lines */
-		DTF("Request Ended stat: %02x\n", GET_STAT());
-		ide_end_request(1, HWGROUP(drive));
-	} else {
-		ide_set_handler(drive, &task_in_intr,  WAIT_CMD, NULL);
-		return ide_started;
-	}
-	return ide_stopped;
-}
+#if 0
 
-#undef ALTSTAT_SCREW_UP
+	/*
+	 * Holding point for a brain dump of a thought :-/
+	 */
 
-#ifdef ALTSTAT_SCREW_UP
-/*
- * (ks/hs): Poll Alternate Status Register to ensure
- * that drive is not busy.
- */
-byte altstat_multi_busy (ide_drive_t *drive, byte stat, const char *msg)
-{
-	int i;
+	if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
+		DTF("%s: READ attempting to recover last " \
+			"sector counter status=0x%02x\n",
+			drive->name, stat);
+		rq->current_nr_sectors++;
+		return DRIVER(drive)->error(drive, "task_in_intr", stat);
+        }
+	if (!rq->current_nr_sectors)
+		if (!DRIVER(drive)->end_request(drive, 1))
+			return ide_stopped;
+
+	if (--rq->current_nr_sectors <= 0)
+		if (!DRIVER(drive)->end_request(drive, 1))
+			return ide_stopped;
+#endif
 
-	DTF("multi%s: ASR = %x\n", msg, stat);
-	if (stat & BUSY_STAT) {
-		/* (ks/hs): FIXME: Replace hard-coded 100, error handling? */
-		for (i=0; i<100; i++) {
-			stat = GET_ALTSTAT();
-			if ((stat & BUSY_STAT) == 0)
-				break;
-		}
-	}
+	pBuf = task_map_rq(rq, &flags);
+	DTF("Read: %p, rq->current_nr_sectors: %d, stat: %02x\n",
+		pBuf, (int) rq->current_nr_sectors, stat);
+	taskfile_input_data(drive, pBuf, SECTOR_WORDS);
+	task_unmap_rq(rq, pBuf, &flags);
+	/*
+	 * FIXME :: We really can not legally get a new page/bh
+	 * regardless, if this is the end of our segment.
+	 * BH walking or segment can only be updated after we have a good
+	 * hwif->INB(IDE_STATUS_REG); return.
+	 */
+	if (--rq->current_nr_sectors <= 0)
+		if (!DRIVER(drive)->end_request(drive, 1))
+			return ide_stopped;
 	/*
-	 * (ks/hs): Read Status AFTER Alternate Status Register
+	 * ERM, it is techincally legal to leave/exit here but it makes
+	 * a mess of the code ...
 	 */
-	return(GET_STAT());
+	if (HWGROUP(drive)->handler == NULL)
+		ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
+	return ide_started;
 }
 
-/*
- * (ks/hs): Poll Alternate status register to wait for drive
- * to become ready for next transfer
- */
-byte altstat_multi_poll (ide_drive_t *drive, byte stat, const char *msg)
-{
-	/* (ks/hs): FIXME: Error handling, time-out? */
-	while (stat & BUSY_STAT)
-		stat = GET_ALTSTAT();
-	DTF("multi%s: nsect=1, ASR = %x\n", msg, stat);
-	return(GET_STAT());	/* (ks/hs): Clear pending IRQ */
-}
-#endif /* ALTSTAT_SCREW_UP */
+EXPORT_SYMBOL(task_in_intr);
 
 /*
  * Handler for command with Read Multiple
  */
 ide_startstop_t task_mulin_intr (ide_drive_t *drive)
 {
-	unsigned int		msect, nsect;
-
-#ifdef ALTSTAT_SCREW_UP
-	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "read");
-#else
-	byte stat		= GET_STAT();
-#endif /* ALTSTAT_SCREW_UP */
-
-	byte io_32bit		= drive->io_32bit;
+	ide_hwif_t *hwif	= HWIF(drive);
 	struct request *rq	= HWGROUP(drive)->rq;
 	char *pBuf		= NULL;
+	unsigned int msect	= drive->mult_count;
+	unsigned int nsect;
+	unsigned long flags;
+	u8 stat;
 
-	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
-			return ide_error(drive, "task_mulin_intr", stat);
+			if (!rq->bh) {
+				rq->current_nr_sectors += drive->mult_count;
+				/*
+				 * NOTE: could rewind beyond beginning :-/
+				 */
+			} else {
+				printk("%s: MULTI-READ assume all data " \
+					"transfered is bad status=0x%02x\n",
+					drive->name, stat);
+			}
+			return DRIVER(drive)->error(drive, "task_mulin_intr", stat);
 		}
 		/* no data yet, so wait for another interrupt */
-		ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
+		if (HWGROUP(drive)->handler == NULL)
+			ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL);
 		return ide_started;
 	}
 
-	/* (ks/hs): Fixed Multi-Sector transfer */
-	msect = drive->mult_count;
-
-#ifdef ALTSTAT_SCREW_UP
-	/*
-	 * Screw the request we do not support bad data-phase setups!
-	 * Either read and learn the ATA standard or crash yourself!
-	 */
-	if (!msect) {
+	do {
+		nsect = rq->current_nr_sectors;
+		if (nsect > msect)
+			nsect = msect;
+		pBuf = task_map_rq(rq, &flags);
+		DTF("Multiread: %p, nsect: %d, msect: %d, " \
+			" rq->current_nr_sectors: %d\n",
+			pBuf, nsect, msect, rq->current_nr_sectors);
+		taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+		task_unmap_rq(rq, pBuf, &flags);
+		rq->errors = 0;
+		rq->current_nr_sectors -= nsect;
+		msect -= nsect;
 		/*
-		 * (ks/hs): Drive supports multi-sector transfer,
-		 * drive->mult_count was not set
+		 * FIXME :: We really can not legally get a new page/bh
+		 * regardless, if this is the end of our segment.
+		 * BH walking or segment can only be updated after we have a
+		 * good hwif->INB(IDE_STATUS_REG); return.
 		 */
-		nsect = 1;
-		while (rq->current_nr_sectors) {
-			pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-			DTF("Multiread: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
-			drive->io_32bit = 0;
-			taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
-			drive->io_32bit = io_32bit;
-			rq->errors = 0;
-			rq->current_nr_sectors -= nsect;
-			stat = altstat_multi_poll(drive, GET_ALTSTAT(), "read");
-		}
-		ide_end_request(1, HWGROUP(drive));
-		return ide_stopped;
-	}
-#endif /* ALTSTAT_SCREW_UP */
+		if (!rq->current_nr_sectors) {
+			if (!DRIVER(drive)->end_request(drive, 1))
+				return ide_stopped;
+		}
+	} while (msect);
+	if (HWGROUP(drive)->handler == NULL)
+		ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL);
+	return ide_started;
+}
 
-	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
-	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-
-	DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
-		pBuf, nsect, rq->current_nr_sectors);
-	drive->io_32bit = 0;
-	taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
-	drive->io_32bit = io_32bit;
-	rq->errors = 0;
-	rq->current_nr_sectors -= nsect;
-	if (rq->current_nr_sectors != 0) {
-		ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
-		return ide_started;
-	}
-	ide_end_request(1, HWGROUP(drive));
-	return ide_stopped;
-}
+EXPORT_SYMBOL(task_mulin_intr);
 
+/*
+ * VERIFY ME before 2.4 ... unexpected race is possible based on details
+ * RMK with 74LS245/373/374 TTL buffer logic because of passthrough.
+ */
 ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
 {
-	ide_task_t *args = rq->special;
+	char *pBuf		= NULL;
+	unsigned long flags;
 	ide_startstop_t startstop;
 
-	if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
-		printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name, drive->mult_count ? "MULTWRITE" : "WRITE");
+	if (ide_wait_stat(&startstop, drive, DATA_READY,
+			drive->bad_wstat, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: no DRQ after issuing WRITE%s\n",
+			drive->name,
+			drive->addressing ? "_EXT" : "");
 		return startstop;
 	}
-
-	/* (ks/hs): Fixed Multi Write */
-	if ((args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE) &&
-	    (args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE_EXT)) {
-		/* For Write_sectors we need to stuff the first sector */
-		taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
-		rq->current_nr_sectors--;
-		return ide_started;
-	} else {
-		/*
-		 * (ks/hs): Stuff the first sector(s)
-		 * by implicitly calling the handler
-		 */
-		if (!(drive_is_ready(drive))) {
-			int i;
-			/*
-			 * (ks/hs): FIXME: Replace hard-coded
-			 *               100, error handling?
-			 */
-			for (i=0; i<100; i++) {
-				if (drive_is_ready(drive))
-					break;
-			}
-		}
-		return args->handler(drive);
-	}
+	/* For Write_sectors we need to stuff the first sector */
+	pBuf = task_map_rq(rq, &flags);
+	taskfile_output_data(drive, pBuf, SECTOR_WORDS);
+	rq->current_nr_sectors--;
+	task_unmap_rq(rq, pBuf, &flags);
 	return ide_started;
 }
 
+EXPORT_SYMBOL(pre_task_out_intr);
+
 /*
- * Handler for command with PIO data-out phase
+ * Handler for command with PIO data-out phase WRITE
+ *
+ * WOOHOO this is a CORRECT STATE DIAGRAM NOW, <andre@linux-ide.org>
  */
 ide_startstop_t task_out_intr (ide_drive_t *drive)
 {
-	byte stat		= GET_STAT();
-	byte io_32bit		= drive->io_32bit;
+	ide_hwif_t *hwif	= HWIF(drive);
 	struct request *rq	= HWGROUP(drive)->rq;
 	char *pBuf		= NULL;
+	unsigned long flags;
+	u8 stat;
 
-	if (!rq->current_nr_sectors) { 
-		ide_end_request(1, HWGROUP(drive));
-		return ide_stopped;
-	}
-
-	if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
-		return ide_error(drive, "task_out_intr", stat);
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), DRIVE_READY, drive->bad_wstat)) {
+		DTF("%s: WRITE attempting to recover last " \
+			"sector counter status=0x%02x\n",
+			drive->name, stat);
+		rq->current_nr_sectors++;
+		return DRIVER(drive)->error(drive, "task_out_intr", stat);
 	}
+	/*
+	 * Safe to update request for partial completions.
+	 * We have a good STATUS CHECK!!!
+	 */
+	if (!rq->current_nr_sectors)
+		if (!DRIVER(drive)->end_request(drive, 1))
+			return ide_stopped;
 	if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) {
 		rq = HWGROUP(drive)->rq;
-		pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-		DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
-		drive->io_32bit = 0;
+		pBuf = task_map_rq(rq, &flags);
+		DTF("write: %p, rq->current_nr_sectors: %d\n",
+			pBuf, (int) rq->current_nr_sectors);
 		taskfile_output_data(drive, pBuf, SECTOR_WORDS);
-		drive->io_32bit = io_32bit;
+		task_unmap_rq(rq, pBuf, &flags);
 		rq->errors = 0;
 		rq->current_nr_sectors--;
 	}
+	if (HWGROUP(drive)->handler == NULL)
+		ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);
+	return ide_started;
+}
 
-	if (rq->current_nr_sectors <= 0) {
-		ide_end_request(1, HWGROUP(drive));
-	} else {
-		ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
-		return ide_started;
+EXPORT_SYMBOL(task_out_intr);
+
+#undef ALTERNATE_STATE_DIAGRAM_MULTI_OUT
+
+ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq)
+{
+#ifdef ALTERNATE_STATE_DIAGRAM_MULTI_OUT
+	ide_hwif_t *hwif		= HWIF(drive);
+	char *pBuf			= NULL;
+	unsigned int nsect = 0, msect	= drive->mult_count;
+        u8 stat;
+	unsigned long flags;
+#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */
+
+	ide_task_t *args = rq->special;
+	ide_startstop_t startstop;
+
+#if 0
+	/*
+	 * assign private copy for multi-write
+	 */
+	memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request));
+#endif
+
+	if (ide_wait_stat(&startstop, drive, DATA_READY,
+			drive->bad_wstat, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: no DRQ after issuing %s\n",
+			drive->name,
+			drive->addressing ? "MULTWRITE_EXT" : "MULTWRITE");
+		return startstop;
 	}
-	return ide_stopped;
+#ifdef ALTERNATE_STATE_DIAGRAM_MULTI_OUT
+
+	do {
+		nsect = rq->current_nr_sectors;
+		if (nsect > msect)
+			nsect = msect;
+		pBuf = task_map_rq(rq, &flags);
+		DTF("Pre-Multiwrite: %p, nsect: %d, msect: %d, " \
+			"rq->current_nr_sectors: %ld\n",
+			pBuf, nsect, msect, rq->current_nr_sectors);
+		msect -= nsect;
+		taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+		task_unmap_rq(rq, pBuf, &flags);
+		rq->current_nr_sectors -= nsect;
+		if (!rq->current_nr_sectors) {
+			if (!DRIVER(drive)->end_request(drive, 1))
+				if (!rq->bh) {
+					stat = hwif->INB(IDE_STATUS_REG);
+					return ide_stopped;
+				}
+		}
+	} while (msect);
+	rq->errors = 0;
+	return ide_started;
+#else /* ! ALTERNATE_STATE_DIAGRAM_MULTI_OUT */
+
+#if 0
+	if (wait_for_ready(drive, 100))
+		IDE_DEBUG(__LINE__);		//BUG();
+#else
+	if (!(drive_is_ready(drive))) {
+		int i;
+		for (i=0; i<100; i++) {
+			if (drive_is_ready(drive))
+				break;
+		}
+	}
+#endif
+	/*
+	 * WARNING :: if the drive as not acked good status we may not
+	 * move the DATA-TRANSFER T-Bar as BSY != 0. <andre@linux-ide.org>
+	 */
+	return args->handler(drive);
+#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */
 }
 
+EXPORT_SYMBOL(pre_task_mulout_intr);
+
+/*
+ * FIXME before enabling in 2.4 ... DATA integrity issue upon error.
+ */
 /*
  * Handler for command write multiple
  * Called directly from execute_drive_cmd for the first bunch of sectors,
@@ -929,93 +888,119 @@
  */
 ide_startstop_t task_mulout_intr (ide_drive_t *drive)
 {
-	unsigned int		msect, nsect;
-
-#ifdef ALTSTAT_SCREW_UP
-	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "write");
-#else
-	byte stat		= GET_STAT();
-#endif /* ALTSTAT_SCREW_UP */
-
-	byte io_32bit		= drive->io_32bit;
-	struct request *rq	= HWGROUP(drive)->rq;
-	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
-	char *pBuf		= NULL;
+	ide_hwif_t *hwif		= HWIF(drive);
+	u8 stat				= hwif->INB(IDE_STATUS_REG);
+	struct request *rq		= HWGROUP(drive)->rq;
+	char *pBuf			= NULL;
+	ide_startstop_t startstop	= ide_stopped;
+	unsigned int msect		= drive->mult_count;
+	unsigned int nsect;
+	unsigned long flags;
 
 	/*
 	 * (ks/hs): Handle last IRQ on multi-sector transfer,
-	 * occurs after all data was sent
+	 * occurs after all data was sent in this chunk
 	 */
 	if (rq->current_nr_sectors == 0) {
-		if (stat & (ERR_STAT|DRQ_STAT))
-			return ide_error(drive, "task_mulout_intr", stat);
-		ide_end_request(1, HWGROUP(drive));
-		return ide_stopped;
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			if (!rq->bh) {
+                                rq->current_nr_sectors += drive->mult_count;
+				/*
+				 * NOTE: could rewind beyond beginning :-/
+				 */
+			} else {
+				printk("%s: MULTI-WRITE assume all data " \
+					"transfered is bad status=0x%02x\n",
+					drive->name, stat);
+			}
+			return DRIVER(drive)->error(drive, "task_mulout_intr", stat);
+		}
+		if (!rq->bh)
+			DRIVER(drive)->end_request(drive, 1);
+		return startstop;
 	}
-
+	/*
+	 * DON'T be lazy code the above and below togather !!!
+	 */
 	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
-			return ide_error(drive, "task_mulout_intr", stat);
+			if (!rq->bh) {
+				rq->current_nr_sectors += drive->mult_count;
+				/*
+				 * NOTE: could rewind beyond beginning :-/
+				 */
+			} else {
+				printk("%s: MULTI-WRITE assume all data " \
+					"transfered is bad status=0x%02x\n",
+					drive->name, stat);
+			}
+			return DRIVER(drive)->error(drive, "task_mulout_intr", stat);
 		}
 		/* no data yet, so wait for another interrupt */
-		if (hwgroup->handler == NULL)
-			ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+		if (HWGROUP(drive)->handler == NULL)
+			ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL);
 		return ide_started;
 	}
 
-	/* (ks/hs): See task_mulin_intr */
-	msect = drive->mult_count;
-
-#ifdef ALTSTAT_SCREW_UP
-	/*
-	 * Screw the request we do not support bad data-phase setups!
-	 * Either read and learn the ATA standard or crash yourself!
-	 */
-	if (!msect) {
-		nsect = 1;
-		while (rq->current_nr_sectors) {
-			pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-			DTF("Multiwrite: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
-			drive->io_32bit = 0;
-			taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
-			drive->io_32bit = io_32bit;
-			rq->errors = 0;
-			rq->current_nr_sectors -= nsect;
-			stat = altstat_multi_poll(drive, GET_ALTSTAT(), "write");
+#ifndef ALTERNATE_STATE_DIAGRAM_MULTI_OUT
+	if (HWGROUP(drive)->handler != NULL) {
+		unsigned long lflags;
+		spin_lock_irqsave(&io_request_lock, lflags);
+		HWGROUP(drive)->handler = NULL;
+		del_timer(&HWGROUP(drive)->timer);
+		spin_unlock_irqrestore(&io_request_lock, lflags);
+	}
+#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */
+
+	do {
+		nsect = rq->current_nr_sectors;
+		if (nsect > msect)
+			nsect = msect;
+		pBuf = task_map_rq(rq, &flags);
+		DTF("Multiwrite: %p, nsect: %d, msect: %d, " \
+			"rq->current_nr_sectors: %ld\n",
+			pBuf, nsect, msect, rq->current_nr_sectors);
+		msect -= nsect;
+		taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+		task_unmap_rq(rq, pBuf, &flags);
+		rq->current_nr_sectors -= nsect;
+		/*
+		 * FIXME :: We really can not legally get a new page/bh
+		 * regardless, if this is the end of our segment.
+		 * BH walking or segment can only be updated after we
+		 * have a good  hwif->INB(IDE_STATUS_REG); return.
+		 */
+		if (!rq->current_nr_sectors) {
+			if (!DRIVER(drive)->end_request(drive, 1))
+				if (!rq->bh)
+					return ide_stopped;
 		}
-		ide_end_request(1, HWGROUP(drive));
-		return ide_stopped;
-	}
-#endif /* ALTSTAT_SCREW_UP */
-
-	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
-	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
-		pBuf, nsect, rq->current_nr_sectors);
-	drive->io_32bit = 0;
-	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
-	drive->io_32bit = io_32bit;
+	} while (msect);
 	rq->errors = 0;
-	rq->current_nr_sectors -= nsect;
-	if (hwgroup->handler == NULL)
-		ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+	if (HWGROUP(drive)->handler == NULL)
+		ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL);
 	return ide_started;
 }
 
+EXPORT_SYMBOL(task_mulout_intr);
+
 /* Called by internal to feature out type of command being called */
+//ide_pre_handler_t * ide_pre_handler_parser (task_struct_t *taskfile, hob_struct_t *hobfile)
 ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
 {
 	switch(taskfile->command) {
 				/* IDE_DRIVE_TASK_RAW_WRITE */
 		case CFA_WRITE_MULTI_WO_ERASE:
+	//	case WIN_WRITE_LONG:
+	//	case WIN_WRITE_LONG_ONCE:
 		case WIN_MULTWRITE:
 		case WIN_MULTWRITE_EXT:
-//		case WIN_WRITEDMA:
-//		case WIN_WRITEDMA_QUEUED:
-//		case WIN_WRITEDMA_EXT:
-//		case WIN_WRITEDMA_QUEUED_EXT:
+			return &pre_task_mulout_intr;
+			
 				/* IDE_DRIVE_TASK_OUT */
 		case WIN_WRITE:
+	//	case WIN_WRITE_ONCE:
+		case WIN_WRITE_EXT:
 		case WIN_WRITE_VERIFY:
 		case WIN_WRITE_BUFFER:
 		case CFA_WRITE_SECT_WO_ERASE:
@@ -1025,13 +1010,22 @@
 		case WIN_SMART:
 			if (taskfile->feature == SMART_WRITE_LOG_SECTOR)
 				return &pre_task_out_intr;
+		case WIN_WRITEDMA:
+	//	case WIN_WRITEDMA_ONCE:
+		case WIN_WRITEDMA_QUEUED:
+		case WIN_WRITEDMA_EXT:
+		case WIN_WRITEDMA_QUEUED_EXT:
+				/* IDE_DRIVE_TASK_OUT */
 		default:
 			break;
 	}
 	return(NULL);
 }
 
+EXPORT_SYMBOL(ide_pre_handler_parser);
+
 /* Called by internal to feature out type of command being called */
+//ide_handler_t * ide_handler_parser (task_struct_t *taskfile, hob_struct_t *hobfile)
 ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
 {
 	switch(taskfile->command) {
@@ -1040,6 +1034,7 @@
 		case CFA_TRANSLATE_SECTOR:
 		case WIN_READ_BUFFER:
 		case WIN_READ:
+	//	case WIN_READ_ONCE:
 		case WIN_READ_EXT:
 			return &task_in_intr;
 		case WIN_SECURITY_DISABLE:
@@ -1051,11 +1046,16 @@
 		case WIN_WRITE_BUFFER:
 		case WIN_WRITE_VERIFY:
 		case WIN_WRITE:
+	//	case WIN_WRITE_ONCE:	
 		case WIN_WRITE_EXT:
 			return &task_out_intr;
+	//	case WIN_READ_LONG:
+	//	case WIN_READ_LONG_ONCE:
 		case WIN_MULTREAD:
 		case WIN_MULTREAD_EXT:
 			return &task_mulin_intr;
+	//	case WIN_WRITE_LONG:
+	//	case WIN_WRITE_LONG_ONCE:
 		case CFA_WRITE_MULTI_WO_ERASE:
 		case WIN_MULTWRITE:
 		case WIN_MULTWRITE_EXT:
@@ -1074,13 +1074,16 @@
 		case CFA_REQ_EXT_ERROR_CODE:
 		case CFA_ERASE_SECTORS:
 		case WIN_VERIFY:
+	//	case WIN_VERIFY_ONCE:
 		case WIN_VERIFY_EXT:
 		case WIN_SEEK:
 			return &task_no_data_intr;
 		case WIN_SPECIFY:
 			return &set_geometry_intr;
-		case WIN_RESTORE:
+		case WIN_RECAL:
+	//	case WIN_RESTORE:
 			return &recal_intr;
+		case WIN_NOP:
 		case WIN_DIAGNOSE:
 		case WIN_FLUSH_CACHE:
 		case WIN_FLUSH_CACHE_EXT:
@@ -1111,11 +1114,13 @@
 			return &task_no_data_intr;
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		case WIN_READDMA:
+	//	case WIN_READDMA_ONCE:
 		case WIN_IDENTIFY_DMA:
 		case WIN_READDMA_QUEUED:
 		case WIN_READDMA_EXT:
 		case WIN_READDMA_QUEUED_EXT:
 		case WIN_WRITEDMA:
+	//	case WIN_WRITEDMA_ONCE:
 		case WIN_WRITEDMA_QUEUED:
 		case WIN_WRITEDMA_EXT:
 		case WIN_WRITEDMA_QUEUED_EXT:
@@ -1130,14 +1135,31 @@
 	}	
 }
 
+EXPORT_SYMBOL(ide_handler_parser);
+
+ide_post_handler_t * ide_post_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
+{
+	switch(taskfile->command) {
+		case WIN_SPECIFY:	/* set_geometry_intr */
+		case WIN_RESTORE:	/* recal_intr */
+		case WIN_SETMULT:	/* set_multmode_intr */
+		default:
+			return(NULL);
+	}
+}
+
+EXPORT_SYMBOL(ide_post_handler_parser);
+
 /* Called by ioctl to feature out type of command being called */
 int ide_cmd_type_parser (ide_task_t *args)
 {
-	struct hd_drive_task_hdr *taskfile = (struct hd_drive_task_hdr *) args->tfRegister;
-	struct hd_drive_hob_hdr *hobfile = (struct hd_drive_hob_hdr *) args->hobRegister;
 
-	args->prehandler = ide_pre_handler_parser(taskfile, hobfile);
-	args->handler = ide_handler_parser(taskfile, hobfile);
+	task_struct_t *taskfile = (task_struct_t *) args->tfRegister;
+	hob_struct_t *hobfile   = (hob_struct_t *) args->hobRegister;
+
+	args->prehandler	= ide_pre_handler_parser(taskfile, hobfile);
+	args->handler		= ide_handler_parser(taskfile, hobfile);
+	args->posthandler	= ide_post_handler_parser(taskfile, hobfile);
 
 	switch(args->tfRegister[IDE_COMMAND_OFFSET]) {
 		case WIN_IDENTIFY:
@@ -1145,18 +1167,28 @@
 			return IDE_DRIVE_TASK_IN;
 		case CFA_TRANSLATE_SECTOR:
 		case WIN_READ:
+	//	case WIN_READ_ONCE:
+		case WIN_READ_EXT:
 		case WIN_READ_BUFFER:
 			return IDE_DRIVE_TASK_IN;
 		case WIN_WRITE:
+	//	case WIN_WRITE_ONCE:
+		case WIN_WRITE_EXT:
 		case WIN_WRITE_VERIFY:
 		case WIN_WRITE_BUFFER:
 		case CFA_WRITE_SECT_WO_ERASE:
 		case WIN_DOWNLOAD_MICROCODE:
 			return IDE_DRIVE_TASK_RAW_WRITE;
+	//	case WIN_READ_LONG:
+	//	case WIN_READ_LONG_ONCE:
 		case WIN_MULTREAD:
+		case WIN_MULTREAD_EXT:
 			return IDE_DRIVE_TASK_IN;
+	//	case WIN_WRITE_LONG:
+	//	case WIN_WRITE_LONG_ONCE:
 		case CFA_WRITE_MULTI_WO_ERASE:
 		case WIN_MULTWRITE:
+		case WIN_MULTWRITE_EXT:
 			return IDE_DRIVE_TASK_RAW_WRITE;
 		case WIN_SECURITY_DISABLE:
 		case WIN_SECURITY_ERASE_UNIT:
@@ -1178,12 +1210,14 @@
 			}
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		case WIN_READDMA:
+	//	case WIN_READDMA_ONCE:
 		case WIN_IDENTIFY_DMA:
 		case WIN_READDMA_QUEUED:
 		case WIN_READDMA_EXT:
 		case WIN_READDMA_QUEUED_EXT:
 			return IDE_DRIVE_TASK_IN;
 		case WIN_WRITEDMA:
+	//	case WIN_WRITEDMA_ONCE:
 		case WIN_WRITEDMA_QUEUED:
 		case WIN_WRITEDMA_EXT:
 		case WIN_WRITEDMA_QUEUED_EXT:
@@ -1191,20 +1225,32 @@
 #endif
 		case WIN_SETFEATURES:
 			switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
+				case SETFEATURES_EN_8BIT:
+				case SETFEATURES_EN_WCACHE:
+					return IDE_DRIVE_TASK_NO_DATA;
 				case SETFEATURES_XFER:
 					return IDE_DRIVE_TASK_SET_XFER;
 				case SETFEATURES_DIS_DEFECT:
 				case SETFEATURES_EN_APM:
 				case SETFEATURES_DIS_MSN:
+				case SETFEATURES_DIS_RETRY:
+				case SETFEATURES_EN_AAM:
+				case SETFEATURES_RW_LONG:
+				case SETFEATURES_SET_CACHE:
+				case SETFEATURES_DIS_RLA:
 				case SETFEATURES_EN_RI:
 				case SETFEATURES_EN_SI:
 				case SETFEATURES_DIS_RPOD:
 				case SETFEATURES_DIS_WCACHE:
 				case SETFEATURES_EN_DEFECT:
 				case SETFEATURES_DIS_APM:
+				case SETFEATURES_EN_ECC:
 				case SETFEATURES_EN_MSN:
+				case SETFEATURES_EN_RETRY:
 				case SETFEATURES_EN_RLA:
 				case SETFEATURES_PREFETCH:
+				case SETFEATURES_4B_RW_LONG:
+				case SETFEATURES_DIS_AAM:
 				case SETFEATURES_EN_RPOD:
 				case SETFEATURES_DIS_RI:
 				case SETFEATURES_DIS_SI:
@@ -1215,6 +1261,7 @@
 		case CFA_REQ_EXT_ERROR_CODE:
 		case CFA_ERASE_SECTORS:
 		case WIN_VERIFY:
+	//	case WIN_VERIFY_ONCE:
 		case WIN_VERIFY_EXT:
 		case WIN_SEEK:
 		case WIN_SPECIFY:
@@ -1253,6 +1300,8 @@
 	}
 }
 
+EXPORT_SYMBOL(ide_cmd_type_parser);
+
 /*
  * This function is intended to be used prior to invoking ide_do_drive_cmd().
  */
@@ -1262,127 +1311,158 @@
 	rq->cmd = IDE_DRIVE_TASK_NO_DATA;
 }
 
-/*
- * This is kept for internal use only !!!
- * This is an internal call and nobody in user-space has a damn
- * reason to call this taskfile.
- *
- * ide_raw_taskfile is the one that user-space executes.
- */
-int ide_wait_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf)
-{
-	struct request rq;
-	ide_task_t args;
+EXPORT_SYMBOL(ide_init_drive_taskfile);
 
-	memset(&args, 0, sizeof(ide_task_t));
+#if 1
 
-	args.tfRegister[IDE_DATA_OFFSET]         = taskfile->data;
-	args.tfRegister[IDE_FEATURE_OFFSET]      = taskfile->feature;
-	args.tfRegister[IDE_NSECTOR_OFFSET]      = taskfile->sector_count;
-	args.tfRegister[IDE_SECTOR_OFFSET]       = taskfile->sector_number;
-	args.tfRegister[IDE_LCYL_OFFSET]         = taskfile->low_cylinder;
-	args.tfRegister[IDE_HCYL_OFFSET]         = taskfile->high_cylinder;
-	args.tfRegister[IDE_SELECT_OFFSET]       = taskfile->device_head;
-	args.tfRegister[IDE_COMMAND_OFFSET]      = taskfile->command;
-
-	args.hobRegister[IDE_DATA_OFFSET_HOB]    = hobfile->data;
-	args.hobRegister[IDE_FEATURE_OFFSET_HOB] = hobfile->feature;
-	args.hobRegister[IDE_NSECTOR_OFFSET_HOB] = hobfile->sector_count;
-	args.hobRegister[IDE_SECTOR_OFFSET_HOB]  = hobfile->sector_number;
-	args.hobRegister[IDE_LCYL_OFFSET_HOB]    = hobfile->low_cylinder;
-	args.hobRegister[IDE_HCYL_OFFSET_HOB]    = hobfile->high_cylinder;
-	args.hobRegister[IDE_SELECT_OFFSET_HOB]  = hobfile->device_head;
-	args.hobRegister[IDE_CONTROL_OFFSET_HOB] = hobfile->control;
+int ide_diag_taskfile (ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf)
+{
+	struct request rq;
 
 	ide_init_drive_taskfile(&rq);
-	/* This is kept for internal use only !!! */
-	args.command_type = ide_cmd_type_parser (&args);
-	if (args.command_type != IDE_DRIVE_TASK_NO_DATA)
-		rq.current_nr_sectors = rq.nr_sectors = (hobfile->sector_count << 8) | taskfile->sector_count;
-
 	rq.cmd = IDE_DRIVE_TASKFILE;
 	rq.buffer = buf;
-	rq.special = &args;
+
+	/*
+	 * (ks) We transfer currently only whole sectors.
+	 * This is suffient for now.  But, it would be great,
+	 * if we would find a solution to transfer any size.
+	 * To support special commands like READ LONG.
+	 */
+	if (args->command_type != IDE_DRIVE_TASK_NO_DATA) {
+		if (data_size == 0)
+			rq.current_nr_sectors = rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
+		/*	rq.hard_cur_sectors	*/
+		else
+			rq.current_nr_sectors = rq.nr_sectors = data_size / SECTOR_SIZE;
+		/*	rq.hard_cur_sectors	*/
+	}
+
+	if (args->tf_out_flags.all == 0) {
+		/*
+		 * clean up kernel settings for driver sanity, regardless.
+		 * except for discrete diag services.
+		 */
+		args->posthandler = ide_post_handler_parser(
+				(struct hd_drive_task_hdr *) args->tfRegister,
+				(struct hd_drive_hob_hdr *) args->hobRegister);
+
+	}
+	rq.special = args;
 	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
-int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, byte *buf)
+#else
+
+int ide_diag_taskfile (ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf)
 {
-	struct request rq;
-	ide_init_drive_taskfile(&rq);
-	rq.cmd = IDE_DRIVE_TASKFILE;
-	rq.buffer = buf;
+	struct request *rq;
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	unsigned int major = HWIF(drive)->major;
+	struct list_head *queue_head = &drive->queue.queue_head;
+	DECLARE_COMPLETION(wait);
 
-	if (args->command_type != IDE_DRIVE_TASK_NO_DATA)
-		rq.current_nr_sectors = rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
+	if (HWIF(drive)->chipset == ide_pdc4030 && buf != NULL)
+		return -ENOSYS; /* special drive cmds not supported */
 
-	rq.special = args;
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
+	memset(rq, 0, sizeof(*rq));
+	rq->cmd = IDE_DRIVE_TASKFILE;
+	rq->buffer = buf;
+
+	/*
+	 * (ks) We transfer currently only whole sectors.
+	 * This is suffient for now.  But, it would be great,
+	 * if we would find a solution to transfer any size.
+	 * To support special commands like READ LONG.
+	 */
+	if (args->command_type != IDE_DRIVE_TASK_NO_DATA) {
+		if (data_size == 0) {
+			ata_nsector_t nsector;
+			nsector.b.low = args->hobRegister[IDE_NSECTOR_OFFSET_HOB];
+			nsector.b.high = args->tfRegister[IDE_NSECTOR_OFFSET];
+			rq.nr_sectors = nsector.all;
+		} else {
+			rq.nr_sectors = data_size / SECTOR_SIZE;
+		}
+		rq.current_nr_sectors = rq.nr_sectors;
+	//	rq.hard_cur_sectors = rq.nr_sectors;
+	}
+
+	if (args->tf_out_flags.all == 0) {
+		/*
+		 * clean up kernel settings for driver sanity, regardless.
+		 * except for discrete diag services.
+		 */
+		args->posthandler = ide_post_handler_parser(
+				(struct hd_drive_task_hdr *) args->tfRegister,
+				(struct hd_drive_hob_hdr *) args->hobRegister);
+	}
+	rq->special = args;
+	rq->errors = 0;
+	rq->rq_status = RQ_ACTIVE;
+	rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);
+	rq->waiting = &wait;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	queue_head = queue_head->prev;
+	list_add(&rq->queue, queue_head);
+	ide_do_request(hwgroup, 0);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	wait_for_completion(&wait);	/* wait for it to be serviced */
+	return rq->errors ? -EIO : 0;	/* return -EIO if errors */
 }
 
+#endif
+
+EXPORT_SYMBOL(ide_diag_taskfile);
 
+int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, u8 *buf)
+{
+	return ide_diag_taskfile(drive, args, 0, buf);
+}
+
+EXPORT_SYMBOL(ide_raw_taskfile);
+	
 #ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
 char * ide_ioctl_verbose (unsigned int cmd)
 {
 	return("unknown");
 }
 
-char * ide_task_cmd_verbose (byte task)
+char * ide_task_cmd_verbose (u8 task)
 {
 	return("unknown");
 }
 #endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
 
-/*
- *  The taskfile glue table
- *
- *  reqtask.data_phase	reqtask.req_cmd
- *  			args.command_type		args.handler
- *
- *  TASKFILE_P_OUT_DMAQ	??				??
- *  TASKFILE_P_IN_DMAQ	??				??
- *  TASKFILE_P_OUT_DMA	??				??
- *  TASKFILE_P_IN_DMA	??				??
- *  TASKFILE_P_OUT	??				??
- *  TASKFILE_P_IN	??				??
- *
- *  TASKFILE_OUT_DMAQ	IDE_DRIVE_TASK_RAW_WRITE	NULL
- *  TASKFILE_IN_DMAQ	IDE_DRIVE_TASK_IN		NULL
- *
- *  TASKFILE_OUT_DMA	IDE_DRIVE_TASK_RAW_WRITE	NULL
- *  TASKFILE_IN_DMA	IDE_DRIVE_TASK_IN		NULL
- *
- *  TASKFILE_IN_OUT	??				??
- *
- *  TASKFILE_MULTI_OUT	IDE_DRIVE_TASK_RAW_WRITE	task_mulout_intr
- *  TASKFILE_MULTI_IN	IDE_DRIVE_TASK_IN		task_mulin_intr
- *
- *  TASKFILE_OUT	IDE_DRIVE_TASK_RAW_WRITE	task_out_intr
- *  TASKFILE_OUT	IDE_DRIVE_TASK_OUT		task_out_intr
- *
- *  TASKFILE_IN		IDE_DRIVE_TASK_IN		task_in_intr
- *  TASKFILE_NO_DATA	IDE_DRIVE_TASK_NO_DATA		task_no_data_intr
- *
- *  			IDE_DRIVE_TASK_SET_XFER		task_no_data_intr
- *  			IDE_DRIVE_TASK_INVALID
- *
- */
-
 #define MAX_DMA		(256*SECTOR_WORDS)
 
+ide_startstop_t flagged_taskfile(ide_drive_t *, ide_task_t *);
+ide_startstop_t flagged_task_no_data_intr(ide_drive_t *);
+ide_startstop_t flagged_task_in_intr(ide_drive_t *);
+ide_startstop_t flagged_task_mulin_intr(ide_drive_t *);
+ide_startstop_t flagged_pre_task_out_intr(ide_drive_t *, struct request *);
+ide_startstop_t flagged_task_out_intr(ide_drive_t *);
+ide_startstop_t flagged_pre_task_mulout_intr(ide_drive_t *, struct request *);
+ide_startstop_t flagged_task_mulout_intr(ide_drive_t *);
+
 int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	ide_task_request_t	*req_task;
 	ide_task_t		args;
-
-	byte *outbuf		= NULL;
-	byte *inbuf		= NULL;
+	u8 *outbuf		= NULL;
+	u8 *inbuf		= NULL;
 	task_ioreg_t *argsptr	= args.tfRegister;
 	task_ioreg_t *hobsptr	= args.hobRegister;
 	int err			= 0;
 	int tasksize		= sizeof(struct ide_task_request_s);
 	int taskin		= 0;
 	int taskout		= 0;
+	u8 io_32bit		= drive->io_32bit;
+
+//	printk("IDE Taskfile ...\n");
 
 	req_task = kmalloc(tasksize, GFP_KERNEL);
 	if (req_task == NULL) return -ENOMEM;
@@ -1423,8 +1503,7 @@
 		}
 	}
 
-	memset(argsptr, 0, HDIO_DRIVE_TASK_HDR_SIZE);
-	memset(hobsptr, 0, HDIO_DRIVE_HOB_HDR_SIZE);
+	memset(&args, 0, sizeof(ide_task_t));
 	memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
 	memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE);
 
@@ -1440,64 +1519,61 @@
 		ide_task_cmd_verbose(args.tfRegister[IDE_COMMAND_OFFSET]));
 #endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
 
+	drive->io_32bit = 0;
 	switch(req_task->data_phase) {
 		case TASKFILE_OUT_DMAQ:
 		case TASKFILE_OUT_DMA:
-			args.prehandler = NULL;
-			args.handler = NULL;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, outbuf);
+			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
 			break;
 		case TASKFILE_IN_DMAQ:
 		case TASKFILE_IN_DMA:
-			args.prehandler = NULL;
-			args.handler = NULL;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, inbuf);
+			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
 			break;
 		case TASKFILE_IN_OUT:
 #if 0
 			args.prehandler = &pre_task_out_intr;
 			args.handler = &task_out_intr;
 			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, outbuf);
+			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
 			args.prehandler = NULL;
 			args.handler = &task_in_intr;
 			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, inbuf);
+			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
 			break;
 #else
 			err = -EFAULT;
 			goto abort;
 #endif
 		case TASKFILE_MULTI_OUT:
-			if (drive->mult_count) {
-				args.prehandler = &pre_task_out_intr;
-				args.handler = &task_mulout_intr;
-				args.posthandler = NULL;
-				err = ide_raw_taskfile(drive, &args, outbuf);
-			} else {
+			if (!drive->mult_count) {
 				/* (hs): give up if multcount is not set */
 				printk("%s: %s Multimode Write " \
 					"multcount is not set\n",
-					 drive->name, __FUNCTION__);
+					drive->name, __FUNCTION__);
 				err = -EPERM;
 				goto abort;
 			}
+			if (args.tf_out_flags.all != 0) {
+				args.prehandler = &flagged_pre_task_mulout_intr;
+				args.handler = &flagged_task_mulout_intr;
+			} else {
+				args.prehandler = &pre_task_mulout_intr;
+				args.handler = &task_mulout_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
 			break;
 		case TASKFILE_OUT:
-			args.prehandler = &pre_task_out_intr;
-			args.handler = &task_out_intr;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, outbuf);
+			if (args.tf_out_flags.all != 0) {
+				args.prehandler = &flagged_pre_task_out_intr;
+				args.handler    = &flagged_task_out_intr;
+			} else {
+				args.prehandler = &pre_task_out_intr;
+				args.handler = &task_out_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
 			break;
 		case TASKFILE_MULTI_IN:
-			if (drive->mult_count) {
-				args.prehandler = NULL;
-				args.handler = &task_mulin_intr;
-				args.posthandler = NULL;
-				err = ide_raw_taskfile(drive, &args, inbuf);
-			} else {
+			if (!drive->mult_count) {
 				/* (hs): give up if multcount is not set */
 				printk("%s: %s Multimode Read failure " \
 					"multcount is not set\n",
@@ -1505,23 +1581,30 @@
 				err = -EPERM;
 				goto abort;
 			}
+			if (args.tf_out_flags.all != 0) {
+				args.handler = &flagged_task_mulin_intr;
+			} else {
+				args.handler = &task_mulin_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
 			break;
 		case TASKFILE_IN:
-			args.prehandler = NULL;
-			args.handler = &task_in_intr;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, inbuf);
+			if (args.tf_out_flags.all != 0) {
+				args.handler = &flagged_task_in_intr;
+			} else {
+				args.handler = &task_in_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
 			break;
 		case TASKFILE_NO_DATA:
-			args.prehandler = NULL;
-			args.handler = &task_no_data_intr;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, NULL);
+			if (args.tf_out_flags.all != 0) {
+				args.handler = &flagged_task_no_data_intr;
+			} else {
+				args.handler = &task_no_data_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, 0, NULL);
 			break;
 		default:
-			args.prehandler = NULL;
-			args.handler = NULL;
-			args.posthandler = NULL;
 			err = -EFAULT;
 			goto abort;
 	}
@@ -1555,153 +1638,594 @@
 		kfree(outbuf);
 	if (inbuf != NULL)
 		kfree(inbuf);
+
+//	printk("IDE Taskfile ioctl ended. rc = %i\n", err);
+
+	drive->io_32bit = io_32bit;
+
 	return err;
 }
 
-EXPORT_SYMBOL(task_read_24);
-EXPORT_SYMBOL(do_rw_taskfile);
-EXPORT_SYMBOL(do_taskfile);
-// EXPORT_SYMBOL(flagged_taskfile);
+EXPORT_SYMBOL(ide_taskfile_ioctl);
 
-//EXPORT_SYMBOL(ide_end_taskfile);
+int ide_wait_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
+{
+	struct request rq;
+	u8 buffer[4];
 
-EXPORT_SYMBOL(set_multmode_intr);
-EXPORT_SYMBOL(set_geometry_intr);
-EXPORT_SYMBOL(recal_intr);
+	if (!buf)
+		buf = buffer;
+	memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);
+	ide_init_drive_cmd(&rq);
+	rq.buffer = buf;
+	*buf++ = cmd;
+	*buf++ = nsect;
+	*buf++ = feature;
+	*buf++ = sectors;
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
 
-EXPORT_SYMBOL(task_no_data_intr);
-EXPORT_SYMBOL(task_in_intr);
-EXPORT_SYMBOL(task_mulin_intr);
-EXPORT_SYMBOL(pre_task_out_intr);
-EXPORT_SYMBOL(task_out_intr);
-EXPORT_SYMBOL(task_mulout_intr);
+EXPORT_SYMBOL(ide_wait_cmd);
 
-EXPORT_SYMBOL(ide_init_drive_taskfile);
-EXPORT_SYMBOL(ide_wait_taskfile);
-EXPORT_SYMBOL(ide_raw_taskfile);
-EXPORT_SYMBOL(ide_pre_handler_parser);
-EXPORT_SYMBOL(ide_handler_parser);
-EXPORT_SYMBOL(ide_cmd_type_parser);
-EXPORT_SYMBOL(ide_taskfile_ioctl);
+/*
+ * FIXME : this needs to map into at taskfile. <andre@linux-ide.org>
+ */
+int ide_cmd_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+#if 1
+	int err = 0;
+	u8 args[4], *argbuf = args;
+	u8 xfer_rate = 0;
+	int argsize = 4;
+	ide_task_t tfargs;
 
-#ifdef CONFIG_PKT_TASK_IOCTL
+	if (NULL == (void *) arg) {
+		struct request rq;
+		ide_init_drive_cmd(&rq);
+		return ide_do_drive_cmd(drive, &rq, ide_wait);
+	}
 
-#if 0
+	if (copy_from_user(args, (void *)arg, 4))
+		return -EFAULT;
+
+	memset(&tfargs, 0, sizeof(ide_task_t));
+	tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
+	tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
+	tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
+	tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
+	tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
+	tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
+	tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
+
+	if (args[3]) {
+		argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
+		argbuf = kmalloc(argsize, GFP_KERNEL);
+		if (argbuf == NULL)
+			return -ENOMEM;
+		memcpy(argbuf, args, 4);
+	}
+	if (set_transfer(drive, &tfargs)) {
+		xfer_rate = args[1];
+		if (ide_ata66_check(drive, &tfargs))
+			goto abort;
+	}
+
+	err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
+
+	if (!err && xfer_rate) {
+		/* active-retuning-calls future */
+		ide_set_xfer_rate(drive, xfer_rate);
+		ide_driveid_update(drive);
+	}
+abort:
+	if (copy_to_user((void *)arg, argbuf, argsize))
+		err = -EFAULT;
+	if (argsize > 4)
+		kfree(argbuf);
+	return err;
+
+#else
+
+	int err = 0;
+	u8 args[4], *argbuf = args;
+	u8 xfer_rate = 0;
+	int argsize = 0;
+	ide_task_t tfargs;
+
+	if (NULL == (void *) arg) {
+		struct request rq;
+		ide_init_drive_cmd(&rq);
+		return ide_do_drive_cmd(drive, &rq, ide_wait);
+	}
+
+	if (copy_from_user(args, (void *)arg, 4))
+		return -EFAULT;
+
+	memset(&tfargs, 0, sizeof(ide_task_t));
+	tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
+	tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
+	tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
+	tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
+	tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
+	tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
+	tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
+
+	if (args[3]) {
+		argsize = (SECTOR_WORDS * 4 * args[3]);
+		argbuf = kmalloc(argsize, GFP_KERNEL);
+		if (argbuf == NULL)
+			return -ENOMEM;
+	}
+
+	if (set_transfer(drive, &tfargs)) {
+		xfer_rate = args[1];
+		if (ide_ata66_check(drive, &tfargs))
+			goto abort;
+	}
+
+	tfargs.command_type = ide_cmd_type_parser(&tfargs);
+	err = ide_raw_taskfile(drive, &tfargs, argbuf);
+
+	if (!err && xfer_rate) {
+		/* active-retuning-calls future */
+		ide_set_xfer_rate(drive, xfer_rate);
+		ide_driveid_update(drive);
+	}
+abort:
+	args[0] = tfargs.tfRegister[IDE_COMMAND_OFFSET];
+	args[1] = tfargs.tfRegister[IDE_FEATURE_OFFSET];
+	args[2] = tfargs.tfRegister[IDE_NSECTOR_OFFSET];
+	args[3] = 0;
+
+	if (copy_to_user((void *)arg, argbuf, 4))
+		err = -EFAULT;
+	if (argbuf != NULL) {
+		if (copy_to_user((void *)arg, argbuf + 4, argsize))
+			err = -EFAULT;
+		kfree(argbuf);
+	}
+	return err;
+
+#endif
+}
+
+EXPORT_SYMBOL(ide_cmd_ioctl);
+
+int ide_wait_cmd_task (ide_drive_t *drive, u8 *buf)
 {
+	struct request rq;
 
-{ /* start cdrom */
+	ide_init_drive_cmd(&rq);
+	rq.cmd = IDE_DRIVE_TASK;
+	rq.buffer = buf;
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
 
-	struct cdrom_info *info = drive->driver_data;
+EXPORT_SYMBOL(ide_wait_cmd_task);
 
-	if (info->dma) {
-		if (info->cmd == READ) {
-			info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
-		} else if (info->cmd == WRITE) {
-			info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive);
-		} else {
-			printk("ide-cd: DMA set, but not allowed\n");
+/*
+ * FIXME : this needs to map into at taskfile. <andre@linux-ide.org>
+ */
+int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int err = 0;
+	u8 args[7], *argbuf = args;
+	int argsize = 7;
+
+	if (copy_from_user(args, (void *)arg, 7))
+		return -EFAULT;
+	err = ide_wait_cmd_task(drive, argbuf);
+	if (copy_to_user((void *)arg, argbuf, argsize))
+		err = -EFAULT;
+	return err;
+}
+
+EXPORT_SYMBOL(ide_task_ioctl);
+
+/*
+ * NOTICE: This is additions from IBM to provide a discrete interface,
+ * for selective taskregister access operations.  Nice JOB Klaus!!!
+ * Glad to be able to work and co-develop this with you and IBM.
+ */
+ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	task_struct_t *taskfile	= (task_struct_t *) task->tfRegister;
+	hob_struct_t *hobfile	= (hob_struct_t *) task->hobRegister;
+#if DEBUG_TASKFILE
+	u8 status;
+#endif
+
+
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+	void debug_taskfile(drive, task);
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
+
+	/*
+	 * (ks) Check taskfile in/out flags.
+	 * If set, then execute as it is defined.
+	 * If not set, then define default settings.
+	 * The default values are:
+	 *	write and read all taskfile registers (except data) 
+	 *	write and read the hob registers (sector,nsector,lcyl,hcyl)
+	 */
+	if (task->tf_out_flags.all == 0) {
+		task->tf_out_flags.all = IDE_TASKFILE_STD_OUT_FLAGS;
+		if (drive->addressing == 1)
+			task->tf_out_flags.all |= (IDE_HOB_STD_OUT_FLAGS << 8);
+        }
+
+	if (task->tf_in_flags.all == 0) {
+		task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
+		if (drive->addressing == 1)
+			task->tf_in_flags.all |= (IDE_HOB_STD_IN_FLAGS  << 8);
+        }
+
+	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
+	if (IDE_CONTROL_REG)
+		/* clear nIEN */
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	SELECT_MASK(drive, 0);
+
+#if DEBUG_TASKFILE
+	status = hwif->INB(IDE_STATUS_REG);
+	if (status & 0x80) {
+		printk("flagged_taskfile -> Bad status. Status = %02x. wait 100 usec ...\n", status);
+		udelay(100);
+		status = hwif->INB(IDE_STATUS_REG);
+		printk("flagged_taskfile -> Status = %02x\n", status);
+	}
+#endif
+
+	if (task->tf_out_flags.b.data) {
+		u16 data =  taskfile->data + (hobfile->data << 8);
+		hwif->OUTW(data, IDE_DATA_REG);
+	}
+
+	/* (ks) send hob registers first */
+	if (task->tf_out_flags.b.nsector_hob)
+		hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
+	if (task->tf_out_flags.b.sector_hob)
+		hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
+	if (task->tf_out_flags.b.lcyl_hob)
+		hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);
+	if (task->tf_out_flags.b.hcyl_hob)
+		hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);
+
+	/* (ks) Send now the standard registers */
+	if (task->tf_out_flags.b.error_feature)
+		hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);
+	/* refers to number of sectors to transfer */
+	if (task->tf_out_flags.b.nsector)
+		hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to sector offset or start sector */
+	if (task->tf_out_flags.b.sector)
+		hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
+	if (task->tf_out_flags.b.lcyl)
+		hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
+	if (task->tf_out_flags.b.hcyl)
+		hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
+
+        /*
+	 * (ks) In the flagged taskfile approch, we will used all specified
+	 * registers and the register value will not be changed. Except the
+	 * select bit (master/slave) in the drive_head register. We must make
+	 * sure that the desired drive is selected.
+	 */
+	hwif->OUTB(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
+	switch(task->data_phase) {
+
+   	        case TASKFILE_OUT_DMAQ:
+		case TASKFILE_OUT_DMA:
+			hwif->ide_dma_write(drive);
+			break;
+
+		case TASKFILE_IN_DMAQ:
+		case TASKFILE_IN_DMA:
+			hwif->ide_dma_read(drive);
+			break;
+
+	        default:
+ 			if (task->handler == NULL)
+				return ide_stopped;
+
+			ide_set_handler(drive, task->handler, WAIT_WORSTCASE, NULL);
+			/* Issue the command */
+			hwif->OUTB(taskfile->command, IDE_COMMAND_REG);
+			if (task->prehandler != NULL)
+				return task->prehandler(drive, HWGROUP(drive)->rq);
+	}
+
+	return ide_started;
+}
+
+EXPORT_SYMBOL(flagged_taskfile);
+
+ide_startstop_t flagged_task_no_data_intr (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 stat;
+
+	local_irq_enable();
+
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), READY_STAT, BAD_STAT)) {
+		if (stat & ERR_STAT) {
+			return DRIVER(drive)->error(drive, "flagged_task_no_data_intr", stat);
 		}
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+ 		return DRIVER(drive)->error(drive, "flagged_task_no_data_intr (unexpected phase)", stat); 
 	}
 
-	/* Set up the controller registers. */
-	OUT_BYTE (info->dma, IDE_FEATURE_REG);
-	OUT_BYTE (0, IDE_NSECTOR_REG);
-	OUT_BYTE (0, IDE_SECTOR_REG);
+	ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
 
-	OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);
-	OUT_BYTE (xferlen >> 8  , IDE_HCYL_REG);
-	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
+	return ide_stopped;
+}
+
+/*
+ * Handler for command with PIO data-in phase
+ */
+ide_startstop_t flagged_task_in_intr (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	int retries             = 5;
+
+	if (rq->current_nr_sectors == 0) 
+		return DRIVER(drive)->error(drive, "flagged_task_in_intr (no data requested)", stat); 
+
+	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
+		if (stat & ERR_STAT) {
+			return DRIVER(drive)->error(drive, "flagged_task_in_intr", stat);
+		}
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+		return DRIVER(drive)->error(drive, "flagged_task_in_intr (unexpected data phase)", stat); 
+	}
+
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Read - rq->current_nr_sectors: %d, status: %02x\n", (int) rq->current_nr_sectors, stat);
 
-	if (info->dma)
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+	taskfile_input_data(drive, pBuf, SECTOR_WORDS);
 
-	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
-		ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+	if (--rq->current_nr_sectors != 0) {
+		/*
+                 * (ks) We don't know which command was executed. 
+		 * So, we wait the 'WORSTCASE' value.
+                 */
+		ide_set_handler(drive, &flagged_task_in_intr,  WAIT_WORSTCASE, NULL);
 		return ide_started;
-	} else {
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
-		return (*handler) (drive);
 	}
+	/*
+	 * (ks) Last sector was transfered, wait until drive is ready. 
+	 * This can take up to 10 usec. We willl wait max 50 us.
+	 */
+	while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+		udelay(10);
+	ide_end_drive_cmd (drive, stat, hwif->INB(IDE_ERROR_REG));
 
-} /* end cdrom */
+	return ide_stopped;
+}
 
-{ /* start floppy */
+ide_startstop_t flagged_task_mulin_intr (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	int retries             = 5;
+	unsigned int msect, nsect;
 
-	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_bcount_reg_t bcount;
-	int dma_ok = 0;
+	if (rq->current_nr_sectors == 0) 
+		return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (no data requested)", stat); 
 
-	floppy->pc=pc;		/* Set the current packet command */
+	msect = drive->mult_count;
+	if (msect == 0) 
+		return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (multimode not set)", stat); 
 
-	pc->retries++;
-	pc->actually_transferred=0; /* We haven't transferred any data yet */
-	pc->current_position=pc->buffer;
-	bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024);
+	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
+		if (stat & ERR_STAT) {
+			return DRIVER(drive)->error(drive, "flagged_task_mulin_intr", stat);
+		}
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+		return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (unexpected data phase)", stat); 
+	}
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+
+	DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+	    pBuf, nsect, rq->current_nr_sectors);
+
+	taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+
+	rq->current_nr_sectors -= nsect;
+	if (rq->current_nr_sectors != 0) {
+		/*
+                 * (ks) We don't know which command was executed. 
+		 * So, we wait the 'WORSTCASE' value.
+                 */
+		ide_set_handler(drive, &flagged_task_mulin_intr,  WAIT_WORSTCASE, NULL);
+		return ide_started;
 	}
-	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
-	OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);	/* Use PIO/DMA */
-	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
-	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
-	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
+	/*
+	 * (ks) Last sector was transfered, wait until drive is ready. 
+	 * This can take up to 10 usec. We willl wait max 50 us.
+	 */
+	while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+		udelay(10);
+	ide_end_drive_cmd (drive, stat, hwif->INB(IDE_ERROR_REG));
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (dma_ok) {	/* Begin DMA, if necessary */
-		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+	return ide_stopped;
+}
+
+/*
+ * Pre handler for command with PIO data-out phase
+ */
+ide_startstop_t flagged_pre_task_out_intr (ide_drive_t *drive, struct request *rq)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	ide_startstop_t startstop;
+
+	if (!rq->current_nr_sectors) {
+		return DRIVER(drive)->error(drive, "flagged_pre_task_out_intr (write data not specified)", stat);
 	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-} /* end floppy */
+	if (ide_wait_stat(&startstop, drive, DATA_READY,
+			BAD_W_STAT, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: No DRQ bit after issuing write command.\n", drive->name);
+		return startstop;
+	}
 
-{ /* start tape */
+	taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
+	--rq->current_nr_sectors;
 
-	idetape_tape_t *tape = drive->driver_data;
+	return ide_started;
+}
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
-		printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-	}
-	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+ide_startstop_t flagged_task_out_intr (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
 
-	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
-	OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);	/* Use PIO/DMA */
-	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
-	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
-	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (dma_ok) {	/* Begin DMA, if necessary */
-		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
-		ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
-		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
-		return ide_started;
-	} else {
-		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
-		return idetape_transfer_pc(drive);
+	if (!OK_STAT(stat, DRIVE_READY, BAD_W_STAT)) 
+		return DRIVER(drive)->error(drive, "flagged_task_out_intr", stat);
+	
+	if (!rq->current_nr_sectors) { 
+		ide_end_drive_cmd (drive, stat, hwif->INB(IDE_ERROR_REG));
+		return ide_stopped;
 	}
 
-} /* end tape */
+	if (!OK_STAT(stat, DATA_READY, BAD_W_STAT)) {
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+		return DRIVER(drive)->error(drive, "flagged_task_out_intr (unexpected data phase)", stat); 
+	}
+
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Write - rq->current_nr_sectors: %d, status: %02x\n",
+		(int) rq->current_nr_sectors, stat);
+
+	taskfile_output_data(drive, pBuf, SECTOR_WORDS);
+	--rq->current_nr_sectors;
 
+	/*
+	 * (ks) We don't know which command was executed. 
+	 * So, we wait the 'WORSTCASE' value.
+	 */
+	ide_set_handler(drive, &flagged_task_out_intr, WAIT_WORSTCASE, NULL);
+
+	return ide_started;
 }
-#endif
+
+ide_startstop_t flagged_pre_task_mulout_intr (ide_drive_t *drive, struct request *rq)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	char *pBuf		= NULL;
+	ide_startstop_t startstop;
+	unsigned int msect, nsect;
+
+	if (!rq->current_nr_sectors) 
+		return DRIVER(drive)->error(drive, "flagged_pre_task_mulout_intr (write data not specified)", stat);
+
+	msect = drive->mult_count;
+	if (msect == 0)
+		return DRIVER(drive)->error(drive, "flagged_pre_task_mulout_intr (multimode not set)", stat);
+
+	if (ide_wait_stat(&startstop, drive, DATA_READY,
+			BAD_W_STAT, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: No DRQ bit after issuing write command.\n", drive->name);
+		return startstop;
+	}
+
+	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+	    pBuf, nsect, rq->current_nr_sectors);
+
+	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+
+	rq->current_nr_sectors -= nsect;
+
+	return ide_started;
+}
+
+ide_startstop_t flagged_task_mulout_intr (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	unsigned int msect, nsect;
+
+	msect = drive->mult_count;
+	if (msect == 0)
+		return DRIVER(drive)->error(drive, "flagged_task_mulout_intr (multimode not set)", stat);
+
+	if (!OK_STAT(stat, DRIVE_READY, BAD_W_STAT)) 
+		return DRIVER(drive)->error(drive, "flagged_task_mulout_intr", stat);
+	
+	if (!rq->current_nr_sectors) { 
+		ide_end_drive_cmd (drive, stat, hwif->INB(IDE_ERROR_REG));
+		return ide_stopped;
+	}
+
+	if (!OK_STAT(stat, DATA_READY, BAD_W_STAT)) {
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+		return DRIVER(drive)->error(drive, "flagged_task_mulout_intr (unexpected data phase)", stat); 
+	}
+
+	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+	    pBuf, nsect, rq->current_nr_sectors);
+
+	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+	rq->current_nr_sectors -= nsect;
+
+	/*
+	 * (ks) We don't know which command was executed. 
+	 * So, we wait the 'WORSTCASE' value.
+	 */
+	ide_set_handler(drive, &flagged_task_mulout_intr, WAIT_WORSTCASE, NULL);
+
+	return ide_started;
+}
+
+/*
+ * Beginning of Taskfile OPCODE Library and feature sets.
+ */
+
+#ifdef CONFIG_PKT_TASK_IOCTL
 
 int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide.c linux-2.4.21/drivers/ide/ide.c
--- linux-2.4.20/drivers/ide/ide.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide.c	2002-12-18 18:58:12.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/ide.c		Version 6.31	June 9, 2000
+ *  linux/drivers/ide/ide.c		Version 7.00beta1	Nov 29 2002
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
@@ -12,7 +12,8 @@
  *  See linux/MAINTAINERS for address of current maintainer.
  *
  * This is the multiple IDE interface driver, as evolved from hd.c.
- * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs (usually 14 & 15).
+ * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs
+ *   (usually 14 & 15).
  * There can be up to two drives per interface, as per the ATA-2 spec.
  *
  * Primary:    ide0, port 0x1f0; major=3;  hda is minor=0; hdb is minor=64
@@ -113,16 +114,15 @@
  * Version 6.31		Debug Share INTR's and request queue streaming
  *			Native ATA-100 support
  *			Prep for Cascades Project
+ * Version 7.00alpha	First named revision of ide rearrange
+ * Version 7.00beta	(2.4 backport)
  *
  *  Some additional driver compile-time options are in ./include/linux/ide.h
  *
- *  To do, in likely order of completion:
- *	- modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
- *
  */
 
-#define	REVISION	"Revision: 6.31"
-#define	VERSION		"Id: ide.c 6.31 2000/06/09"
+#define	REVISION	"Revision: 7.00beta-2.4"
+#define	VERSION		"Id: ide.c 7.00b1 20021129"
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
@@ -141,9 +141,7 @@
 #include <linux/genhd.h>
 #include <linux/blkpg.h>
 #include <linux/slab.h>
-#ifndef MODULE
 #include <linux/init.h>
-#endif /* MODULE */
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
@@ -159,81 +157,65 @@
 
 #include "ide_modes.h"
 
-#ifdef CONFIG_KMOD
 #include <linux/kmod.h>
-#endif /* CONFIG_KMOD */
-
-#ifdef CONFIG_IDE_TASKFILE_IO
-#  define __TASKFILE__IO
-#else /* CONFIG_IDE_TASKFILE_IO */
-#  undef __TASKFILE__IO
-#endif /* CONFIG_IDE_TASKFILE_IO */
-
-#ifdef __TASKFILE__IO
-#else /* !__TASKFILE__IO */
-#endif /* __TASKFILE__IO */
 
 /* default maximum number of failures */
 #define IDE_DEFAULT_MAX_FAILURES 	1
 
-static const byte ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR };
-
-static int	idebus_parameter; /* holds the "idebus=" parameter */
-static int	system_bus_speed; /* holds what we think is VESA/PCI bus speed */
-static int	initializing;     /* set while initializing built-in drivers */
+static const u8 ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR,
+					IDE2_MAJOR, IDE3_MAJOR,
+					IDE4_MAJOR, IDE5_MAJOR,
+					IDE6_MAJOR, IDE7_MAJOR,
+					IDE8_MAJOR, IDE9_MAJOR };
+
+static int idebus_parameter;	/* holds the "idebus=" parameter */
+static int system_bus_speed;	/* holds what we think is VESA/PCI bus speed */
+static int initializing;	/* set while initializing built-in drivers */
 
-#ifdef CONFIG_BLK_DEV_IDEPCI
-static int	ide_scan_direction;	/* THIS was formerly 2.2.x pci=reverse */
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+static int ide_scan_direction;	/* THIS was formerly 2.2.x pci=reverse */
 
 #if defined(__mc68000__) || defined(CONFIG_APUS)
 /*
  * ide_lock is used by the Atari code to obtain access to the IDE interrupt,
  * which is shared between several drivers.
  */
-static int	ide_lock;
+static int ide_intr_lock;
 #endif /* __mc68000__ || CONFIG_APUS */
 
+#ifdef CONFIG_IDEDMA_AUTO
 int noautodma = 0;
+#else
+int noautodma = 1;
+#endif
+
+EXPORT_SYMBOL(noautodma);
+
 
 /*
  * ide_modules keeps track of the available IDE chipset/probe/driver modules.
  */
+ide_module_t *ide_chipsets;
 ide_module_t *ide_modules;
 ide_module_t *ide_probe;
 
 /*
  * This is declared extern in ide.h, for access by other IDE modules:
  */
-ide_hwif_t	ide_hwifs[MAX_HWIFS];	/* master data repository */
+ide_hwif_t ide_hwifs[MAX_HWIFS];	/* master data repository */
 
-#if (DISK_RECOVERY_TIME > 0)
-/*
- * For really screwy hardware (hey, at least it *can* be used with Linux)
- * we can enforce a minimum delay time between successive operations.
- */
-static unsigned long read_timer (void)
-{
-	unsigned long t, flags;
-	int i;
+EXPORT_SYMBOL(ide_hwifs);
 
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	t = jiffies * 11932;
-    	outb_p(0, 0x43);
-	i = inb_p(0x40);
-	i |= inb(0x40) << 8;
-	__restore_flags(flags);	/* local CPU only */
-	return (t - i);
-}
-#endif /* DISK_RECOVERY_TIME */
-
-static inline void set_recovery_timer (ide_hwif_t *hwif)
-{
-#if (DISK_RECOVERY_TIME > 0)
-	hwif->last_time = read_timer();
-#endif /* DISK_RECOVERY_TIME */
-}
+ide_devices_t *idedisk;
+ide_devices_t *idecd;
+ide_devices_t *idefloppy;
+ide_devices_t *idetape;
+ide_devices_t *idescsi;
+
+EXPORT_SYMBOL(idedisk);
+EXPORT_SYMBOL(idecd);
+EXPORT_SYMBOL(idefloppy);
+EXPORT_SYMBOL(idetape);
+EXPORT_SYMBOL(idescsi);
 
 /*
  * Do not even *think* about calling this!
@@ -264,6 +246,16 @@
 	hwif->name[2]	= 'e';
 	hwif->name[3]	= '0' + index;
 	hwif->bus_state = BUSSTATE_ON;
+	hwif->reset_poll= NULL;
+	hwif->pre_reset = NULL;
+
+	hwif->atapi_dma = 0;		/* disable all atapi dma */ 
+	hwif->ultra_mask = 0x80;	/* disable all ultra */
+	hwif->mwdma_mask = 0x80;	/* disable all mwdma */
+	hwif->swdma_mask = 0x80;	/* disable all swdma */
+
+	default_hwif_iops(hwif);
+	default_hwif_transport(hwif);
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
 
@@ -279,6 +271,8 @@
 		drive->name[1]			= 'd';
 		drive->name[2]			= 'a' + (index * MAX_DRIVES) + unit;
 		drive->max_failures		= IDE_DEFAULT_MAX_FAILURES;
+		drive->using_dma		= 0;
+		drive->is_flash			= 0;
 		init_waitqueue_head(&drive->wqueue);
 	}
 }
@@ -291,1726 +285,169 @@
  * This routine is normally called at driver initialization time,
  * but may also be called MUCH earlier during kernel "command-line"
  * parameter processing.  As such, we cannot depend on any other parts
- * of the kernel (such as memory allocation) to be functioning yet.
- *
- * This is too bad, as otherwise we could dynamically allocate the
- * ide_drive_t structs as needed, rather than always consuming memory
- * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them.
- */
-#define MAGIC_COOKIE 0x12345678
-static void __init init_ide_data (void)
-{
-	unsigned int index;
-	static unsigned long magic_cookie = MAGIC_COOKIE;
-
-	if (magic_cookie != MAGIC_COOKIE)
-		return;		/* already initialized */
-	magic_cookie = 0;
-
-	/* Initialise all interface structures */
-	for (index = 0; index < MAX_HWIFS; ++index)
-		init_hwif_data(index);
-
-	/* Add default hw interfaces */
-	ide_init_default_hwifs();
-
-	idebus_parameter = 0;
-	system_bus_speed = 0;
-}
-
-/*
- * CompactFlash cards and their brethern pretend to be removable hard disks, except:
- *	(1) they never have a slave unit, and
- *	(2) they don't have doorlock mechanisms.
- * This test catches them, and is invoked elsewhere when setting appropriate config bits.
- *
- * FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD) devices,
- * so in linux 2.3.x we should change this to just treat all PCMCIA drives this way,
- * and get rid of the model-name tests below (too big of an interface change for 2.2.x).
- * At that time, we might also consider parameterizing the timeouts and retries,
- * since these are MUCH faster than mechanical drives.	-M.Lord
- */
-int drive_is_flashcard (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (drive->removable && id != NULL) {
-		if (id->config == 0x848a) return 1;	/* CompactFlash */
-		if (!strncmp(id->model, "KODAK ATA_FLASH", 15)	/* Kodak */
-		 || !strncmp(id->model, "Hitachi CV", 10)	/* Hitachi */
-		 || !strncmp(id->model, "SunDisk SDCFB", 13)	/* SunDisk */
-		 || !strncmp(id->model, "HAGIWARA HPC", 12)	/* Hagiwara */
-		 || !strncmp(id->model, "LEXAR ATA_FLASH", 15)	/* Lexar */
-		 || !strncmp(id->model, "ATA_FLASH", 9))	/* Simple Tech */
-		{
-			return 1;	/* yes, it is a flash memory card */
-		}
-	}
-	return 0;	/* no, it is not a flash memory card */
-}
-
-/*
- * ide_system_bus_speed() returns what we think is the system VESA/PCI
- * bus speed (in MHz).  This is used for calculating interface PIO timings.
- * The default is 40 for known PCI systems, 50 otherwise.
- * The "idebus=xx" parameter can be used to override this value.
- * The actual value to be used is computed/displayed the first time through.
- */
-int ide_system_bus_speed (void)
-{
-	if (!system_bus_speed) {
-		if (idebus_parameter)
-			system_bus_speed = idebus_parameter;	/* user supplied value */
-#ifdef CONFIG_PCI
-		else if (pci_present())
-			system_bus_speed = 33;	/* safe default value for PCI */
-#endif /* CONFIG_PCI */
-		else
-			system_bus_speed = 50;	/* safe default value for VESA and PCI */
-		printk("ide: Assuming %dMHz system bus speed for PIO modes%s\n", system_bus_speed,
-			idebus_parameter ? "" : "; override with idebus=xx");
-	}
-	return system_bus_speed;
-}
-
-#if SUPPORT_VLB_SYNC
-/*
- * Some localbus EIDE interfaces require a special access sequence
- * when using 32-bit I/O instructions to transfer data.  We call this
- * the "vlb_sync" sequence, which consists of three successive reads
- * of the sector count register location, with interrupts disabled
- * to ensure that the reads all happen together.
- */
-static inline void do_vlb_sync (ide_ioreg_t port) {
-	(void) inb (port);
-	(void) inb (port);
-	(void) inb (port);
-}
-#endif /* SUPPORT_VLB_SYNC */
-
-/*
- * This is used for most PIO data transfers *from* the IDE interface
- */
-void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	byte io_32bit;
-
-	/* first check if this controller has defined a special function
-	 * for handling polled ide transfers
-	 */
-
-	if(HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_ide_input_data,
-				     drive, buffer, wcount);
-		return;
-	}
-
-	io_32bit = drive->io_32bit;
-
-	if (io_32bit) {
-#if SUPPORT_VLB_SYNC
-		if (io_32bit & 2) {
-			unsigned long flags;
-			__save_flags(flags);	/* local CPU only */
-			__cli();		/* local CPU only */
-			do_vlb_sync(IDE_NSECTOR_REG);
-			insl(IDE_DATA_REG, buffer, wcount);
-			__restore_flags(flags);	/* local CPU only */
-		} else
-#endif /* SUPPORT_VLB_SYNC */
-			insl(IDE_DATA_REG, buffer, wcount);
-	} else {
-#if SUPPORT_SLOW_DATA_PORTS
-		if (drive->slow) {
-			unsigned short *ptr = (unsigned short *) buffer;
-			while (wcount--) {
-				*ptr++ = inw_p(IDE_DATA_REG);
-				*ptr++ = inw_p(IDE_DATA_REG);
-			}
-		} else
-#endif /* SUPPORT_SLOW_DATA_PORTS */
-			insw(IDE_DATA_REG, buffer, wcount<<1);
-	}
-}
-
-/*
- * This is used for most PIO data transfers *to* the IDE interface
- */
-void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	byte io_32bit;
-
-	if(HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_ide_output_data,
-				     drive, buffer, wcount);
-		return;
-	}
-
-	io_32bit = drive->io_32bit;
-
-	if (io_32bit) {
-#if SUPPORT_VLB_SYNC
-		if (io_32bit & 2) {
-			unsigned long flags;
-			__save_flags(flags);	/* local CPU only */
-			__cli();		/* local CPU only */
-			do_vlb_sync(IDE_NSECTOR_REG);
-			outsl(IDE_DATA_REG, buffer, wcount);
-			__restore_flags(flags);	/* local CPU only */
-		} else
-#endif /* SUPPORT_VLB_SYNC */
-			outsl(IDE_DATA_REG, buffer, wcount);
-	} else {
-#if SUPPORT_SLOW_DATA_PORTS
-		if (drive->slow) {
-			unsigned short *ptr = (unsigned short *) buffer;
-			while (wcount--) {
-				outw_p(*ptr++, IDE_DATA_REG);
-				outw_p(*ptr++, IDE_DATA_REG);
-			}
-		} else
-#endif /* SUPPORT_SLOW_DATA_PORTS */
-			outsw(IDE_DATA_REG, buffer, wcount<<1);
-	}
-}
-
-/*
- * The following routines are mainly used by the ATAPI drivers.
- *
- * These routines will round up any request for an odd number of bytes,
- * so if an odd bytecount is specified, be sure that there's at least one
- * extra byte allocated for the buffer.
- */
-void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
-{
-	if(HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_atapi_input_bytes,
-				     drive, buffer, bytecount);
-		return;
-	}
-
-	++bytecount;
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
-	if (MACH_IS_ATARI || MACH_IS_Q40) {
-		/* Atari has a byte-swapped IDE interface */
-		insw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
-		return;
-	}
-#endif /* CONFIG_ATARI */
-	ide_input_data (drive, buffer, bytecount / 4);
-	if ((bytecount & 0x03) >= 2)
-		insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
-}
-
-void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
-{
-	if(HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_atapi_output_bytes,
-				     drive, buffer, bytecount);
-		return;
-	}
-
-	++bytecount;
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
-	if (MACH_IS_ATARI || MACH_IS_Q40) {
-		/* Atari has a byte-swapped IDE interface */
-		outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
-		return;
-	}
-#endif /* CONFIG_ATARI */
-	ide_output_data (drive, buffer, bytecount / 4);
-	if ((bytecount & 0x03) >= 2)
-		outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
-}
-
-/*
- * Needed for PCI irq sharing
- */
-//static inline
-int drive_is_ready (ide_drive_t *drive)
-{
-	byte stat = 0;
-	if (drive->waiting_for_dma)
-		return HWIF(drive)->dmaproc(ide_dma_test_irq, drive);
-#if 0
-	udelay(1);	/* need to guarantee 400ns since last command was issued */
-#endif
-
-#ifdef CONFIG_IDEPCI_SHARE_IRQ
-	/*
-	 * We do a passive status test under shared PCI interrupts on
-	 * cards that truly share the ATA side interrupt, but may also share
-	 * an interrupt with another pci card/device.  We make no assumptions
-	 * about possible isa-pnp and pci-pnp issues yet.
-	 */
-	if (IDE_CONTROL_REG)
-		stat = GET_ALTSTAT();
-	else
-#endif /* CONFIG_IDEPCI_SHARE_IRQ */
-	stat = GET_STAT();	/* Note: this may clear a pending IRQ!! */
-
-	if (stat & BUSY_STAT)
-		return 0;	/* drive busy:  definitely not interrupting */
-	return 1;		/* drive ready: *might* be interrupting */
-}
-
-/*
- * This is our end_request replacement function.
- */
-void ide_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
-{
-	struct request *rq;
-	unsigned long flags;
-	ide_drive_t *drive = hwgroup->drive;
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	rq = hwgroup->rq;
-
-	/*
-	 * decide whether to reenable DMA -- 3 is a random magic for now,
-	 * if we DMA timeout more than 3 times, just stay in PIO
-	 */
-	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
-		drive->state = 0;
-		hwgroup->hwif->dmaproc(ide_dma_on, drive);
-	}
-
-	if (!end_that_request_first(rq, uptodate, hwgroup->drive->name)) {
-		add_blkdev_randomness(MAJOR(rq->rq_dev));
-		blkdev_dequeue_request(rq);
-        	hwgroup->rq = NULL;
-		end_that_request_last(rq);
-	}
-	spin_unlock_irqrestore(&io_request_lock, flags);
-}
-
-/*
- * This should get invoked any time we exit the driver to
- * wait for an interrupt response from a drive.  handler() points
- * at the appropriate code to handle the next interrupt, and a
- * timer is started to prevent us from waiting forever in case
- * something goes wrong (see the ide_timer_expiry() handler later on).
- */
-void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
-		      unsigned int timeout, ide_expiry_t *expiry)
-{
-	unsigned long flags;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	if (hwgroup->handler != NULL) {
-		printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n",
-			drive->name, hwgroup->handler, handler);
-	}
-	hwgroup->handler	= handler;
-	hwgroup->expiry		= expiry;
-	hwgroup->timer.expires	= jiffies + timeout;
-	add_timer(&hwgroup->timer);
-	spin_unlock_irqrestore(&io_request_lock, flags);
-}
-
-/*
- * current_capacity() returns the capacity (in sectors) of a drive
- * according to its current geometry/LBA settings.
- */
-unsigned long current_capacity (ide_drive_t *drive)
-{
-	if (!drive->present)
-		return 0;
-	if (drive->driver != NULL)
-		return DRIVER(drive)->capacity(drive);
-	return 0;
-}
-
-extern struct block_device_operations ide_fops[];
-/*
- * ide_geninit() is called exactly *once* for each interface.
- */
-void ide_geninit (ide_hwif_t *hwif)
-{
-	unsigned int unit;
-	struct gendisk *gd = hwif->gd;
-
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		ide_drive_t *drive = &hwif->drives[unit];
-
-		if (!drive->present)
-			continue;
-		if (drive->media!=ide_disk && drive->media!=ide_floppy)
-			continue;
-		register_disk(gd,MKDEV(hwif->major,unit<<PARTN_BITS),
-#ifdef CONFIG_BLK_DEV_ISAPNP
-			(drive->forced_geom && drive->noprobe) ? 1 :
-#endif /* CONFIG_BLK_DEV_ISAPNP */
-			1<<PARTN_BITS, ide_fops,
-			current_capacity(drive));
-	}
-}
-
-static ide_startstop_t do_reset1 (ide_drive_t *, int);		/* needed below */
-
-/*
- * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
- * during an atapi drive reset operation. If the drive has not yet responded,
- * and we have not yet hit our maximum waiting time, then the timer is restarted
- * for another 50ms.
- */
-static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	byte stat;
-
-	SELECT_DRIVE(HWIF(drive),drive);
-	udelay (10);
-
-	if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
-		printk("%s: ATAPI reset complete\n", drive->name);
-	} else {
-		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
-			ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
-			return ide_started;	/* continue polling */
-		}
-		hwgroup->poll_timeout = 0;	/* end of polling */
-		printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat);
-		return do_reset1 (drive, 1);	/* do it the old fashioned way */
-	}
-	hwgroup->poll_timeout = 0;	/* done polling */
-	return ide_stopped;
-}
-
-/*
- * reset_pollfunc() gets invoked to poll the interface for completion every 50ms
- * during an ide reset operation. If the drives have not yet responded,
- * and we have not yet hit our maximum waiting time, then the timer is restarted
- * for another 50ms.
- */
-static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	ide_hwif_t *hwif = HWIF(drive);
-	byte tmp;
-
-	if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
-		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
-			ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
-			return ide_started;	/* continue polling */
-		}
-		printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
-		drive->failures++;
-	} else  {
-		printk("%s: reset: ", hwif->name);
-		if ((tmp = GET_ERR()) == 1) {
-			printk("success\n");
-			drive->failures = 0;
-		} else {
-			drive->failures++;
-#if FANCY_STATUS_DUMPS
-			printk("master: ");
-			switch (tmp & 0x7f) {
-				case 1: printk("passed");
-					break;
-				case 2: printk("formatter device error");
-					break;
-				case 3: printk("sector buffer error");
-					break;
-				case 4: printk("ECC circuitry error");
-					break;
-				case 5: printk("controlling MPU error");
-					break;
-				default:printk("error (0x%02x?)", tmp);
-			}
-			if (tmp & 0x80)
-				printk("; slave: failed");
-			printk("\n");
-#else
-			printk("failed\n");
-#endif /* FANCY_STATUS_DUMPS */
-		}
-	}
-	hwgroup->poll_timeout = 0;	/* done polling */
-	return ide_stopped;
-}
-
-static void check_dma_crc (ide_drive_t *drive)
-{
-	if (drive->crc_count) {
-		(void) HWIF(drive)->dmaproc(ide_dma_off_quietly, drive);
-		if ((HWIF(drive)->speedproc) != NULL)
-			HWIF(drive)->speedproc(drive, ide_auto_reduce_xfer(drive));
-		if (drive->current_speed >= XFER_SW_DMA_0)
-			(void) HWIF(drive)->dmaproc(ide_dma_on, drive);
-	} else {
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-	}
-}
-
-static void pre_reset (ide_drive_t *drive)
-{
-	if (drive->driver != NULL)
-		DRIVER(drive)->pre_reset(drive);
-
-	if (!drive->keep_settings) {
-		if (drive->using_dma) {
-			check_dma_crc(drive);
-		} else {
-			drive->unmask = 0;
-			drive->io_32bit = 0;
-		}
-		return;
-	}
-	if (drive->using_dma)
-		check_dma_crc(drive);
-}
-
-/*
- * do_reset1() attempts to recover a confused drive by resetting it.
- * Unfortunately, resetting a disk drive actually resets all devices on
- * the same interface, so it can really be thought of as resetting the
- * interface rather than resetting the drive.
- *
- * ATAPI devices have their own reset mechanism which allows them to be
- * individually reset without clobbering other devices on the same interface.
- *
- * Unfortunately, the IDE interface does not generate an interrupt to let
- * us know when the reset operation has finished, so we must poll for this.
- * Equally poor, though, is the fact that this may a very long time to complete,
- * (up to 30 seconds worstcase).  So, instead of busy-waiting here for it,
- * we set a timer to poll at 50ms intervals.
- */
-static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
-{
-	unsigned int unit;
-	unsigned long flags;
-	ide_hwif_t *hwif = HWIF(drive);
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	/* For an ATAPI device, first try an ATAPI SRST. */
-	if (drive->media != ide_disk && !do_not_try_atapi) {
-		pre_reset(drive);
-		SELECT_DRIVE(hwif,drive);
-		udelay (20);
-		OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
-		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
-		__restore_flags (flags);	/* local CPU only */
-		return ide_started;
-	}
-
-	/*
-	 * First, reset any device state data we were maintaining
-	 * for any of the drives on this interface.
-	 */
-	for (unit = 0; unit < MAX_DRIVES; ++unit)
-		pre_reset(&hwif->drives[unit]);
-
-#if OK_TO_RESET_CONTROLLER
-	if (!IDE_CONTROL_REG) {
-		__restore_flags(flags);
-		return ide_stopped;
-	}
-	/*
-	 * Note that we also set nIEN while resetting the device,
-	 * to mask unwanted interrupts from the interface during the reset.
-	 * However, due to the design of PC hardware, this will cause an
-	 * immediate interrupt due to the edge transition it produces.
-	 * This single interrupt gives us a "fast poll" for drives that
-	 * recover from reset very quickly, saving us the first 50ms wait time.
-	 */
-	OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG);	/* set SRST and nIEN */
-	udelay(10);			/* more than enough time */
-	if (drive->quirk_list == 2) {
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* clear SRST and nIEN */
-	} else {
-		OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* clear SRST, leave nIEN */
-	}
-	udelay(10);			/* more than enough time */
-	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-	ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
-
-	/*
-	 * Some weird controller like resetting themselves to a strange
-	 * state when the disks are reset this way. At least, the Winbond
-	 * 553 documentation says that
-	 */
-	if (hwif->resetproc != NULL)
-		hwif->resetproc(drive);
-
-#endif	/* OK_TO_RESET_CONTROLLER */
-
-	__restore_flags (flags);	/* local CPU only */
-	return ide_started;
-}
-
-/*
- * ide_do_reset() is the entry point to the drive/interface reset code.
- */
-ide_startstop_t ide_do_reset (ide_drive_t *drive)
-{
-	return do_reset1 (drive, 0);
-}
-
-static inline u32 read_24 (ide_drive_t *drive)
-{
-	return  (IN_BYTE(IDE_HCYL_REG)<<16) |
-		(IN_BYTE(IDE_LCYL_REG)<<8) |
-		 IN_BYTE(IDE_SECTOR_REG);
-}
-
-/*
- * Clean up after success/failure of an explicit drive cmd
- */
-void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
-{
-	unsigned long flags;
-	struct request *rq;
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	rq = HWGROUP(drive)->rq;
-	spin_unlock_irqrestore(&io_request_lock, flags);
-
-	switch(rq->cmd) {
-		case IDE_DRIVE_CMD:
-		{
-			byte *args = (byte *) rq->buffer;
-			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
-			if (args) {
-				args[0] = stat;
-				args[1] = err;
-				args[2] = IN_BYTE(IDE_NSECTOR_REG);
-			}
-			break;
-		}
-		case IDE_DRIVE_TASK:
-		{
-			byte *args = (byte *) rq->buffer;
-			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
-			if (args) {
-				args[0] = stat;
-				args[1] = err;
-				args[2] = IN_BYTE(IDE_NSECTOR_REG);
-				args[3] = IN_BYTE(IDE_SECTOR_REG);
-				args[4] = IN_BYTE(IDE_LCYL_REG);
-				args[5] = IN_BYTE(IDE_HCYL_REG);
-				args[6] = IN_BYTE(IDE_SELECT_REG);
-			}
-			break;
-		}
-		case IDE_DRIVE_TASKFILE:
-		{
-			ide_task_t *args = (ide_task_t *) rq->special;
-			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
-			if (args) {
-				if (args->tf_in_flags.b.data) {
-					unsigned short data			= IN_WORD(IDE_DATA_REG);
-					args->tfRegister[IDE_DATA_OFFSET]	= (data) & 0xFF;
-					args->hobRegister[IDE_DATA_OFFSET_HOB]	= (data >> 8) & 0xFF;
-				}
-				args->tfRegister[IDE_ERROR_OFFSET]   = err;
-				args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
-				args->tfRegister[IDE_SECTOR_OFFSET]  = IN_BYTE(IDE_SECTOR_REG);
-				args->tfRegister[IDE_LCYL_OFFSET]    = IN_BYTE(IDE_LCYL_REG);
-				args->tfRegister[IDE_HCYL_OFFSET]    = IN_BYTE(IDE_HCYL_REG);
-				args->tfRegister[IDE_SELECT_OFFSET]  = IN_BYTE(IDE_SELECT_REG);
-				args->tfRegister[IDE_STATUS_OFFSET]  = stat;
-
-				if ((drive->id->command_set_2 & 0x0400) &&
-				    (drive->id->cfs_enable_2 & 0x0400) &&
-				    (drive->addressing == 1)) {
-					OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
-					args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
-					args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
-					args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = IN_BYTE(IDE_SECTOR_REG);
-					args->hobRegister[IDE_LCYL_OFFSET_HOB]    = IN_BYTE(IDE_LCYL_REG);
-					args->hobRegister[IDE_HCYL_OFFSET_HOB]    = IN_BYTE(IDE_HCYL_REG);
-				}
-			}
-			break;
-		}
-		default:
-			break;
-	}
-	spin_lock_irqsave(&io_request_lock, flags);
-	blkdev_dequeue_request(rq);
-	HWGROUP(drive)->rq = NULL;
-	end_that_request_last(rq);
-	spin_unlock_irqrestore(&io_request_lock, flags);
-}
-
-/*
- * Error reporting, in human readable form (luxurious, but a memory hog).
- */
-byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat)
-{
-	unsigned long flags;
-	byte err = 0;
-
-	__save_flags (flags);	/* local CPU only */
-	ide__sti();		/* local CPU only */
-	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
-#if FANCY_STATUS_DUMPS
-	printk(" { ");
-	if (stat & BUSY_STAT)
-		printk("Busy ");
-	else {
-		if (stat & READY_STAT)	printk("DriveReady ");
-		if (stat & WRERR_STAT)	printk("DeviceFault ");
-		if (stat & SEEK_STAT)	printk("SeekComplete ");
-		if (stat & DRQ_STAT)	printk("DataRequest ");
-		if (stat & ECC_STAT)	printk("CorrectedError ");
-		if (stat & INDEX_STAT)	printk("Index ");
-		if (stat & ERR_STAT)	printk("Error ");
-	}
-	printk("}");
-#endif	/* FANCY_STATUS_DUMPS */
-	printk("\n");
-	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
-		err = GET_ERR();
-		printk("%s: %s: error=0x%02x", drive->name, msg, err);
-#if FANCY_STATUS_DUMPS
-		if (drive->media == ide_disk) {
-			printk(" { ");
-			if (err & ABRT_ERR)	printk("DriveStatusError ");
-			if (err & ICRC_ERR)	printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector ");
-			if (err & ECC_ERR)	printk("UncorrectableError ");
-			if (err & ID_ERR)	printk("SectorIdNotFound ");
-			if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
-			if (err & MARK_ERR)	printk("AddrMarkNotFound ");
-			printk("}");
-			if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
-				if ((drive->id->command_set_2 & 0x0400) &&
-				    (drive->id->cfs_enable_2 & 0x0400) &&
-				    (drive->addressing == 1)) {
-					__u64 sectors = 0;
-					u32 low = 0, high = 0;
-					low = read_24(drive);
-					OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG);
-					high = read_24(drive);
-
-					sectors = ((__u64)high << 24) | low;
-					printk(", LBAsect=%llu, high=%d, low=%d",
-					       (unsigned long long) sectors,
-					       high, low);
-				} else {
-					byte cur = IN_BYTE(IDE_SELECT_REG);
-					if (cur & 0x40) {	/* using LBA? */
-						printk(", LBAsect=%ld", (unsigned long)
-						 ((cur&0xf)<<24)
-						 |(IN_BYTE(IDE_HCYL_REG)<<16)
-						 |(IN_BYTE(IDE_LCYL_REG)<<8)
-						 | IN_BYTE(IDE_SECTOR_REG));
-					} else {
-						printk(", CHS=%d/%d/%d",
-						 (IN_BYTE(IDE_HCYL_REG)<<8) +
-						  IN_BYTE(IDE_LCYL_REG),
-						  cur & 0xf,
-						  IN_BYTE(IDE_SECTOR_REG));
-					}
-				}
-				if (HWGROUP(drive) && HWGROUP(drive)->rq)
-					printk(", sector=%ld", HWGROUP(drive)->rq->sector);
-			}
-		}
-#endif	/* FANCY_STATUS_DUMPS */
-		printk("\n");
-	}
-	__restore_flags (flags);	/* local CPU only */
-	return err;
-}
-
-/*
- * try_to_flush_leftover_data() is invoked in response to a drive
- * unexpectedly having its DRQ_STAT bit set.  As an alternative to
- * resetting the drive, this routine tries to clear the condition
- * by read a sector's worth of data from the drive.  Of course,
- * this may not help if the drive is *waiting* for data from *us*.
- */
-static void try_to_flush_leftover_data (ide_drive_t *drive)
-{
-	int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
-
-	if (drive->media != ide_disk)
-		return;
-	while (i > 0) {
-		u32 buffer[16];
-		unsigned int wcount = (i > 16) ? 16 : i;
-		i -= wcount;
-		ide_input_data (drive, buffer, wcount);
-	}
-}
-
-/*
- * ide_error() takes action based on the error returned by the drive.
- */
-ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat)
-{
-	struct request *rq;
-	byte err;
-
-	err = ide_dump_status(drive, msg, stat);
-	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
-		return ide_stopped;
-	/* retry only "normal" I/O: */
-	if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) {
-		rq->errors = 1;
-		ide_end_drive_cmd(drive, stat, err);
-		return ide_stopped;
-	}
-	if (rq->cmd == IDE_DRIVE_TASKFILE) {
-		rq->errors = 1;
-		ide_end_drive_cmd(drive, stat, err);
-//		ide_end_taskfile(drive, stat, err);
-		return ide_stopped;
-	}
-
-	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
-		rq->errors |= ERROR_RESET;
-	} else {
-		if (drive->media == ide_disk && (stat & ERR_STAT)) {
-			/* err has different meaning on cdrom and tape */
-			if (err == ABRT_ERR) {
-				if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
-					return ide_stopped; /* some newer drives don't support WIN_SPECIFY */
-			} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) {
-				drive->crc_count++; /* UDMA crc error -- just retry the operation */
-			} else if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */
-				rq->errors = ERROR_MAX;
-			else if (err & TRK0_ERR)	/* help it find track zero */
-				rq->errors |= ERROR_RECAL;
-		}
-		if ((stat & DRQ_STAT) && rq->cmd != WRITE)
-			try_to_flush_leftover_data(drive);
-	}
-	if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
-		OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);	/* force an abort */
-
-	if (rq->errors >= ERROR_MAX) {
-		if (drive->driver != NULL)
-			DRIVER(drive)->end_request(0, HWGROUP(drive));
-		else
-	 		ide_end_request(0, HWGROUP(drive));
-	} else {
-		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
-			++rq->errors;
-			return ide_do_reset(drive);
-		}
-		if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
-			drive->special.b.recalibrate = 1;
-		++rq->errors;
-	}
-	return ide_stopped;
-}
-
-/*
- * Issue a simple drive command
- * The drive must be selected beforehand.
- */
-void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
-{
-	ide_set_handler (drive, handler, WAIT_CMD, NULL);
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* clear nIEN */
-	SELECT_MASK(HWIF(drive),drive,0);
-	OUT_BYTE(nsect,IDE_NSECTOR_REG);
-	OUT_BYTE(cmd,IDE_COMMAND_REG);
-}
-
-/*
- * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
- */
-static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
-{
-	struct request *rq = HWGROUP(drive)->rq;
-	byte *args = (byte *) rq->buffer;
-	byte stat = GET_STAT();
-	int retries = 10;
-
-	ide__sti();	/* local CPU only */
-	if ((stat & DRQ_STAT) && args && args[3]) {
-		byte io_32bit = drive->io_32bit;
-		drive->io_32bit = 0;
-		ide_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
-		drive->io_32bit = io_32bit;
-		while (((stat = GET_STAT()) & BUSY_STAT) && retries--)
-			udelay(100);
-	}
-
-	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
-		return ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */
-	ide_end_drive_cmd (drive, stat, GET_ERR());
-	return ide_stopped;
-}
-
-/*
- * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
- * commands to a drive.  It used to do much more, but has been scaled back.
- */
-static ide_startstop_t do_special (ide_drive_t *drive)
-{
-	special_t *s = &drive->special;
-
-#ifdef DEBUG
-	printk("%s: do_special: 0x%02x\n", drive->name, s->all);
-#endif
-	if (s->b.set_tune) {
-		ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
-		s->b.set_tune = 0;
-		if (tuneproc != NULL)
-			tuneproc(drive, drive->tune_req);
-	} else if (drive->driver != NULL) {
-		return DRIVER(drive)->special(drive);
-	} else if (s->all) {
-		printk("%s: bad special flag: 0x%02x\n", drive->name, s->all);
-		s->all = 0;
-	}
-	return ide_stopped;
-}
-
-/*
- * This routine busy-waits for the drive status to be not "busy".
- * It then checks the status for all of the "good" bits and none
- * of the "bad" bits, and if all is okay it returns 0.  All other
- * cases return 1 after invoking ide_error() -- caller should just return.
- *
- * This routine should get fixed to not hog the cpu during extra long waits..
- * That could be done by busy-waiting for the first jiffy or two, and then
- * setting a timer to wake up at half second intervals thereafter,
- * until timeout is achieved, before timing out.
- */
-int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout) {
-	byte stat;
-	int i;
-	unsigned long flags;
- 
-	/* bail early if we've exceeded max_failures */
-	if (drive->max_failures && (drive->failures > drive->max_failures)) {
-		*startstop = ide_stopped;
-		return 1;
-	}
-
-	udelay(1);	/* spec allows drive 400ns to assert "BUSY" */
-	if ((stat = GET_STAT()) & BUSY_STAT) {
-		__save_flags(flags);	/* local CPU only */
-		ide__sti();		/* local CPU only */
-		timeout += jiffies;
-		while ((stat = GET_STAT()) & BUSY_STAT) {
-			if (0 < (signed long)(jiffies - timeout)) {
-				__restore_flags(flags);	/* local CPU only */
-				*startstop = ide_error(drive, "status timeout", stat);
-				return 1;
-			}
-		}
-		__restore_flags(flags);	/* local CPU only */
-	}
-	/*
-	 * Allow status to settle, then read it again.
-	 * A few rare drives vastly violate the 400ns spec here,
-	 * so we'll wait up to 10usec for a "good" status
-	 * rather than expensively fail things immediately.
-	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
-	 */
-	for (i = 0; i < 10; i++) {
-		udelay(1);
-		if (OK_STAT((stat = GET_STAT()), good, bad))
-			return 0;
-	}
-	*startstop = ide_error(drive, "status error", stat);
-	return 1;
-}
-
-/*
- * execute_drive_cmd() issues a special drive command,
- * usually initiated by ioctl() from the external hdparm program.
- */
-static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
-{
- 	switch(rq->cmd) {
- 		case IDE_DRIVE_TASKFILE:
- 		{
- 			ide_task_t *args = rq->special;
- 
- 			if (!(args)) break;
- 
-#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
-	{
-	printk(KERN_INFO "%s: ", drive->name);
-//	printk("TF.0=x%02x ", args->tfRegister[IDE_DATA_OFFSET]);
-	printk("TF.1=x%02x ", args->tfRegister[IDE_FEATURE_OFFSET]);
-	printk("TF.2=x%02x ", args->tfRegister[IDE_NSECTOR_OFFSET]);
-	printk("TF.3=x%02x ", args->tfRegister[IDE_SECTOR_OFFSET]);
-	printk("TF.4=x%02x ", args->tfRegister[IDE_LCYL_OFFSET]);
-	printk("TF.5=x%02x ", args->tfRegister[IDE_HCYL_OFFSET]);
-	printk("TF.6=x%02x ", args->tfRegister[IDE_SELECT_OFFSET]);
-	printk("TF.7=x%02x\n", args->tfRegister[IDE_COMMAND_OFFSET]);
-	printk(KERN_INFO "%s: ", drive->name);
-//	printk("HTF.0=x%02x ", args->hobRegister[IDE_DATA_OFFSET_HOB]);
-	printk("HTF.1=x%02x ", args->hobRegister[IDE_FEATURE_OFFSET_HOB]);
-	printk("HTF.2=x%02x ", args->hobRegister[IDE_NSECTOR_OFFSET_HOB]);
-	printk("HTF.3=x%02x ", args->hobRegister[IDE_SECTOR_OFFSET_HOB]);
-	printk("HTF.4=x%02x ", args->hobRegister[IDE_LCYL_OFFSET_HOB]);
-	printk("HTF.5=x%02x ", args->hobRegister[IDE_HCYL_OFFSET_HOB]);
-	printk("HTF.6=x%02x ", args->hobRegister[IDE_SELECT_OFFSET_HOB]);
-	printk("HTF.7=x%02x\n", args->hobRegister[IDE_CONTROL_OFFSET_HOB]);
-	}
-#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
-
-//			if (args->tf_out_flags.all == 0) {
- 			do_taskfile(drive,
- 				(struct hd_drive_task_hdr *)&args->tfRegister,
-				(struct hd_drive_hob_hdr *)&args->hobRegister,
- 				args->handler);
-//			} else {
-//				return flagged_taskfile(drive, args);
-//			} 
-
- 			if (((args->command_type == IDE_DRIVE_TASK_RAW_WRITE) ||
- 			     (args->command_type == IDE_DRIVE_TASK_OUT)) &&
-			      args->prehandler && args->handler)
-				return args->prehandler(drive, rq);
- 			return ide_started;
- 		}
- 		case IDE_DRIVE_TASK:
- 		{
- 			byte *args = rq->buffer;
- 			byte sel;
- 
- 			if (!(args)) break;
-#ifdef DEBUG
- 			printk("%s: DRIVE_TASK_CMD ", drive->name);
- 			printk("cmd=0x%02x ", args[0]);
- 			printk("fr=0x%02x ", args[1]);
- 			printk("ns=0x%02x ", args[2]);
- 			printk("sc=0x%02x ", args[3]);
- 			printk("lcyl=0x%02x ", args[4]);
- 			printk("hcyl=0x%02x ", args[5]);
- 			printk("sel=0x%02x\n", args[6]);
-#endif
- 			OUT_BYTE(args[1], IDE_FEATURE_REG);
- 			OUT_BYTE(args[3], IDE_SECTOR_REG);
- 			OUT_BYTE(args[4], IDE_LCYL_REG);
- 			OUT_BYTE(args[5], IDE_HCYL_REG);
- 			sel = (args[6] & ~0x10);
- 			if (drive->select.b.unit)
- 				sel |= 0x10;
- 			OUT_BYTE(sel, IDE_SELECT_REG);
- 			ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
- 			return ide_started;
- 		}
- 		case IDE_DRIVE_CMD:
- 		{
- 			byte *args = rq->buffer;
- 
- 			if (!(args)) break;
-#ifdef DEBUG
- 			printk("%s: DRIVE_CMD ", drive->name);
- 			printk("cmd=0x%02x ", args[0]);
- 			printk("sc=0x%02x ", args[1]);
- 			printk("fr=0x%02x ", args[2]);
- 			printk("xx=0x%02x\n", args[3]);
-#endif
- 			if (args[0] == WIN_SMART) {
- 				OUT_BYTE(0x4f, IDE_LCYL_REG);
- 				OUT_BYTE(0xc2, IDE_HCYL_REG);
- 				OUT_BYTE(args[2],IDE_FEATURE_REG);
- 				OUT_BYTE(args[1],IDE_SECTOR_REG);
- 				ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
- 				return ide_started;
- 			}
- 			OUT_BYTE(args[2],IDE_FEATURE_REG);
- 			ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
- 			return ide_started;
- 		}
- 		default:
- 			break;
- 	}
- 	/*
- 	 * NULL is actually a valid way of waiting for
- 	 * all current requests to be flushed from the queue.
- 	 */
-#ifdef DEBUG
- 	printk("%s: DRIVE_CMD (null)\n", drive->name);
-#endif
- 	ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
- 	return ide_stopped;
-}
-
-/*
- * start_request() initiates handling of a new I/O request
- * needed to reverse the perverted changes anonymously made back
- * 2.3.99-pre6
- */
-static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
-{
-	ide_startstop_t startstop;
-	unsigned long block, blockend;
-	unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS;
-	ide_hwif_t *hwif = HWIF(drive);
-
-#ifdef DEBUG
-	printk("%s: start_request: current=0x%08lx\n", hwif->name, (unsigned long) rq);
-#endif
-	/* bail early if we've exceeded max_failures */
-	if (drive->max_failures && (drive->failures > drive->max_failures)) {
-		goto kill_rq;
-	}
-
-	if (unit >= MAX_DRIVES) {
-		printk("%s: bad device number: %s\n", hwif->name, kdevname(rq->rq_dev));
-		goto kill_rq;
-	}
-#ifdef DEBUG
-	if (rq->bh && !buffer_locked(rq->bh)) {
-		printk("%s: block not locked\n", drive->name);
-		goto kill_rq;
-	}
-#endif
-	block    = rq->sector;
-	blockend = block + rq->nr_sectors;
-
-	if ((rq->cmd == READ || rq->cmd == WRITE) &&
-	    (drive->media == ide_disk || drive->media == ide_floppy)) {
-		if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) {
-			printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name,
-			 (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors);
-			goto kill_rq;
-		}
-		block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0;
-	}
-	/* Yecch - this will shift the entire interval,
-	   possibly killing some innocent following sector */
-	if (block == 0 && drive->remap_0_to_1 == 1)
-		block = 1;  /* redirect MBR access to EZ-Drive partn table */
-
-#if (DISK_RECOVERY_TIME > 0)
-	while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
-#endif
-
-	SELECT_DRIVE(hwif, drive);
-	if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
-		printk("%s: drive not ready for command\n", drive->name);
-		return startstop;
-	}
-	if (!drive->special.all) {
-		switch(rq->cmd) {
-			case IDE_DRIVE_CMD:
-			case IDE_DRIVE_TASK:
-			case IDE_DRIVE_TASKFILE:
-				return execute_drive_cmd(drive, rq);
-			default:
-				break;
-		}
-		if (drive->driver != NULL) {
-			return (DRIVER(drive)->do_request(drive, rq, block));
-		}
-		printk("%s: media type %d not supported\n", drive->name, drive->media);
-		goto kill_rq;
-	}
-	return do_special(drive);
-kill_rq:
-	if (drive->driver != NULL)
-		DRIVER(drive)->end_request(0, HWGROUP(drive));
-	else
-		ide_end_request(0, HWGROUP(drive));
-	return ide_stopped;
-}
-
-ide_startstop_t restart_request (ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	unsigned long flags;
-	struct request *rq;
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	hwgroup->handler = NULL;
-	del_timer(&hwgroup->timer);
-	rq = hwgroup->rq;
-	spin_unlock_irqrestore(&io_request_lock, flags);
-
-	return start_request(drive, rq);
-}
-
-/*
- * ide_stall_queue() can be used by a drive to give excess bandwidth back
- * to the hwgroup by sleeping for timeout jiffies.
- */
-void ide_stall_queue (ide_drive_t *drive, unsigned long timeout)
-{
-	if (timeout > WAIT_WORSTCASE)
-		timeout = WAIT_WORSTCASE;
-	drive->sleep = timeout + jiffies;
-}
-
-#define WAKEUP(drive)	((drive)->service_start + 2 * (drive)->service_time)
-
-/*
- * choose_drive() selects the next drive which will be serviced.
- */
-static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup)
-{
-	ide_drive_t *drive, *best;
-
-repeat:	
-	best = NULL;
-	drive = hwgroup->drive;
-	do {
-		if (!list_empty(&drive->queue.queue_head) && (!drive->sleep || 0 <= (signed long)(jiffies - drive->sleep))) {
-			if (!best
-			 || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep)))
-			 || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive))))
-			{
-				if( !drive->queue.plugged )
-					best = drive;
-			}
-		}
-	} while ((drive = drive->next) != hwgroup->drive);
-	if (best && best->nice1 && !best->sleep && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) {
-		long t = (signed long)(WAKEUP(best) - jiffies);
-		if (t >= WAIT_MIN_SLEEP) {
-			/*
-			 * We *may* have some time to spare, but first let's see if
-			 * someone can potentially benefit from our nice mood today..
-			 */
-			drive = best->next;
-			do {
-				if (!drive->sleep
-				 && 0 < (signed long)(WAKEUP(drive) - (jiffies - best->service_time))
-				 && 0 < (signed long)((jiffies + t) - WAKEUP(drive)))
-				{
-					ide_stall_queue(best, IDE_MIN(t, 10 * WAIT_MIN_SLEEP));
-					goto repeat;
-				}
-			} while ((drive = drive->next) != best);
-		}
-	}
-	return best;
-}
-
-/*
- * Issue a new request to a drive from hwgroup
- * Caller must have already done spin_lock_irqsave(&io_request_lock, ..);
- *
- * A hwgroup is a serialized group of IDE interfaces.  Usually there is
- * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640)
- * may have both interfaces in a single hwgroup to "serialize" access.
- * Or possibly multiple ISA interfaces can share a common IRQ by being grouped
- * together into one hwgroup for serialized access.
- *
- * Note also that several hwgroups can end up sharing a single IRQ,
- * possibly along with many other devices.  This is especially common in
- * PCI-based systems with off-board IDE controller cards.
- *
- * The IDE driver uses the single global io_request_lock spinlock to protect
- * access to the request queues, and to protect the hwgroup->busy flag.
- *
- * The first thread into the driver for a particular hwgroup sets the
- * hwgroup->busy flag to indicate that this hwgroup is now active,
- * and then initiates processing of the top request from the request queue.
- *
- * Other threads attempting entry notice the busy setting, and will simply
- * queue their new requests and exit immediately.  Note that hwgroup->busy
- * remains set even when the driver is merely awaiting the next interrupt.
- * Thus, the meaning is "this hwgroup is busy processing a request".
- *
- * When processing of a request completes, the completing thread or IRQ-handler
- * will start the next request from the queue.  If no more work remains,
- * the driver will clear the hwgroup->busy flag and exit.
- *
- * The io_request_lock (spinlock) is used to protect all access to the
- * hwgroup->busy flag, but is otherwise not needed for most processing in
- * the driver.  This makes the driver much more friendlier to shared IRQs
- * than previous designs, while remaining 100% (?) SMP safe and capable.
- */
-/* --BenH: made non-static as ide-pmac.c uses it to kick the hwgroup back
- *         into life on wakeup from machine sleep.
- */ 
-void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
-{
-	ide_drive_t	*drive;
-	ide_hwif_t	*hwif;
-	struct request	*rq;
-	ide_startstop_t	startstop;
-
-	ide_get_lock(&ide_lock, ide_intr, hwgroup);	/* for atari only: POSSIBLY BROKEN HERE(?) */
-
-	__cli();	/* necessary paranoia: ensure IRQs are masked on local CPU */
-
-	while (!hwgroup->busy) {
-		hwgroup->busy = 1;
-		drive = choose_drive(hwgroup);
-		if (drive == NULL) {
-			unsigned long sleep = 0;
-			hwgroup->rq = NULL;
-			drive = hwgroup->drive;
-			do {
-				if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep)))
-					sleep = drive->sleep;
-			} while ((drive = drive->next) != hwgroup->drive);
-			if (sleep) {
-				/*
-				 * Take a short snooze, and then wake up this hwgroup again.
-				 * This gives other hwgroups on the same a chance to
-				 * play fairly with us, just in case there are big differences
-				 * in relative throughputs.. don't want to hog the cpu too much.
-				 */
-				if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) 
-					sleep = jiffies + WAIT_MIN_SLEEP;
-#if 1
-				if (timer_pending(&hwgroup->timer))
-					printk("ide_set_handler: timer already active\n");
-#endif
-				hwgroup->sleeping = 1;	/* so that ide_timer_expiry knows what to do */
-				mod_timer(&hwgroup->timer, sleep);
-				/* we purposely leave hwgroup->busy==1 while sleeping */
-			} else {
-				/* Ugly, but how can we sleep for the lock otherwise? perhaps from tq_disk? */
-				ide_release_lock(&ide_lock);	/* for atari only */
-				hwgroup->busy = 0;
-			}
-			return;		/* no more work for this hwgroup (for now) */
-		}
-		hwif = HWIF(drive);
-		if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && hwif->io_ports[IDE_CONTROL_OFFSET]) {
-			/* set nIEN for previous hwif */
-			SELECT_INTERRUPT(hwif, drive);
-		}
-		hwgroup->hwif = hwif;
-		hwgroup->drive = drive;
-		drive->sleep = 0;
-		drive->service_start = jiffies;
-
-		if ( drive->queue.plugged )	/* paranoia */
-			printk("%s: Huh? nuking plugged queue\n", drive->name);
-
-		rq = hwgroup->rq = blkdev_entry_next_request(&drive->queue.queue_head);
-		/*
-		 * Some systems have trouble with IDE IRQs arriving while
-		 * the driver is still setting things up.  So, here we disable
-		 * the IRQ used by this interface while the request is being started.
-		 * This may look bad at first, but pretty much the same thing
-		 * happens anyway when any interrupt comes in, IDE or otherwise
-		 *  -- the kernel masks the IRQ while it is being handled.
-		 */
-		if (masked_irq && hwif->irq != masked_irq)
-			disable_irq_nosync(hwif->irq);
-		spin_unlock(&io_request_lock);
-		ide__sti();	/* allow other IRQs while we start this request */
-		startstop = start_request(drive, rq);
-		spin_lock_irq(&io_request_lock);
-		if (masked_irq && hwif->irq != masked_irq)
-			enable_irq(hwif->irq);
-		if (startstop == ide_stopped)
-			hwgroup->busy = 0;
-	}
-}
-
-/*
- * ide_get_queue() returns the queue which corresponds to a given device.
- */
-request_queue_t *ide_get_queue (kdev_t dev)
-{
-	ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[MAJOR(dev)].data;
-
-	return &hwif->drives[DEVICE_NR(dev) & 1].queue;
-}
-
-/*
- * Passes the stuff to ide_do_request
- */
-void do_ide_request(request_queue_t *q)
-{
-	ide_do_request(q->queuedata, 0);
-}
-
-/*
- * un-busy the hwgroup etc, and clear any pending DMA status. we want to
- * retry the current request in pio mode instead of risking tossing it
- * all away
- */
-void ide_dma_timeout_retry(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	struct request *rq;
-
-	/*
-	 * end current dma transaction
-	 */
-	(void) hwif->dmaproc(ide_dma_end, drive);
-
-	/*
-	 * complain a little, later we might remove some of this verbosity
-	 */
-	printk("%s: timeout waiting for DMA\n", drive->name);
-	(void) hwif->dmaproc(ide_dma_timeout, drive);
-
-	/*
-	 * disable dma for now, but remember that we did so because of
-	 * a timeout -- we'll reenable after we finish this next request
-	 * (or rather the first chunk of it) in pio.
-	 */
-	drive->retry_pio++;
-	drive->state = DMA_PIO_RETRY;
-	(void) hwif->dmaproc(ide_dma_off_quietly, drive);
-
-	/*
-	 * un-busy drive etc (hwgroup->busy is cleared on return) and
-	 * make sure request is sane
-	 */
-	rq = HWGROUP(drive)->rq;
-	HWGROUP(drive)->rq = NULL;
-
-	rq->errors = 0;
-	rq->sector = rq->bh->b_rsector;
-	rq->current_nr_sectors = rq->bh->b_size >> 9;
-	rq->buffer = rq->bh->b_data;
-}
-
-/*
- * ide_timer_expiry() is our timeout function for all drive operations.
- * But note that it can also be invoked as a result of a "sleep" operation
- * triggered by the mod_timer() call in ide_do_request.
- */
-void ide_timer_expiry (unsigned long data)
-{
-	ide_hwgroup_t	*hwgroup = (ide_hwgroup_t *) data;
-	ide_handler_t	*handler;
-	ide_expiry_t	*expiry;
- 	unsigned long	flags;
-	unsigned long	wait;
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	del_timer(&hwgroup->timer);
-
-	if ((handler = hwgroup->handler) == NULL) {
-		/*
-		 * Either a marginal timeout occurred
-		 * (got the interrupt just as timer expired),
-		 * or we were "sleeping" to give other devices a chance.
-		 * Either way, we don't really want to complain about anything.
-		 */
-		if (hwgroup->sleeping) {
-			hwgroup->sleeping = 0;
-			hwgroup->busy = 0;
-		}
-	} else {
-		ide_drive_t *drive = hwgroup->drive;
-		if (!drive) {
-			printk("ide_timer_expiry: hwgroup->drive was NULL\n");
-			hwgroup->handler = NULL;
-		} else {
-			ide_hwif_t *hwif;
-			ide_startstop_t startstop;
-			if (!hwgroup->busy) {
-				hwgroup->busy = 1;	/* paranoia */
-				printk("%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name);
-			}
-			if ((expiry = hwgroup->expiry) != NULL) {
-				/* continue */
-				if ((wait = expiry(drive)) != 0) {
-					/* reset timer */
-					hwgroup->timer.expires  = jiffies + wait;
-					add_timer(&hwgroup->timer);
-					spin_unlock_irqrestore(&io_request_lock, flags);
-					return;
-				}
-			}
-			hwgroup->handler = NULL;
-			/*
-			 * We need to simulate a real interrupt when invoking
-			 * the handler() function, which means we need to globally
-			 * mask the specific IRQ:
-			 */
-			spin_unlock(&io_request_lock);
-			hwif  = HWIF(drive);
-#if DISABLE_IRQ_NOSYNC
-			disable_irq_nosync(hwif->irq);
-#else
-			disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
-#endif /* DISABLE_IRQ_NOSYNC */
-			__cli();	/* local CPU only, as if we were handling an interrupt */
-			if (hwgroup->poll_timeout != 0) {
-				startstop = handler(drive);
-			} else if (drive_is_ready(drive)) {
-				if (drive->waiting_for_dma)
-					(void) hwgroup->hwif->dmaproc(ide_dma_lostirq, drive);
-				(void)ide_ack_intr(hwif);
-				printk("%s: lost interrupt\n", drive->name);
-				startstop = handler(drive);
-			} else {
-				if (drive->waiting_for_dma) {
-					startstop = ide_stopped;
-					ide_dma_timeout_retry(drive);
-				} else
-					startstop = ide_error(drive, "irq timeout", GET_STAT());
-			}
-			set_recovery_timer(hwif);
-			drive->service_time = jiffies - drive->service_start;
-			enable_irq(hwif->irq);
-			spin_lock_irq(&io_request_lock);
-			if (startstop == ide_stopped)
-				hwgroup->busy = 0;
-		}
-	}
-	ide_do_request(hwgroup, 0);
-	spin_unlock_irqrestore(&io_request_lock, flags);
-}
-
-/*
- * There's nothing really useful we can do with an unexpected interrupt,
- * other than reading the status register (to clear it), and logging it.
- * There should be no way that an irq can happen before we're ready for it,
- * so we needn't worry much about losing an "important" interrupt here.
- *
- * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
- * drive enters "idle", "standby", or "sleep" mode, so if the status looks
- * "good", we just ignore the interrupt completely.
- *
- * This routine assumes __cli() is in effect when called.
- *
- * If an unexpected interrupt happens on irq15 while we are handling irq14
- * and if the two interfaces are "serialized" (CMD640), then it looks like
- * we could screw up by interfering with a new request being set up for irq15.
- *
- * In reality, this is a non-issue.  The new command is not sent unless the
- * drive is ready to accept one, in which case we know the drive is not
- * trying to interrupt us.  And ide_set_handler() is always invoked before
- * completing the issuance of any new drive command, so we will not be
- * accidentally invoked as a result of any valid command completion interrupt.
- *
- */
-static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
-{
-	byte stat;
-	ide_hwif_t *hwif = hwgroup->hwif;
-
-	/*
-	 * handle the unexpected interrupt
-	 */
-	do {
-		if (hwif->irq == irq) {
-			stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
-			if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
-				/* Try to not flood the console with msgs */
-				static unsigned long last_msgtime, count;
-				++count;
-				if (0 < (signed long)(jiffies - (last_msgtime + HZ))) {
-					last_msgtime = jiffies;
-					printk("%s%s: unexpected interrupt, status=0x%02x, count=%ld\n",
-					 hwif->name, (hwif->next == hwgroup->hwif) ? "" : "(?)", stat, count);
-				}
-			}
-		}
-	} while ((hwif = hwif->next) != hwgroup->hwif);
-}
-
-/*
- * entry point for all interrupts, caller does __cli() for us
+ * of the kernel (such as memory allocation) to be functioning yet.
+ *
+ * This is too bad, as otherwise we could dynamically allocate the
+ * ide_drive_t structs as needed, rather than always consuming memory
+ * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them.
+ *
+ * FIXME: We should stuff the setup data into __init and copy the
+ * relevant hwifs/allocate them properly during boot.
  */
-void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
+#define MAGIC_COOKIE 0x12345678
+static void __init init_ide_data (void)
 {
-	unsigned long flags;
-	ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;
-	ide_hwif_t *hwif;
-	ide_drive_t *drive;
-	ide_handler_t *handler;
-	ide_startstop_t startstop;
+	unsigned int index;
+	static unsigned long magic_cookie = MAGIC_COOKIE;
 
-	spin_lock_irqsave(&io_request_lock, flags);
-	hwif = hwgroup->hwif;
+	if (magic_cookie != MAGIC_COOKIE)
+		return;		/* already initialized */
+	magic_cookie = 0;
 
-	if (!ide_ack_intr(hwif)) {
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return;
-	}
+	/* Initialise all interface structures */
+	for (index = 0; index < MAX_HWIFS; ++index)
+		init_hwif_data(index);
 
-	if ((handler = hwgroup->handler) == NULL || hwgroup->poll_timeout != 0) {
-		/*
-		 * Not expecting an interrupt from this drive.
-		 * That means this could be:
-		 *	(1) an interrupt from another PCI device
-		 *	sharing the same PCI INT# as us.
-		 * or	(2) a drive just entered sleep or standby mode,
-		 *	and is interrupting to let us know.
-		 * or	(3) a spurious interrupt of unknown origin.
-		 *
-		 * For PCI, we cannot tell the difference,
-		 * so in that case we just ignore it and hope it goes away.
-		 */
-#ifdef CONFIG_BLK_DEV_IDEPCI
-		if (IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL))
-#endif	/* CONFIG_BLK_DEV_IDEPCI */
-		{
-			/*
-			 * Probably not a shared PCI interrupt,
-			 * so we can safely try to do something about it:
-			 */
-			unexpected_intr(irq, hwgroup);
-#ifdef CONFIG_BLK_DEV_IDEPCI
-		} else {
-			/*
-			 * Whack the status register, just in case we have a leftover pending IRQ.
-			 */
-			(void) IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
-#endif /* CONFIG_BLK_DEV_IDEPCI */
-		}
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return;
-	}
-	drive = hwgroup->drive;
-	if (!drive) {
-		/*
-		 * This should NEVER happen, and there isn't much we could do about it here.
-		 */
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return;
-	}
-	if (!drive_is_ready(drive)) {
-		/*
-		 * This happens regularly when we share a PCI IRQ with another device.
-		 * Unfortunately, it can also happen with some buggy drives that trigger
-		 * the IRQ before their status register is up to date.  Hopefully we have
-		 * enough advance overhead that the latter isn't a problem.
-		 */
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return;
-	}
-	if (!hwgroup->busy) {
-		hwgroup->busy = 1;	/* paranoia */
-		printk("%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name);
-	}
-	hwgroup->handler = NULL;
-	del_timer(&hwgroup->timer);
-	spin_unlock(&io_request_lock);
-
-	if (drive->unmask)
-		ide__sti();	/* local CPU only */
-	startstop = handler(drive);		/* service this interrupt, may set handler for next interrupt */
-	spin_lock_irq(&io_request_lock);
+	/* Add default hw interfaces */
+	ide_init_default_hwifs();
 
-	/*
-	 * Note that handler() may have set things up for another
-	 * interrupt to occur soon, but it cannot happen until
-	 * we exit from this routine, because it will be the
-	 * same irq as is currently being serviced here, and Linux
-	 * won't allow another of the same (on any CPU) until we return.
-	 */
-	set_recovery_timer(HWIF(drive));
-	drive->service_time = jiffies - drive->service_start;
-	if (startstop == ide_stopped) {
-		if (hwgroup->handler == NULL) {	/* paranoia */
-			hwgroup->busy = 0;
-			ide_do_request(hwgroup, hwif->irq);
-		} else {
-			printk("%s: ide_intr: huh? expected NULL handler on exit\n", drive->name);
-		}
-	}
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	idebus_parameter = 0;
+	system_bus_speed = 0;
 }
 
 /*
- * get_info_ptr() returns the (ide_drive_t *) for a given device number.
- * It returns NULL if the given device number does not match any present drives.
+ * ide_system_bus_speed() returns what we think is the system VESA/PCI
+ * bus speed (in MHz).  This is used for calculating interface PIO timings.
+ * The default is 40 for known PCI systems, 50 otherwise.
+ * The "idebus=xx" parameter can be used to override this value.
+ * The actual value to be used is computed/displayed the first time through.
  */
-ide_drive_t *get_info_ptr (kdev_t i_rdev)
+int ide_system_bus_speed (void)
 {
-	int		major = MAJOR(i_rdev);
-#if 0
-	int		minor = MINOR(i_rdev) & PARTN_MASK;
-#endif
-	unsigned int	h;
-
-	for (h = 0; h < MAX_HWIFS; ++h) {
-		ide_hwif_t  *hwif = &ide_hwifs[h];
-		if (hwif->present && major == hwif->major) {
-			unsigned unit = DEVICE_NR(i_rdev);
-			if (unit < MAX_DRIVES) {
-				ide_drive_t *drive = &hwif->drives[unit];
-#if 0
-				if ((drive->present) && (drive->part[minor].nr_sects))
-#else
-				if (drive->present)
-#endif
-					return drive;
-			}
-			break;
+	if (!system_bus_speed) {
+		if (idebus_parameter) {
+			/* user supplied value */
+			system_bus_speed = idebus_parameter;
+		} else if (pci_present()) {
+			/* safe default value for PCI */
+			system_bus_speed = 33;
+		} else {
+			/* safe default value for VESA and PCI */
+			system_bus_speed = 50;
 		}
+		printk(KERN_INFO "ide: Assuming %dMHz system bus speed "
+			"for PIO modes%s\n", system_bus_speed,
+			idebus_parameter ? "" : "; override with idebus=xx");
 	}
-	return NULL;
+	return system_bus_speed;
 }
 
 /*
- * This function is intended to be used prior to invoking ide_do_drive_cmd().
+ * current_capacity() returns the capacity (in sectors) of a drive
+ * according to its current geometry/LBA settings.
  */
-void ide_init_drive_cmd (struct request *rq)
+unsigned long current_capacity (ide_drive_t *drive)
+{
+	if (!drive->present)
+		return 0;
+	if (drive->driver != NULL)
+		return DRIVER(drive)->capacity(drive);
+	return 0;
+}
+
+EXPORT_SYMBOL(current_capacity);
+
+static inline u32 read_24 (ide_drive_t *drive)
 {
-	memset(rq, 0, sizeof(*rq));
-	rq->cmd = IDE_DRIVE_CMD;
+	return  (HWIF(drive)->INB(IDE_HCYL_REG)<<16) |
+		(HWIF(drive)->INB(IDE_LCYL_REG)<<8) |
+		 HWIF(drive)->INB(IDE_SECTOR_REG);
 }
 
 /*
- * This function issues a special IDE device request
- * onto the request queue.
- *
- * If action is ide_wait, then the rq is queued at the end of the
- * request queue, and the function sleeps until it has been processed.
- * This is for use when invoked from an ioctl handler.
- *
- * If action is ide_preempt, then the rq is queued at the head of
- * the request queue, displacing the currently-being-processed
- * request and this function returns immediately without waiting
- * for the new rq to be completed.  This is VERY DANGEROUS, and is
- * intended for careful use by the ATAPI tape/cdrom driver code.
- *
- * If action is ide_next, then the rq is queued immediately after
- * the currently-being-processed-request (if any), and the function
- * returns without waiting for the new rq to be completed.  As above,
- * This is VERY DANGEROUS, and is intended for careful use by the
- * ATAPI tape/cdrom driver code.
- *
- * If action is ide_end, then the rq is queued at the end of the
- * request queue, and the function returns immediately without waiting
- * for the new rq to be completed. This is again intended for careful
- * use by the ATAPI tape/cdrom driver code.
+ * Error reporting, in human readable form (luxurious, but a memory hog).
  */
-int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action)
+u8 ide_dump_status (ide_drive_t *drive, const char *msg, u8 stat)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long flags;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	unsigned int major = HWIF(drive)->major;
-	struct list_head *queue_head = &drive->queue.queue_head;
-	DECLARE_COMPLETION(wait);
+	u8 err = 0;
 
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (HWIF(drive)->chipset == ide_pdc4030 && rq->buffer != NULL)
-		return -ENOSYS;  /* special drive cmds not supported */
-#endif
-	rq->errors = 0;
-	rq->rq_status = RQ_ACTIVE;
-	rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);
-	if (action == ide_wait)
-		rq->waiting = &wait;
-	spin_lock_irqsave(&io_request_lock, flags);
-	if (list_empty(queue_head) || action == ide_preempt) {
-		if (action == ide_preempt)
-			hwgroup->rq = NULL;
+	local_irq_set(flags);
+	printk(KERN_WARNING "%s: %s: status=0x%02x", drive->name, msg, stat);
+#if FANCY_STATUS_DUMPS
+	printk(" { ");
+	if (stat & BUSY_STAT) {
+		printk("Busy ");
 	} else {
-		if (action == ide_wait || action == ide_end) {
-			queue_head = queue_head->prev;
-		} else
-			queue_head = queue_head->next;
-	}
-	list_add(&rq->queue, queue_head);
-	ide_do_request(hwgroup, 0);
-	spin_unlock_irqrestore(&io_request_lock, flags);
-	if (action == ide_wait) {
-		wait_for_completion(&wait);	/* wait for it to be serviced */
-		return rq->errors ? -EIO : 0;	/* return -EIO if errors */
+		if (stat & READY_STAT)	printk("DriveReady ");
+		if (stat & WRERR_STAT)	printk("DeviceFault ");
+		if (stat & SEEK_STAT)	printk("SeekComplete ");
+		if (stat & DRQ_STAT)	printk("DataRequest ");
+		if (stat & ECC_STAT)	printk("CorrectedError ");
+		if (stat & INDEX_STAT)	printk("Index ");
+		if (stat & ERR_STAT)	printk("Error ");
 	}
-	return 0;
+	printk("}");
+#endif	/* FANCY_STATUS_DUMPS */
+	printk("\n");
+	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+		err = hwif->INB(IDE_ERROR_REG);
+		printk("%s: %s: error=0x%02x", drive->name, msg, err);
+#if FANCY_STATUS_DUMPS
+		if (drive->media == ide_disk) {
+			printk(" { ");
+			if (err & ABRT_ERR)	printk("DriveStatusError ");
+			if (err & ICRC_ERR)	printk("Bad%s ", (err & ABRT_ERR) ? "CRC" : "Sector");
+			if (err & ECC_ERR)	printk("UncorrectableError ");
+			if (err & ID_ERR)	printk("SectorIdNotFound ");
+			if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
+			if (err & MARK_ERR)	printk("AddrMarkNotFound ");
+			printk("}");
+			if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+				if ((drive->id->command_set_2 & 0x0400) &&
+				    (drive->id->cfs_enable_2 & 0x0400) &&
+				    (drive->addressing == 1)) {
+					u64 sectors = 0;
+					u32 high = 0;
+					u32 low = read_24(drive);
+					hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
+					high = read_24(drive);
 
+					sectors = ((u64)high << 24) | low;
+					printk(", LBAsect=%llu, high=%d, low=%d",
+					       (u64) sectors,
+					       high, low);
+				} else {
+					u8 cur = hwif->INB(IDE_SELECT_REG);
+					if (cur & 0x40) {	/* using LBA? */
+						printk(", LBAsect=%ld", (unsigned long)
+						 ((cur&0xf)<<24)
+						 |(hwif->INB(IDE_HCYL_REG)<<16)
+						 |(hwif->INB(IDE_LCYL_REG)<<8)
+						 | hwif->INB(IDE_SECTOR_REG));
+					} else {
+						printk(", CHS=%d/%d/%d",
+						 (hwif->INB(IDE_HCYL_REG)<<8) +
+						  hwif->INB(IDE_LCYL_REG),
+						  cur & 0xf,
+						  hwif->INB(IDE_SECTOR_REG));
+					}
+				}
+				if (HWGROUP(drive) && HWGROUP(drive)->rq)
+					printk(", sector=%ld", HWGROUP(drive)->rq->sector);
+			}
+		}
+#endif	/* FANCY_STATUS_DUMPS */
+		printk("\n");
+	}
+	local_irq_restore(flags);
+	return err;
 }
 
+EXPORT_SYMBOL(ide_dump_status);
+
+
 /*
  * This routine is called to flush all partitions and partition tables
  * for a changed disk, and then re-read the new partition table.
@@ -2049,7 +486,7 @@
 		drive->part[p].nr_sects   = 0;
 	};
 
-	if (DRIVER(drive)->revalidate)
+	if (DRIVER(drive) && DRIVER(drive)->revalidate)
 		DRIVER(drive)->revalidate(drive);
 
 	drive->busy = 0;
@@ -2058,7 +495,9 @@
 	return 0;
 }
 
-static void revalidate_drives (void)
+EXPORT_SYMBOL(ide_revalidate_disk);
+
+static void revalidate_drives (int revaldiate)
 {
 	ide_hwif_t *hwif;
 	ide_drive_t *drive;
@@ -2070,26 +509,28 @@
 			drive = &ide_hwifs[index].drives[unit];
 			if (drive->revalidate) {
 				drive->revalidate = 0;
-				if (!initializing)
+				if ((!initializing) && (revaldiate))
 					(void) ide_revalidate_disk(MKDEV(hwif->major, unit<<PARTN_BITS));
 			}
 		}
 	}
 }
 
-static void ide_probe_module (void)
+void ide_probe_module (int revaldiate)
 {
 	if (!ide_probe) {
-#if defined(CONFIG_KMOD) && defined(CONFIG_BLK_DEV_IDE_MODULE)
+#if  defined(CONFIG_BLK_DEV_IDE_MODULE)
 		(void) request_module("ide-probe-mod");
-#endif /* (CONFIG_KMOD) && (CONFIG_BLK_DEV_IDE_MODULE) */
+#endif
 	} else {
 		(void) ide_probe->init();
 	}
-	revalidate_drives();
+	revalidate_drives(revaldiate);
 }
 
-static void ide_driver_module (void)
+EXPORT_SYMBOL(ide_probe_module);
+
+void ide_driver_module (int revaldiate)
 {
 	int index;
 	ide_module_t *module = ide_modules;
@@ -2097,15 +538,17 @@
 	for (index = 0; index < MAX_HWIFS; ++index)
 		if (ide_hwifs[index].present)
 			goto search;
-	ide_probe_module();
+	ide_probe_module(revaldiate);
 search:
 	while (module) {
 		(void) module->init();
 		module = module->next;
 	}
-	revalidate_drives();
+	revalidate_drives(revaldiate);
 }
 
+EXPORT_SYMBOL(ide_driver_module);
+
 static int ide_open (struct inode * inode, struct file * filp)
 {
 	ide_drive_t *drive;
@@ -2113,29 +556,28 @@
 	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
 		return -ENXIO;
 	if (drive->driver == NULL)
-		ide_driver_module();
-#ifdef CONFIG_KMOD
+		ide_driver_module(1);
 	if (drive->driver == NULL) {
 		if (drive->media == ide_disk)
 			(void) request_module("ide-disk");
+		if (drive->scsi)
+			(void) request_module("ide-scsi");
 		if (drive->media == ide_cdrom)
 			(void) request_module("ide-cd");
 		if (drive->media == ide_tape)
 			(void) request_module("ide-tape");
 		if (drive->media == ide_floppy)
 			(void) request_module("ide-floppy");
-#if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI)
-		if (drive->media == ide_scsi)
-			(void) request_module("ide-scsi");
-#endif /* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */
 	}
-#endif /* CONFIG_KMOD */
+	
+	/* The locking here isnt enough, but this is hard to fix
+	   in the 2.4 cases */
 	while (drive->busy)
 		sleep_on(&drive->wqueue);
 	drive->usage++;
-	if (drive->driver != NULL)
+	if (drive->driver != NULL && !drive->dead)
 		return DRIVER(drive)->open(inode, filp, drive);
-	printk ("%s: driver not present\n", drive->name);
+	printk(KERN_WARNING "%s: driver not present\n", drive->name);
 	drive->usage--;
 	return -ENXIO;
 }
@@ -2156,22 +598,6 @@
 	return 0;
 }
 
-int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
-{
-	if (!drive->present || drive->busy || drive->usage)
-		goto abort;
-	if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
-		goto abort;
-	strncpy(drive->driver_req, driver, 9);
-	ide_driver_module();
-	drive->driver_req[0] = 0;
-	ide_driver_module();
-	if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver))
-		return 0;
-abort:
-	return 1;
-}
-
 #ifdef CONFIG_PROC_FS
 ide_proc_entry_t generic_subdriver_entries[] = {
 	{ "capacity",	S_IFREG|S_IRUGO,	proc_ide_read_capacity,	NULL },
@@ -2179,6 +605,10 @@
 };
 #endif
 
+
+#define hwif_release_region(addr, num) \
+	((hwif->mmio) ? release_mem_region((addr),(num)) : release_region((addr),(num)))
+
 /*
  * Note that we only release the standard ports,
  * and do not even try to handle any extra ports
@@ -2186,36 +616,33 @@
  */
 void hwif_unregister (ide_hwif_t *hwif)
 {
-	if (hwif->straight8) {
-		ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
-		goto jump_eight;
-	}
-	if (hwif->io_ports[IDE_DATA_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
-	if (hwif->io_ports[IDE_ERROR_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_ERROR_OFFSET], 1);
-	if (hwif->io_ports[IDE_NSECTOR_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1);
-	if (hwif->io_ports[IDE_SECTOR_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1);
-	if (hwif->io_ports[IDE_LCYL_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_LCYL_OFFSET], 1);
-	if (hwif->io_ports[IDE_HCYL_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_HCYL_OFFSET], 1);
-	if (hwif->io_ports[IDE_SELECT_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
-	if (hwif->io_ports[IDE_STATUS_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
-jump_eight:
+	u32 i = 0;
+
+	if (hwif->mmio == 2)
+		return;
 	if (hwif->io_ports[IDE_CONTROL_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
+		hwif_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
 #if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
 	if (hwif->io_ports[IDE_IRQ_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
+		hwif_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
 #endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
+
+	if (hwif->straight8) {
+		hwif_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
+		return;
+	}
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		if (hwif->io_ports[i]) {
+			hwif_release_region(hwif->io_ports[i], 1);
+		}
+	}
 }
 
-void ide_unregister (unsigned int index)
+EXPORT_SYMBOL(hwif_unregister);
+
+extern void init_hwif_data(unsigned int index);
+
+int ide_unregister (unsigned int index)
 {
 	struct gendisk *gd;
 	ide_drive_t *drive, *d;
@@ -2227,9 +654,9 @@
 	ide_hwif_t old_hwif;
 
 	if (index >= MAX_HWIFS)
-		return;
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
+		BUG();
+		
+	spin_lock_irqsave(&io_request_lock, flags);
 	hwif = &ide_hwifs[index];
 	if (!hwif->present)
 		goto abort;
@@ -2239,7 +666,7 @@
 			continue;
 		if (drive->busy || drive->usage)
 			goto abort;
-		if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+		if (drive->driver != NULL && DRIVER(drive)->shutdown(drive))
 			goto abort;
 	}
 	hwif->present = 0;
@@ -2247,11 +674,13 @@
 	/*
 	 * All clear?  Then blow away the buffer cache
 	 */
-	sti();
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		drive = &hwif->drives[unit];
 		if (!drive->present)
 			continue;
+		if (drive->driver != NULL)
+			DRIVER(drive)->cleanup(drive);
 		minor = drive->select.b.unit << PARTN_BITS;
 		for (p = 0; p < (1<<PARTN_BITS); ++p) {
 			if (drive->part[p].nr_sects > 0) {
@@ -2263,7 +692,8 @@
 		destroy_proc_ide_drives(hwif);
 #endif
 	}
-	cli();
+
+	spin_lock_irqsave(&io_request_lock, flags);
 	hwgroup = hwif->hwgroup;
 
 	/*
@@ -2293,7 +723,7 @@
 	for (i = 0; i < MAX_DRIVES; ++i) {
 		drive = &hwif->drives[i];
 		if (drive->de) {
-			devfs_unregister (drive->de);
+			devfs_unregister(drive->de);
 			drive->de = NULL;
 		}
 		if (!drive->present)
@@ -2320,12 +750,19 @@
 	else
 		hwgroup->hwif = HWIF(hwgroup->drive);
 
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+#if !defined(CONFIG_DMA_NONPCI)
 	if (hwif->dma_base) {
 		(void) ide_release_dma(hwif);
+
 		hwif->dma_base = 0;
+		hwif->dma_master = 0;
+		hwif->dma_command = 0;
+		hwif->dma_vendor1 = 0;
+		hwif->dma_status = 0;
+		hwif->dma_vendor3 = 0;
+		hwif->dma_prdtable = 0;
 	}
-#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+#endif /* !(CONFIG_DMA_NONPCI) */
 
 	/*
 	 * Remove us from the kernel's knowledge
@@ -2343,49 +780,136 @@
 		kfree(gd->sizes);
 		kfree(gd->part);
 		if (gd->de_arr)
-			kfree (gd->de_arr);
+			kfree(gd->de_arr);
 		if (gd->flags)
-			kfree (gd->flags);
+			kfree(gd->flags);
 		kfree(gd);
 		hwif->gd = NULL;
 	}
-	old_hwif		= *hwif;
-	init_hwif_data (index);	/* restore hwif data to pristine status */
-	hwif->hwgroup		= old_hwif.hwgroup;
-	hwif->tuneproc		= old_hwif.tuneproc;
-	hwif->speedproc		= old_hwif.speedproc;
-	hwif->selectproc	= old_hwif.selectproc;
-	hwif->resetproc		= old_hwif.resetproc;
-	hwif->intrproc		= old_hwif.intrproc;
-	hwif->maskproc		= old_hwif.maskproc;
-	hwif->quirkproc		= old_hwif.quirkproc;
-	hwif->rwproc		= old_hwif.rwproc;
-	hwif->ideproc		= old_hwif.ideproc;
-	hwif->dmaproc		= old_hwif.dmaproc;
-	hwif->busproc		= old_hwif.busproc;
-	hwif->bus_state		= old_hwif.bus_state;
-	hwif->dma_base		= old_hwif.dma_base;
-	hwif->dma_extra		= old_hwif.dma_extra;
-	hwif->config_data	= old_hwif.config_data;
-	hwif->select_data	= old_hwif.select_data;
-	hwif->proc		= old_hwif.proc;
-#ifndef CONFIG_BLK_DEV_IDECS
-	hwif->irq		= old_hwif.irq;
-#endif /* CONFIG_BLK_DEV_IDECS */
-	hwif->major		= old_hwif.major;
-	hwif->chipset		= old_hwif.chipset;
-	hwif->autodma		= old_hwif.autodma;
-	hwif->udma_four		= old_hwif.udma_four;
+
+	old_hwif			= *hwif;
+	init_hwif_data(index);	/* restore hwif data to pristine status */
+	hwif->hwgroup			= old_hwif.hwgroup;
+
+	hwif->proc			= old_hwif.proc;
+
+	hwif->major			= old_hwif.major;
+//	hwif->index			= old_hwif.index;
+//	hwif->channel			= old_hwif.channel;
+	hwif->straight8			= old_hwif.straight8;
+	hwif->bus_state			= old_hwif.bus_state;
+
+	hwif->atapi_dma			= old_hwif.atapi_dma;
+	hwif->ultra_mask		= old_hwif.ultra_mask;
+	hwif->mwdma_mask		= old_hwif.mwdma_mask;
+	hwif->swdma_mask		= old_hwif.swdma_mask;
+
+	hwif->chipset			= old_hwif.chipset;
+
 #ifdef CONFIG_BLK_DEV_IDEPCI
-	hwif->pci_dev		= old_hwif.pci_dev;
-	hwif->pci_devid		= old_hwif.pci_devid;
+	hwif->pci_dev			= old_hwif.pci_dev;
+	hwif->cds			= old_hwif.cds;
 #endif /* CONFIG_BLK_DEV_IDEPCI */
-	hwif->straight8		= old_hwif.straight8;
-	hwif->hwif_data		= old_hwif.hwif_data;
+
+#if 0
+	hwif->hwifops			= old_hwif.hwifops;
+#else
+	hwif->identify			= old_hwif.identify;
+	hwif->tuneproc			= old_hwif.tuneproc;
+	hwif->speedproc			= old_hwif.speedproc;
+	hwif->selectproc		= old_hwif.selectproc;
+	hwif->reset_poll		= old_hwif.reset_poll;
+	hwif->pre_reset			= old_hwif.pre_reset;
+	hwif->resetproc			= old_hwif.resetproc;
+	hwif->intrproc			= old_hwif.intrproc;
+	hwif->maskproc			= old_hwif.maskproc;
+	hwif->quirkproc			= old_hwif.quirkproc;
+	hwif->busproc			= old_hwif.busproc;
+#endif
+
+#if 0
+	hwif->pioops			= old_hwif.pioops;
+#else
+	hwif->ata_input_data		= old_hwif.ata_input_data;
+	hwif->ata_output_data		= old_hwif.ata_output_data;
+	hwif->atapi_input_bytes		= old_hwif.atapi_input_bytes;
+	hwif->atapi_output_bytes	= old_hwif.atapi_output_bytes;
+#endif
+
+#if 0
+	hwif->dmaops			= old_hwif.dmaops;
+#else
+	hwif->ide_dma_read		= old_hwif.ide_dma_read;
+	hwif->ide_dma_write		= old_hwif.ide_dma_write;
+	hwif->ide_dma_begin		= old_hwif.ide_dma_begin;
+	hwif->ide_dma_end		= old_hwif.ide_dma_end;
+	hwif->ide_dma_check		= old_hwif.ide_dma_check;
+	hwif->ide_dma_on		= old_hwif.ide_dma_on;
+	hwif->ide_dma_off		= old_hwif.ide_dma_off;
+	hwif->ide_dma_off_quietly	= old_hwif.ide_dma_off_quietly;
+	hwif->ide_dma_test_irq		= old_hwif.ide_dma_test_irq;
+	hwif->ide_dma_host_on		= old_hwif.ide_dma_host_on;
+	hwif->ide_dma_host_off		= old_hwif.ide_dma_host_off;
+	hwif->ide_dma_bad_drive		= old_hwif.ide_dma_bad_drive;
+	hwif->ide_dma_good_drive	= old_hwif.ide_dma_good_drive;
+	hwif->ide_dma_count		= old_hwif.ide_dma_count;
+	hwif->ide_dma_verbose		= old_hwif.ide_dma_verbose;
+	hwif->ide_dma_retune		= old_hwif.ide_dma_retune;
+	hwif->ide_dma_lostirq		= old_hwif.ide_dma_lostirq;
+	hwif->ide_dma_timeout		= old_hwif.ide_dma_timeout;
+#endif
+
+#if 0
+	hwif->iops			= old_hwif.iops;
+#else
+	hwif->OUTB		= old_hwif.OUTB;
+	hwif->OUTW		= old_hwif.OUTW;
+	hwif->OUTL		= old_hwif.OUTL;
+	hwif->OUTSW		= old_hwif.OUTSW;
+	hwif->OUTSL		= old_hwif.OUTSL;
+
+	hwif->INB		= old_hwif.INB;
+	hwif->INW		= old_hwif.INW;
+	hwif->INL		= old_hwif.INL;
+	hwif->INSW		= old_hwif.INSW;
+	hwif->INSL		= old_hwif.INSL;
+#endif
+
+	hwif->mmio			= old_hwif.mmio;
+	hwif->rqsize			= old_hwif.rqsize;
+	hwif->addressing		= old_hwif.addressing;
+#ifndef CONFIG_BLK_DEV_IDECS
+	hwif->irq			= old_hwif.irq;
+#endif /* CONFIG_BLK_DEV_IDECS */
+	hwif->initializing		= old_hwif.initializing;
+
+	hwif->dma_base			= old_hwif.dma_base;
+	hwif->dma_master		= old_hwif.dma_master;
+	hwif->dma_command		= old_hwif.dma_command;
+	hwif->dma_vendor1		= old_hwif.dma_vendor1;
+	hwif->dma_status		= old_hwif.dma_status;
+	hwif->dma_vendor3		= old_hwif.dma_vendor3;
+	hwif->dma_prdtable		= old_hwif.dma_prdtable;
+
+	hwif->dma_extra			= old_hwif.dma_extra;
+	hwif->config_data		= old_hwif.config_data;
+	hwif->select_data		= old_hwif.select_data;
+	hwif->autodma			= old_hwif.autodma;
+	hwif->udma_four			= old_hwif.udma_four;
+	hwif->no_dsc			= old_hwif.no_dsc;
+
+	hwif->hwif_data			= old_hwif.hwif_data;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return 0;
+
 abort:
-	restore_flags(flags);	/* all CPUs */
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return 1;
+	
 }
 
+EXPORT_SYMBOL(ide_unregister);
+
 /*
  * Setup hw_regs_t structure described by parameters.  You
  * may set up the hw structure yourself OR use this routine to
@@ -2394,7 +918,11 @@
 void ide_setup_ports (	hw_regs_t *hw,
 			ide_ioreg_t base, int *offsets,
 			ide_ioreg_t ctrl, ide_ioreg_t intr,
-			ide_ack_intr_t *ack_intr, int irq)
+			ide_ack_intr_t *ack_intr,
+/*
+ *			ide_io_ops_t *iops,
+ */
+			int irq)
 {
 	int i;
 
@@ -2420,8 +948,13 @@
 	hw->irq = irq;
 	hw->dma = NO_DMA;
 	hw->ack_intr = ack_intr;
+/*
+ *	hw->iops = iops;
+ */
 }
 
+EXPORT_SYMBOL(ide_setup_ports);
+
 /*
  * Register an IDE interface, specifing exactly the registers etc
  * Set init=1 iff calling before probes have taken place.
@@ -2459,11 +992,11 @@
 	hwif->chipset = hw->chipset;
 
 	if (!initializing) {
-		ide_probe_module();
+		ide_probe_module(1);
 #ifdef CONFIG_PROC_FS
 		create_proc_ide_interfaces();
 #endif
-		ide_driver_module();
+		ide_driver_module(1);
 	}
 
 	if (hwifp)
@@ -2472,6 +1005,8 @@
 	return (initializing || hwif->present) ? index : -1;
 }
 
+EXPORT_SYMBOL(ide_register_hw);
+
 /*
  * Compatability function with existing drivers.  If you want
  * something different, use the function above.
@@ -2484,6 +1019,8 @@
 	return ide_register_hw(&hw, NULL);
 }
 
+EXPORT_SYMBOL(ide_register);
+
 void ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
 {
 	ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
@@ -2495,12 +1032,18 @@
 	memset(setting, 0, sizeof(*setting));
 	if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
 		goto abort;
-	strcpy(setting->name, name);		setting->rw = rw;
-	setting->read_ioctl = read_ioctl;	setting->write_ioctl = write_ioctl;
-	setting->data_type = data_type;		setting->min = min;
-	setting->max = max;			setting->mul_factor = mul_factor;
-	setting->div_factor = div_factor;	setting->data = data;
-	setting->set = set;			setting->next = *p;
+	strcpy(setting->name, name);
+	setting->rw = rw;
+	setting->read_ioctl = read_ioctl;
+	setting->write_ioctl = write_ioctl;
+	setting->data_type = data_type;
+	setting->min = min;
+	setting->max = max;
+	setting->mul_factor = mul_factor;
+	setting->div_factor = div_factor;
+	setting->data = data;
+	setting->set = set;
+	setting->next = *p;
 	if (drive->driver)
 		setting->auto_remove = 1;
 	*p = setting;
@@ -2510,6 +1053,8 @@
 		kfree(setting);
 }
 
+EXPORT_SYMBOL(ide_add_setting);
+
 void ide_remove_setting (ide_drive_t *drive, char *name)
 {
 	ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting;
@@ -2523,6 +1068,8 @@
 	kfree(setting);
 }
 
+EXPORT_SYMBOL(ide_remove_setting);
+
 static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd)
 {
 	ide_settings_t *setting = drive->settings;
@@ -2595,19 +1142,20 @@
 	while (hwgroup->busy) {
 		unsigned long lflags;
 		spin_unlock_irq(&io_request_lock);
-		__save_flags(lflags);	/* local CPU only */
-		__sti();		/* local CPU only; needed for jiffies */
-		if (0 < (signed long)(jiffies - timeout)) {
-			__restore_flags(lflags);	/* local CPU only */
-			printk("%s: channel busy\n", drive->name);
+		local_irq_set(lflags);
+		if (time_after(jiffies, timeout)) {
+			local_irq_restore(lflags);
+			printk(KERN_ERR "%s: channel busy\n", drive->name);
 			return -EBUSY;
 		}
-		__restore_flags(lflags);	/* local CPU only */
+		local_irq_restore(lflags);
 		spin_lock_irq(&io_request_lock);
 	}
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_spin_wait_hwgroup);
+
 /*
  * FIXME:  This should be changed to enqueue a special request
  * to the driver to change settings, and then wait on a sema for completion.
@@ -2648,6 +1196,8 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_write_setting);
+
 static int set_io_32bit(ide_drive_t *drive, int arg)
 {
 	drive->io_32bit = arg;
@@ -2662,10 +1212,15 @@
 {
 	if (!drive->driver || !DRIVER(drive)->supports_dma)
 		return -EPERM;
-	if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc)
+	if (!drive->id || !(drive->id->capability & 1))
 		return -EPERM;
-	if (HWIF(drive)->dmaproc(arg ? ide_dma_on : ide_dma_off, drive))
-		return -EIO;
+	if (HWIF(drive)->ide_dma_check == NULL)
+		return -EPERM;
+	if (arg) {
+		if (HWIF(drive)->ide_dma_on(drive)) return -EIO;
+	} else {
+		if (HWIF(drive)->ide_dma_off(drive)) return -EIO;
+	}
 	return 0;
 }
 
@@ -2678,9 +1233,39 @@
 	if (drive->special.b.set_tune)
 		return -EBUSY;
 	ide_init_drive_cmd(&rq);
-	drive->tune_req = (byte) arg;
+	drive->tune_req = (u8) arg;
 	drive->special.b.set_tune = 1;
-	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
+	(void) ide_do_drive_cmd(drive, &rq, ide_wait);
+	return 0;
+}
+
+static int set_xfer_rate (ide_drive_t *drive, int arg)
+{
+	int err = ide_wait_cmd(drive,
+			WIN_SETFEATURES, (u8) arg,
+			SETFEATURES_XFER, 0, NULL);
+
+	if (!err && arg) {
+		ide_set_xfer_rate(drive, (u8) arg);
+		ide_driveid_update(drive);
+	}
+	return err;
+}
+
+int ide_atapi_to_scsi (ide_drive_t *drive, int arg)
+{
+	if (drive->media == ide_disk) {
+		drive->scsi = 0;
+		return 0;
+	}
+	if (drive->driver != NULL) {
+		if (DRIVER(drive)->cleanup(drive)) {
+			drive->scsi = 0;
+			return 0;
+		}
+	}
+	drive->scsi = (u8) arg;
+	ide_attach_drive(drive);
 	return 0;
 }
 
@@ -2696,37 +1281,11 @@
 	ide_add_setting(drive,	"slow",			SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,		1,		&drive->slow,			NULL);
 	ide_add_setting(drive,	"unmaskirq",		drive->no_unmask ? SETTING_READ : SETTING_RW,	HDIO_GET_UNMASKINTR,	HDIO_SET_UNMASKINTR,	TYPE_BYTE,	0,	1,				1,		1,		&drive->unmask,			NULL);
 	ide_add_setting(drive,	"using_dma",		SETTING_RW,					HDIO_GET_DMA,		HDIO_SET_DMA,		TYPE_BYTE,	0,	1,				1,		1,		&drive->using_dma,		set_using_dma);
-	ide_add_setting(drive,	"ide_scsi",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,		1,		&drive->scsi,			NULL);
-	ide_add_setting(drive,	"init_speed",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	69,				1,		1,		&drive->init_speed,		NULL);
-	ide_add_setting(drive,	"current_speed",	SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	69,				1,		1,		&drive->current_speed,		NULL);
+	ide_add_setting(drive,	"init_speed",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->init_speed,		NULL);
+	ide_add_setting(drive,	"current_speed",	SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->current_speed,		set_xfer_rate);
 	ide_add_setting(drive,	"number",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	3,				1,		1,		&drive->dn,			NULL);
-}
-
-int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf)
-{
-	struct request rq;
-	byte buffer[4];
-
-	if (!buf)
-		buf = buffer;
-	memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);
-	ide_init_drive_cmd(&rq);
-	rq.buffer = buf;
-	*buf++ = cmd;
-	*buf++ = nsect;
-	*buf++ = feature;
-	*buf++ = sectors;
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
-}
-
-int ide_wait_cmd_task (ide_drive_t *drive, byte *buf)
-{
-	struct request rq;
-
-	ide_init_drive_cmd(&rq);
-	rq.cmd = IDE_DRIVE_TASK;
-	rq.buffer = buf;
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
+	if (drive->media != ide_disk)
+		ide_add_setting(drive,	"ide-scsi",		SETTING_RW,					-1,		HDIO_SET_IDE_SCSI,		TYPE_BYTE,	0,	1,				1,		1,		&drive->scsi,			ide_atapi_to_scsi);
 }
 
 /*
@@ -2747,19 +1306,53 @@
 #endif /* CONFIG_BLK_DEV_IDECS */
 }
 
+EXPORT_SYMBOL(ide_delay_50ms);
+
 int system_bus_clock (void)
 {
 	return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));
 }
 
-int ide_reinit_drive (ide_drive_t *drive)
+EXPORT_SYMBOL(system_bus_clock);
+
+int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
+{
+	if (!drive->present || drive->busy || drive->usage || drive->dead)
+		goto abort;
+	if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+		goto abort;
+	strncpy(drive->driver_req, driver, 9);
+	ide_driver_module(0);
+	drive->driver_req[0] = 0;
+	ide_driver_module(0);
+	if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver))
+		return 0;
+abort:
+	return 1;
+}
+
+EXPORT_SYMBOL(ide_replace_subdriver);
+
+int ide_attach_drive (ide_drive_t *drive)
 {
+	/* Someone unplugged the device on us */
+	if(drive->dead)
+		return 1;
+		
+#ifdef CONFIG_BLK_DEV_IDESCSI
+	if (drive->scsi) {
+		extern int idescsi_attach(ide_drive_t *drive);
+		if (idescsi_attach(drive))
+			return 0;
+	}
+#endif /* CONFIG_BLK_DEV_IDESCSI */
+
 	switch (drive->media) {
 #ifdef CONFIG_BLK_DEV_IDECD
 		case ide_cdrom:
 		{
-			extern int ide_cdrom_reinit(ide_drive_t *drive);
-			if (ide_cdrom_reinit(drive))
+			extern int ide_cdrom_attach(ide_drive_t *drive);
+			if (ide_cdrom_attach(drive))
 				return 1;
 			break;
 		}
@@ -2767,8 +1360,8 @@
 #ifdef CONFIG_BLK_DEV_IDEDISK
 		case ide_disk:
 		{
-			extern int idedisk_reinit(ide_drive_t *drive);
-			if (idedisk_reinit(drive))
+			extern int idedisk_attach(ide_drive_t *drive);
+			if (idedisk_attach(drive))
 				return 1;
 			break;
 		}
@@ -2776,8 +1369,8 @@
 #ifdef CONFIG_BLK_DEV_IDEFLOPPY
 		case ide_floppy:
 		{
-			extern int idefloppy_reinit(ide_drive_t *drive);
-			if (idefloppy_reinit(drive))
+			extern int idefloppy_attach(ide_drive_t *drive);
+			if (idefloppy_attach(drive))
 				return 1;
 			break;
 		}
@@ -2785,28 +1378,20 @@
 #ifdef CONFIG_BLK_DEV_IDETAPE
 		case ide_tape:
 		{
-			extern int idetape_reinit(ide_drive_t *drive);
-			if (idetape_reinit(drive))
+			extern int idetape_attach(ide_drive_t *drive);
+			if (idetape_attach(drive))
 				return 1;
 			break;
 		}
 #endif /* CONFIG_BLK_DEV_IDETAPE */
-#ifdef CONFIG_BLK_DEV_IDESCSI
-/*
- *              {
- *                      extern int idescsi_reinit(ide_drive_t *drive);
- *                      if (idescsi_reinit(drive))
- *                              return 1;
- *                      break;
- * }
- */
-#endif /* CONFIG_BLK_DEV_IDESCSI */
 		default:
 			return 1;
 	}
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_attach_drive);
+
 static int ide_ioctl (struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg)
 {
@@ -2838,11 +1423,11 @@
 		case HDIO_GETGEO:
 		{
 			struct hd_geometry *loc = (struct hd_geometry *) arg;
-			unsigned short bios_cyl = drive->bios_cyl; /* truncate */
+			u16 bios_cyl = drive->bios_cyl; /* truncate */
 			if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
-			if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
-			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
+			if (put_user(drive->bios_head, (u8 *) &loc->heads)) return -EFAULT;
+			if (put_user(drive->bios_sect, (u8 *) &loc->sectors)) return -EFAULT;
+			if (put_user(bios_cyl, (u16 *) &loc->cylinders)) return -EFAULT;
 			if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
 				(unsigned long *) &loc->start)) return -EFAULT;
 			return 0;
@@ -2852,8 +1437,8 @@
 		{
 			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
 			if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
-			if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(drive->bios_head, (u8 *) &loc->heads)) return -EFAULT;
+			if (put_user(drive->bios_sect, (u8 *) &loc->sectors)) return -EFAULT;
 			if (put_user(drive->bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
 			if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
 				(unsigned long *) &loc->start)) return -EFAULT;
@@ -2864,8 +1449,8 @@
 		{
 			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
 			if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
-			if (put_user(drive->head, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(drive->sect, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(drive->head, (u8 *) &loc->heads)) return -EFAULT;
+			if (put_user(drive->sect, (u8 *) &loc->sectors)) return -EFAULT;
 			if (put_user(drive->cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
 			if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
 				(unsigned long *) &loc->start)) return -EFAULT;
@@ -2918,68 +1503,15 @@
 #endif /* CONFIG_IDE_TASK_IOCTL */
 
 		case HDIO_DRIVE_CMD:
-		{
-			byte args[4], *argbuf = args;
-			byte xfer_rate = 0;
-			int argsize = 4;
-			ide_task_t tfargs;
-
 			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
 				return -EACCES;
-			if (NULL == (void *) arg)
-				return ide_do_drive_cmd(drive, &rq, ide_wait);
-			if (copy_from_user(args, (void *)arg, 4))
-				return -EFAULT;
-
-			tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
-			tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
-			tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
-			tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
-			tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
-			tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
-			tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
-
-			if (args[3]) {
-				argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
-				argbuf = kmalloc(argsize, GFP_KERNEL);
-				if (argbuf == NULL)
-					return -ENOMEM;
-				memcpy(argbuf, args, 4);
-			}
-
-			if (set_transfer(drive, &tfargs)) {
-				xfer_rate = args[1];
-				if (ide_ata66_check(drive, &tfargs))
-					goto abort;
-			}
-
-			err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
+			return ide_cmd_ioctl(drive, inode, file, cmd, arg);
 
-			if (!err && xfer_rate) {
-				/* active-retuning-calls future */
-				if ((HWIF(drive)->speedproc) != NULL)
-					HWIF(drive)->speedproc(drive, xfer_rate);
-				ide_driveid_update(drive);
-			}
-		abort:
-			if (copy_to_user((void *)arg, argbuf, argsize))
-				err = -EFAULT;
-			if (argsize > 4)
-				kfree(argbuf);
-			return err;
-		}
 		case HDIO_DRIVE_TASK:
-		{
-			byte args[7], *argbuf = args;
-			int argsize = 7;
-			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES;
-			if (copy_from_user(args, (void *)arg, 7))
-				return -EFAULT;
-			err = ide_wait_cmd_task(drive, argbuf);
-			if (copy_to_user((void *)arg, argbuf, argsize))
-				err = -EFAULT;
-			return err;
-		}
+			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+				return -EACCES;
+			return ide_task_ioctl(drive, inode, file, cmd, arg);
+
 		case HDIO_SCAN_HWIF:
 		{
 			int args[3];
@@ -3011,18 +1543,15 @@
 		case HDIO_DRIVE_RESET:
 		{
 			unsigned long flags;
-			ide_hwgroup_t *hwgroup = HWGROUP(drive);
-
 			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
 #if 1
 			spin_lock_irqsave(&io_request_lock, flags);
-			if (hwgroup->handler != NULL) {
-				printk("%s: ide_set_handler: handler not null; %p\n", drive->name, hwgroup->handler);
-				(void) hwgroup->handler(drive);
-//				hwgroup->handler = NULL;
-//				hwgroup->expiry	= NULL;
-				hwgroup->timer.expires = jiffies + 0;;
-				del_timer(&hwgroup->timer);
+			if ( HWGROUP(drive)->handler != NULL) {
+				printk(KERN_ERR "%s: ide_set_handler: handler not null; %p\n", drive->name, HWGROUP(drive)->handler);
+				(void) HWGROUP(drive)->handler(drive);
+//				HWGROUP(drive)->handler = NULL;
+				HWGROUP(drive)->expiry	= NULL;
+				del_timer(&HWGROUP(drive)->timer);
 			}
 			spin_unlock_irqrestore(&io_request_lock, flags);
 
@@ -3085,33 +1614,6 @@
 	return 0;
 }
 
-void ide_fixstring (byte *s, const int bytecount, const int byteswap)
-{
-	byte *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */
-
-	if (byteswap) {
-		/* convert from big-endian to host byte order */
-		for (p = end ; p != s;) {
-			unsigned short *pp = (unsigned short *) (p -= 2);
-			*pp = ntohs(*pp);
-		}
-	}
-
-	/* strip leading blanks */
-	while (s != end && *s == ' ')
-		++s;
-
-	/* compress internal blanks and strip trailing blanks */
-	while (s != end && *s) {
-		if (*s++ != ' ' || (s != end && *s && *s != ' '))
-			*p++ = *(s-1);
-	}
-
-	/* wipe out trailing garbage */
-	while (p != end)
-		*p++ = '\0';
-}
-
 /*
  * stridx() returns the offset of c within s,
  * or -1 if c is '\0' or not found within s.
@@ -3274,7 +1776,7 @@
 	    strncmp(s,"hd",2))		/* hdx= & hdxlun= */
 		return 0;
 
-	printk("ide_setup: %s", s);
+	printk(KERN_INFO "ide_setup: %s", s);
 	init_ide_data ();
 
 #ifdef CONFIG_BLK_DEV_IDEDOUBLER
@@ -3288,7 +1790,7 @@
 #endif /* CONFIG_BLK_DEV_IDEDOUBLER */
 
 	if (!strcmp(s, "ide=nodma")) {
-		printk("IDE: Prevented DMA\n");
+		printk(" : Prevented DMA\n");
 		noautodma = 1;
 		return 1;
 	}
@@ -3418,7 +1920,7 @@
 		const char *ide_words[] = {
 			"noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66",
 			"minus8", "minus9", "minus10",
-			"four", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", "nohighio", NULL };
+			"four", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL };
 		hw = s[3] - '0';
 		hwif = &ide_hwifs[hw];
 		i = match_parm(&s[4], ide_words, vals, 3);
@@ -3437,10 +1939,6 @@
 		}
 
 		switch (i) {
-			case -19: /* nohighio */
-				hwif->no_highio = 1;
-				printk("%s: disabled high i/o capability\n", hwif->name);
-				goto done;
 #ifdef CONFIG_BLK_DEV_PDC4030
 			case -18: /* "dc4030" */
 			{
@@ -3580,21 +2078,12 @@
  */
 static void __init probe_for_hwifs (void)
 {
-#ifdef CONFIG_PCI
+#ifdef CONFIG_BLK_DEV_IDEPCI
 	if (pci_present())
 	{
-#ifdef CONFIG_BLK_DEV_IDEPCI
 		ide_scan_pcibus(ide_scan_direction);
-#else
-#ifdef CONFIG_BLK_DEV_RZ1000
-		{
-			extern void ide_probe_for_rz100x(void);
-			ide_probe_for_rz100x();
-		}
-#endif /* CONFIG_BLK_DEV_RZ1000 */
-#endif /* CONFIG_BLK_DEV_IDEPCI */
 	}
-#endif /* CONFIG_PCI */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
 
 #ifdef CONFIG_ETRAX_IDE
 	{
@@ -3676,39 +2165,8 @@
 #endif /* CONFIG_BLK_DEV_ISAPNP */
 }
 
-void __init ide_init_builtin_drivers (void)
+void __init ide_init_builtin_subdrivers (void)
 {
-	/*
-	 * Probe for special PCI and other "known" interface chipsets
-	 */
-	probe_for_hwifs ();
-
-#ifdef CONFIG_BLK_DEV_IDE
-#if defined(__mc68000__) || defined(CONFIG_APUS)
-	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
-		ide_get_lock(&ide_lock, NULL, NULL);	/* for atari only */
-		disable_irq(ide_hwifs[0].irq);	/* disable_irq_nosync ?? */
-//		disable_irq_nosync(ide_hwifs[0].irq);
-	}
-#endif /* __mc68000__ || CONFIG_APUS */
-
-	(void) ideprobe_init();
-
-#if defined(__mc68000__) || defined(CONFIG_APUS)
-	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
-		enable_irq(ide_hwifs[0].irq);
-		ide_release_lock(&ide_lock);	/* for atari only */
-	}
-#endif /* __mc68000__ || CONFIG_APUS */
-#endif /* CONFIG_BLK_DEV_IDE */
-
-#ifdef CONFIG_PROC_FS
-	proc_ide_create();
-#endif
-
-	/*
-	 * Attempt to match drivers for the available drives
-	 */
 #ifdef CONFIG_BLK_DEV_IDEDISK
 	(void) idedisk_init();
 #endif /* CONFIG_BLK_DEV_IDEDISK */
@@ -3730,32 +2188,131 @@
 #endif /* CONFIG_BLK_DEV_IDESCSI */
 }
 
+#ifndef CLASSIC_BUILTINS_METHOD
+#  ifndef DIRECT_HWIF_PROBE_ATTACH_METHOD
+#    ifdef FAKE_CLASSIC_ATTACH_METHOD
+/*
+ * Attempt to match drivers for the available drives
+ */
+void ide_attach_devices (void)
+{
+	ide_hwif_t *hwif;
+	ide_drive_t *drive;
+	int i, unit;
+
+	for (i = 0; i < MAX_HWIFS; i++) {
+		hwif = &ide_hwifs[i];
+		if (!hwif->present)
+			continue;
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			drive = &hwif->drives[unit];
+			if (drive->present && !drive->dead)
+				ide_attach_drive(drive);
+		}
+	}
+}
+#    endif /* FAKE_CLASSIC_ATTACH_METHOD */
+#  endif /* DIRECT_HWIF_PROBE_ATTACH_METHOD */
+#endif /* CLASSIC_BUILTINS_METHOD */
+
+void __init ide_init_builtin_drivers (void)
+{
+	/*
+	 * Probe for special PCI and other "known" interface chipsets
+	 */
+	probe_for_hwifs ();
+
+#ifdef CONFIG_BLK_DEV_IDE
+	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
+		ide_get_lock(&ide_intr_lock, NULL, NULL); /* for atari only */
+
+	(void) ideprobe_init();
+
+	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
+		ide_release_lock(&ide_intr_lock);	/* for atari only */
+#endif /* CONFIG_BLK_DEV_IDE */
+
+#ifdef CONFIG_PROC_FS
+	proc_ide_create();
+#endif
+
+#ifdef CLASSIC_BUILTINS_METHOD
+	ide_init_builtin_subdrivers();
+#else /* ! CLASSIC_BUILTINS_METHOD */
+#  ifndef DIRECT_HWIF_PROBE_ATTACH_METHOD
+#    ifdef FAKE_CLASSIC_ATTACH_METHOD
+	ide_attach_devices();
+#    endif /* FAKE_CLASSIC_ATTACH_METHOD */
+#  endif /* DIRECT_HWIF_PROBE_ATTACH_METHOD */
+#endif /* CLASSIC_BUILTINS_METHOD */
+}
+
+/*
+ *	Actually unregister the subdriver. Called with the
+ *	request lock dropped.
+ */
+ 
 static int default_cleanup (ide_drive_t *drive)
 {
 	return ide_unregister_subdriver(drive);
 }
 
+/*
+ *	Check if we can unregister the subdriver. Called with the
+ *	request lock held.
+ */
+ 
+static int default_shutdown(ide_drive_t *drive)
+{
+	if (drive->usage || drive->busy ||
+	    drive->driver == NULL || DRIVER(drive)->busy) {
+		return 1;
+	}
+	drive->dead = 1;
+	return 0;
+}
+
 static int default_standby (ide_drive_t *drive)
 {
 	return 0;
 }
 
+static int default_suspend (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int default_resume (ide_drive_t *drive)
+{
+	return 0;
+}
+
 static int default_flushcache (ide_drive_t *drive)
 {
 	return 0;
 }
 
-static ide_startstop_t default_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t default_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	ide_end_request(0, HWGROUP(drive));
+	ide_end_request(drive, 0);
 	return ide_stopped;
 }
- 
-static void default_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
+
+static int default_end_request (ide_drive_t *drive, int uptodate)
 {
-	ide_end_request(uptodate, hwgroup);
+	return ide_end_request(drive, uptodate);
 }
-  
+
+static u8 default_sense (ide_drive_t *drive, const char *msg, u8 stat)
+{
+	return ide_dump_status(drive, msg, stat);
+}
+
+static ide_startstop_t default_error (ide_drive_t *drive, const char *msg, u8 stat)
+{
+	return ide_error(drive, msg, stat);
+}
+
 static int default_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file,
 			  unsigned int cmd, unsigned long arg)
 {
@@ -3795,9 +2352,15 @@
 	return ide_stopped;
 }
 
-static int default_reinit (ide_drive_t *drive)
+static int default_init (void)
+{
+	return 0;
+}
+
+static int default_attach (ide_drive_t *drive)
 {
-	printk(KERN_ERR "%s: does not support hotswap of device class !\n", drive->name);
+	printk(KERN_ERR "%s: does not support hotswap of device class !\n",
+		drive->name);
 
 	return 0;
 }
@@ -3807,10 +2370,15 @@
 	ide_driver_t *d = drive->driver;
 
 	if (d->cleanup == NULL)		d->cleanup = default_cleanup;
+	if (d->shutdown == NULL)	d->shutdown = default_shutdown;
 	if (d->standby == NULL)		d->standby = default_standby;
+	if (d->suspend == NULL)		d->suspend = default_suspend;
+	if (d->resume == NULL)		d->resume = default_resume;
 	if (d->flushcache == NULL)	d->flushcache = default_flushcache;
 	if (d->do_request == NULL)	d->do_request = default_do_request;
 	if (d->end_request == NULL)	d->end_request = default_end_request;
+	if (d->sense == NULL)		d->sense = default_sense;
+	if (d->error == NULL)		d->error = default_error;
 	if (d->ioctl == NULL)		d->ioctl = default_ioctl;
 	if (d->open == NULL)		d->open = default_open;
 	if (d->release == NULL)		d->release = default_release;
@@ -3818,10 +2386,11 @@
 	if (d->pre_reset == NULL)	d->pre_reset = default_pre_reset;
 	if (d->capacity == NULL)	d->capacity = default_capacity;
 	if (d->special == NULL)		d->special = default_special;
-	if (d->reinit == NULL)		d->reinit = default_reinit;
+	if (d->init == NULL)		d->init = default_init;
+	if (d->attach == NULL)		d->attach = default_attach;
 }
 
-ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n)
+ide_drive_t *ide_scan_devices (u8 media, const char *name, ide_driver_t *driver, int n)
 {
 	unsigned int unit, index, i;
 
@@ -3834,37 +2403,34 @@
 			char *req = drive->driver_req;
 			if (*req && !strstr(name, req))
 				continue;
-			if (drive->present && drive->media == media && drive->driver == driver && ++i > n)
+			if (drive->present && drive->media == media &&
+			    drive->driver == driver && ++i > n)
 				return drive;
 		}
 	}
 	return NULL;
 }
 
+EXPORT_SYMBOL(ide_scan_devices);
+
 int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version)
 {
 	unsigned long flags;
 	
-	save_flags(flags);		/* all CPUs */
-	cli();				/* all CPUs */
-	if (version != IDE_SUBDRIVER_VERSION || !drive->present || drive->driver != NULL || drive->busy || drive->usage) {
-		restore_flags(flags);	/* all CPUs */
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (version != IDE_SUBDRIVER_VERSION || !drive->present ||
+	    drive->driver != NULL || drive->busy || drive->usage) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		return 1;
 	}
 	drive->driver = driver;
 	setup_driver_defaults(drive);
-	restore_flags(flags);		/* all CPUs */
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	if (drive->autotune != 2) {
-		if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) {
-			/*
-			 * Force DMAing for the beginning of the check.
-			 * Some chipsets appear to do interesting things,
-			 * if not checked and cleared.
-			 *   PARANOIA!!!
-			 */
-			(void) (HWIF(drive)->dmaproc(ide_dma_off_quietly, drive));
-			(void) (HWIF(drive)->dmaproc(ide_dma_check, drive));
-		}
+		/* DMA timings and setup moved to ide-probe.c */
+		if (!driver->supports_dma && HWIF(drive)->ide_dma_off_quietly)
+//			HWIF(drive)->ide_dma_off_quietly(drive);
+			HWIF(drive)->ide_dma_off(drive);
 		drive->dsc_overlap = (drive->next != drive && driver->supports_dsc_overlap);
 		drive->nice1 = 1;
 	}
@@ -3877,14 +2443,16 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_register_subdriver);
+
 int ide_unregister_subdriver (ide_drive_t *drive)
 {
 	unsigned long flags;
 	
-	save_flags(flags);		/* all CPUs */
-	cli();				/* all CPUs */
-	if (drive->usage || drive->busy || drive->driver == NULL || DRIVER(drive)->busy) {
-		restore_flags(flags);	/* all CPUs */
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (drive->usage || drive->busy ||
+	    drive->driver == NULL || DRIVER(drive)->busy) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		return 1;
 	}
 #if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) && defined(MODULE)
@@ -3896,10 +2464,12 @@
 #endif
 	auto_remove_settings(drive);
 	drive->driver = NULL;
-	restore_flags(flags);		/* all CPUs */
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_unregister_subdriver);
+
 int ide_register_module (ide_module_t *module)
 {
 	ide_module_t *p = ide_modules;
@@ -3911,10 +2481,12 @@
 	}
 	module->next = ide_modules;
 	ide_modules = module;
-	revalidate_drives();
+	revalidate_drives(1);
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_register_module);
+
 void ide_unregister_module (ide_module_t *module)
 {
 	ide_module_t **p;
@@ -3924,6 +2496,8 @@
 		*p = (*p)->next;
 }
 
+EXPORT_SYMBOL(ide_unregister_module);
+
 struct block_device_operations ide_fops[] = {{
 	owner:			THIS_MODULE,
 	open:			ide_open,
@@ -3933,10 +2507,34 @@
 	revalidate:		ide_revalidate_disk
 }};
 
-EXPORT_SYMBOL(ide_hwifs);
-EXPORT_SYMBOL(ide_register_module);
-EXPORT_SYMBOL(ide_unregister_module);
-EXPORT_SYMBOL(ide_spin_wait_hwgroup);
+EXPORT_SYMBOL(ide_fops);
+
+/*
+ * ide_geninit() is called exactly *once* for each interface.
+ */
+void ide_geninit (ide_hwif_t *hwif)
+{
+	unsigned int unit;
+	struct gendisk *gd = hwif->gd;
+
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		ide_drive_t *drive = &hwif->drives[unit];
+
+		if (!drive->present)
+			continue;
+		if (drive->media!=ide_disk && drive->media!=ide_floppy)
+			continue;
+		register_disk(gd,MKDEV(hwif->major,unit<<PARTN_BITS),
+#ifdef CONFIG_BLK_DEV_ISAPNP
+			(drive->forced_geom && drive->noprobe) ? 1 :
+#endif /* CONFIG_BLK_DEV_ISAPNP */
+			1<<PARTN_BITS, ide_fops,
+			current_capacity(drive));
+	}
+}
+
+EXPORT_SYMBOL(ide_geninit);
+
 
 /*
  * Probe module
@@ -3944,65 +2542,7 @@
 devfs_handle_t ide_devfs_handle;
 
 EXPORT_SYMBOL(ide_probe);
-EXPORT_SYMBOL(drive_is_flashcard);
-EXPORT_SYMBOL(ide_timer_expiry);
-EXPORT_SYMBOL(ide_intr);
-EXPORT_SYMBOL(ide_fops);
-EXPORT_SYMBOL(ide_get_queue);
-EXPORT_SYMBOL(ide_add_generic_settings);
 EXPORT_SYMBOL(ide_devfs_handle);
-EXPORT_SYMBOL(do_ide_request);
-/*
- * Driver module
- */
-EXPORT_SYMBOL(ide_scan_devices);
-EXPORT_SYMBOL(ide_register_subdriver);
-EXPORT_SYMBOL(ide_unregister_subdriver);
-EXPORT_SYMBOL(ide_replace_subdriver);
-EXPORT_SYMBOL(ide_input_data);
-EXPORT_SYMBOL(ide_output_data);
-EXPORT_SYMBOL(atapi_input_bytes);
-EXPORT_SYMBOL(atapi_output_bytes);
-EXPORT_SYMBOL(drive_is_ready);
-EXPORT_SYMBOL(ide_set_handler);
-EXPORT_SYMBOL(ide_dump_status);
-EXPORT_SYMBOL(ide_error);
-EXPORT_SYMBOL(ide_fixstring);
-EXPORT_SYMBOL(ide_wait_stat);
-EXPORT_SYMBOL(ide_do_reset);
-EXPORT_SYMBOL(restart_request);
-EXPORT_SYMBOL(ide_init_drive_cmd);
-EXPORT_SYMBOL(ide_do_drive_cmd);
-EXPORT_SYMBOL(ide_end_drive_cmd);
-EXPORT_SYMBOL(ide_end_request);
-EXPORT_SYMBOL(ide_revalidate_disk);
-EXPORT_SYMBOL(ide_cmd);
-EXPORT_SYMBOL(ide_wait_cmd);
-EXPORT_SYMBOL(ide_wait_cmd_task);
-EXPORT_SYMBOL(ide_delay_50ms);
-EXPORT_SYMBOL(ide_stall_queue);
-#ifdef CONFIG_PROC_FS
-EXPORT_SYMBOL(ide_add_proc_entries);
-EXPORT_SYMBOL(ide_remove_proc_entries);
-EXPORT_SYMBOL(proc_ide_read_geometry);
-EXPORT_SYMBOL(create_proc_ide_interfaces);
-EXPORT_SYMBOL(recreate_proc_ide_device);
-EXPORT_SYMBOL(destroy_proc_ide_device);
-#endif
-EXPORT_SYMBOL(ide_add_setting);
-EXPORT_SYMBOL(ide_remove_setting);
-
-EXPORT_SYMBOL(ide_register_hw);
-EXPORT_SYMBOL(ide_register);
-EXPORT_SYMBOL(ide_unregister);
-EXPORT_SYMBOL(ide_setup_ports);
-EXPORT_SYMBOL(hwif_unregister);
-EXPORT_SYMBOL(get_info_ptr);
-EXPORT_SYMBOL(current_capacity);
-
-EXPORT_SYMBOL(system_bus_clock);
-
-EXPORT_SYMBOL(ide_reinit_drive);
 
 static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x)
 {
@@ -4019,7 +2559,7 @@
 			return NOTIFY_DONE;
 	}
 
-	printk("flushing ide devices: ");
+	printk(KERN_INFO "flushing ide devices: ");
 
 	for (i = 0; i < MAX_HWIFS; i++) {
 		hwif = &ide_hwifs[i];
@@ -4036,8 +2576,11 @@
 				if (drive->driver != NULL && DRIVER(drive)->standby(drive))
 				continue;
 
-			if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+			if (drive->driver != NULL)
+			{
+				DRIVER(drive)->cleanup(drive);
 				continue;
+			}
 		}
 	}
 	printk("\n");
@@ -4060,12 +2603,16 @@
 
 	if (!banner_printed) {
 		printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
-		ide_devfs_handle = devfs_mk_dir (NULL, "ide", NULL);
+		ide_devfs_handle = devfs_mk_dir(NULL, "ide", NULL);
 		system_bus_speed = ide_system_bus_speed();
 		banner_printed = 1;
 	}
 
-	init_ide_data ();
+	init_ide_data();
+
+#ifndef CLASSIC_BUILTINS_METHOD
+	ide_init_builtin_subdrivers();
+#endif /* CLASSIC_BUILTINS_METHOD */
 
 	initializing = 1;
 	ide_init_builtin_drivers();
@@ -4113,10 +2660,10 @@
 	unregister_reboot_notifier(&ide_notifier);
 	for (index = 0; index < MAX_HWIFS; ++index) {
 		ide_unregister(index);
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+#if !defined(CONFIG_DMA_NONPCI)
 		if (ide_hwifs[index].dma_base)
 			(void) ide_release_dma(&ide_hwifs[index]);
-#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+#endif /* !(CONFIG_DMA_NONPCI) */
 	}
 
 #ifdef CONFIG_PROC_FS
@@ -4128,5 +2675,6 @@
 #else /* !MODULE */
 
 __setup("", ide_setup);
+module_init(ide_init);
 
 #endif /* MODULE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide_modes.h linux-2.4.21/drivers/ide/ide_modes.h
--- linux-2.4.20/drivers/ide/ide_modes.h	2001-11-22 19:46:58.000000000 +0000
+++ linux-2.4.21/drivers/ide/ide_modes.h	2002-12-18 18:58:10.000000000 +0000
@@ -16,8 +16,6 @@
  * breaking the fragile cmd640.c support.
  */
 
-#ifdef CONFIG_BLK_DEV_IDE_MODES
-
 /*
  * Standard (generic) timings for PIO modes, from ATA2 specification.
  * These timings are for access to the IDE data port register *only*.
@@ -31,206 +29,13 @@
 } ide_pio_timings_t;
 
 typedef struct ide_pio_data_s {
-	byte pio_mode;
-	byte use_iordy;
-	byte overridden;
-	byte blacklisted;
+	u8 pio_mode;
+	u8 use_iordy;
+	u8 overridden;
+	u8 blacklisted;
 	unsigned int cycle_time;
 } ide_pio_data_t;
 	
-#ifndef _IDE_C
-
-int ide_scan_pio_blacklist (char *model);
-byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d);
+u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_pio_data_t *d);
 extern const ide_pio_timings_t ide_pio_timings[6];
-
-#else /* _IDE_C */
-
-const ide_pio_timings_t ide_pio_timings[6] = {
-	{ 70,	165,	600 },	/* PIO Mode 0 */
-	{ 50,	125,	383 },	/* PIO Mode 1 */
-	{ 30,	100,	240 },	/* PIO Mode 2 */
-	{ 30,	80,	180 },	/* PIO Mode 3 with IORDY */
-	{ 25,	70,	120 },	/* PIO Mode 4 with IORDY */
-	{ 20,	50,	100 }	/* PIO Mode 5 with IORDY (nonstandard) */
-};
-
-/*
- * Black list. Some drives incorrectly report their maximal PIO mode,
- * at least in respect to CMD640. Here we keep info on some known drives.
- */
-static struct ide_pio_info {
-	const char	*name;
-	int		pio;
-} ide_pio_blacklist [] = {
-/*	{ "Conner Peripherals 1275MB - CFS1275A", 4 }, */
-	{ "Conner Peripherals 540MB - CFS540A", 3 },
-
-	{ "WDC AC2700",  3 },
-	{ "WDC AC2540",  3 },
-	{ "WDC AC2420",  3 },
-	{ "WDC AC2340",  3 },
-	{ "WDC AC2250",  0 },
-	{ "WDC AC2200",  0 },
-	{ "WDC AC21200", 4 },
-	{ "WDC AC2120",  0 },
-	{ "WDC AC2850",  3 },
-	{ "WDC AC1270",  3 },
-	{ "WDC AC1170",  1 },
-	{ "WDC AC1210",  1 },
-	{ "WDC AC280",   0 },
-/*	{ "WDC AC21000", 4 }, */
-	{ "WDC AC31000", 3 },
-	{ "WDC AC31200", 3 },
-/*	{ "WDC AC31600", 4 }, */
-
-	{ "Maxtor 7131 AT", 1 },
-	{ "Maxtor 7171 AT", 1 },
-	{ "Maxtor 7213 AT", 1 },
-	{ "Maxtor 7245 AT", 1 },
-	{ "Maxtor 7345 AT", 1 },
-	{ "Maxtor 7546 AT", 3 },
-	{ "Maxtor 7540 AV", 3 },
-
-	{ "SAMSUNG SHD-3121A", 1 },
-	{ "SAMSUNG SHD-3122A", 1 },
-	{ "SAMSUNG SHD-3172A", 1 },
-
-/*	{ "ST51080A", 4 },
- *	{ "ST51270A", 4 },
- *	{ "ST31220A", 4 },
- *	{ "ST31640A", 4 },
- *	{ "ST32140A", 4 },
- *	{ "ST3780A",  4 },
- */
-	{ "ST5660A",  3 },
-	{ "ST3660A",  3 },
-	{ "ST3630A",  3 },
-	{ "ST3655A",  3 },
-	{ "ST3391A",  3 },
-	{ "ST3390A",  1 },
-	{ "ST3600A",  1 },
-	{ "ST3290A",  0 },
-	{ "ST3144A",  0 },
-	{ "ST3491A",  1 },	/* reports 3, should be 1 or 2 (depending on */	
-				/* drive) according to Seagates FIND-ATA program */
-
-	{ "QUANTUM ELS127A", 0 },
-	{ "QUANTUM ELS170A", 0 },
-	{ "QUANTUM LPS240A", 0 },
-	{ "QUANTUM LPS210A", 3 },
-	{ "QUANTUM LPS270A", 3 },
-	{ "QUANTUM LPS365A", 3 },
-	{ "QUANTUM LPS540A", 3 },
-	{ "QUANTUM LIGHTNING 540A", 3 },
-	{ "QUANTUM LIGHTNING 730A", 3 },
-
-        { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */
-        { "QUANTUM FIREBALL_640", 3 }, 
-        { "QUANTUM FIREBALL_1080", 3 },
-        { "QUANTUM FIREBALL_1280", 3 },
-	{ NULL,	0 }
-};
-
-/*
- * This routine searches the ide_pio_blacklist for an entry
- * matching the start/whole of the supplied model name.
- *
- * Returns -1 if no match found.
- * Otherwise returns the recommended PIO mode from ide_pio_blacklist[].
- */
-int ide_scan_pio_blacklist (char *model)
-{
-	struct ide_pio_info *p;
-
-	for (p = ide_pio_blacklist; p->name != NULL; p++) {
-		if (strncmp(p->name, model, strlen(p->name)) == 0)
-			return p->pio;
-	}
-	return -1;
-}
-
-/*
- * This routine returns the recommended PIO settings for a given drive,
- * based on the drive->id information and the ide_pio_blacklist[].
- * This is used by most chipset support modules when "auto-tuning".
- */
-
-/*
- * Drive PIO mode auto selection
- */
-byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d)
-{
-	int pio_mode;
-	int cycle_time = 0;
-	int use_iordy = 0;
-	struct hd_driveid* id = drive->id;
-	int overridden  = 0;
-	int blacklisted = 0;
-
-	if (mode_wanted != 255) {
-		pio_mode = mode_wanted;
-	} else if (!drive->id) {
-		pio_mode = 0;
-	} else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
-		overridden = 1;
-		blacklisted = 1;
-		use_iordy = (pio_mode > 2);
-	} else {
-		pio_mode = id->tPIO;
-		if (pio_mode > 2) {	/* 2 is maximum allowed tPIO value */
-			pio_mode = 2;
-			overridden = 1;
-		}
-		if (id->field_valid & 2) {	  /* drive implements ATA2? */
-			if (id->capability & 8) { /* drive supports use_iordy? */
-				use_iordy = 1;
-				cycle_time = id->eide_pio_iordy;
-				if (id->eide_pio_modes & 7) {
-					overridden = 0;
-					if (id->eide_pio_modes & 4)
-						pio_mode = 5;
-					else if (id->eide_pio_modes & 2)
-						pio_mode = 4;
-					else
-						pio_mode = 3;
-				}
-			} else {
-				cycle_time = id->eide_pio;
-			}
-		}
-
-#if 0
-		if (drive->id->major_rev_num & 0x0004) printk("ATA-2 ");
-#endif
-
-		/*
-		 * Conservative "downgrade" for all pre-ATA2 drives
-		 */
-		if (pio_mode && pio_mode < 4) {
-			pio_mode--;
-			overridden = 1;
-#if 0
-			use_iordy = (pio_mode > 2);
-#endif
-			if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time)
-				cycle_time = 0; /* use standard timing */
-		}
-	}
-	if (pio_mode > max_mode) {
-		pio_mode = max_mode;
-		cycle_time = 0;
-	}
-	if (d) {
-		d->pio_mode = pio_mode;
-		d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time;
-		d->use_iordy = use_iordy;
-		d->overridden = overridden;
-		d->blacklisted = blacklisted;
-	}
-	return pio_mode;
-}
-
-#endif /* _IDE_C */
-#endif /* CONFIG_BLK_DEV_IDE_MODES */
 #endif /* _IDE_MODES_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/it8172.c linux-2.4.21/drivers/ide/it8172.c
--- linux-2.4.20/drivers/ide/it8172.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/it8172.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,286 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- *      IT8172 IDE controller support
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- *              stevel@mvista.com or source@mvista.com
- *
- *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/it8172/it8172_int.h>
-
-#include "ide_modes.h"
-
-/*
- * Prototypes
- */
-static void it8172_tune_drive (ide_drive_t *drive, byte pio);
-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING)
-static byte it8172_dma_2_pio (byte xfer_rate);
-static int it8172_tune_chipset (ide_drive_t *drive, byte speed);
-static int it8172_config_chipset_for_dma (ide_drive_t *drive);
-static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
-#endif
-unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name);
-void __init ide_init_it8172 (ide_hwif_t *hwif);
-
-
-static void it8172_tune_drive (ide_drive_t *drive, byte pio)
-{
-    unsigned long flags;
-    u16 drive_enables;
-    u32 drive_timing;
-    int is_slave	= (&HWIF(drive)->drives[1] == drive);
-    
-    pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-    pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &drive_enables);
-    pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &drive_timing);
-
-    /*
-     * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44
-     * are being left at the default values of 8 PCI clocks (242 nsec
-     * for a 33 MHz clock). These can be safely shortened at higher
-     * PIO modes. The DIOR/DIOW pulse width and recovery times only
-     * apply to PIO modes, not to the DMA modes.
-     */
-    
-    /*
-     * Enable port 0x44. The IT8172G spec is confused; it calls
-     * this register the "Slave IDE Timing Register", but in fact,
-     * it controls timing for both master and slave drives.
-     */
-    drive_enables |= 0x4000;
-
-    if (is_slave) {
-	drive_enables &= 0xc006;
-	if (pio > 1)
-	    /* enable prefetch and IORDY sample-point */
-	    drive_enables |= 0x0060;
-    } else {
-	drive_enables &= 0xc060;
-	if (pio > 1)
-	    /* enable prefetch and IORDY sample-point */
-	    drive_enables |= 0x0006;
-    }
-
-    save_flags(flags);
-    cli();
-    pci_write_config_word(HWIF(drive)->pci_dev, 0x40, drive_enables);
-    restore_flags(flags);
-}
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING)
-/*
- *
- */
-static byte it8172_dma_2_pio (byte xfer_rate)
-{
-    switch(xfer_rate) {
-    case XFER_UDMA_5:
-    case XFER_UDMA_4:
-    case XFER_UDMA_3:
-    case XFER_UDMA_2:
-    case XFER_UDMA_1:
-    case XFER_UDMA_0:
-    case XFER_MW_DMA_2:
-    case XFER_PIO_4:
-	return 4;
-    case XFER_MW_DMA_1:
-    case XFER_PIO_3:
-	return 3;
-    case XFER_SW_DMA_2:
-    case XFER_PIO_2:
-	return 2;
-    case XFER_MW_DMA_0:
-    case XFER_SW_DMA_1:
-    case XFER_SW_DMA_0:
-    case XFER_PIO_1:
-    case XFER_PIO_0:
-    case XFER_PIO_SLOW:
-    default:
-	return 0;
-    }
-}
-
-static int it8172_tune_chipset (ide_drive_t *drive, byte speed)
-{
-    ide_hwif_t *hwif	= HWIF(drive);
-    struct pci_dev *dev	= hwif->pci_dev;
-    int a_speed		= 3 << (drive->dn * 4);
-    int u_flag		= 1 << drive->dn;
-    int u_speed		= 0;
-    int err		= 0;
-    byte reg48, reg4a;
-
-    pci_read_config_byte(dev, 0x48, &reg48);
-    pci_read_config_byte(dev, 0x4a, &reg4a);
-
-    /*
-     * Setting the DMA cycle time to 2 or 3 PCI clocks (60 and 91 nsec
-     * at 33 MHz PCI clock) seems to cause BadCRC errors during DMA
-     * transfers on some drives, even though both numbers meet the minimum
-     * ATAPI-4 spec of 73 and 54 nsec for UDMA 1 and 2 respectively.
-     * So the faster times are just commented out here. The good news is
-     * that the slower cycle time has very little affect on transfer
-     * performance.
-     */
-    
-    switch(speed) {
-    case XFER_UDMA_4:
-    case XFER_UDMA_2:	//u_speed = 2 << (drive->dn * 4); break;
-    case XFER_UDMA_5:
-    case XFER_UDMA_3:
-    case XFER_UDMA_1:	//u_speed = 1 << (drive->dn * 4); break;
-    case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
-    case XFER_MW_DMA_2:
-    case XFER_MW_DMA_1:
-    case XFER_MW_DMA_0:
-    case XFER_SW_DMA_2:	break;
-    default:		return -1;
-    }
-
-    if (speed >= XFER_UDMA_0) {
-	pci_write_config_byte(dev, 0x48, reg48 | u_flag);
-	reg4a &= ~a_speed;
-	pci_write_config_byte(dev, 0x4a, reg4a | u_speed);
-    } else {
-	pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
-	pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed);
-    }
-
-    it8172_tune_drive(drive, it8172_dma_2_pio(speed));
-
-    if (!drive->init_speed)
-	drive->init_speed = speed;
-    err = ide_config_drive_speed(drive, speed);
-    drive->current_speed = speed;
-    return err;
-}
-
-static int it8172_config_chipset_for_dma (ide_drive_t *drive)
-{
-    struct hd_driveid *id = drive->id;
-    byte speed;
-
-    if (id->dma_ultra & 0x0010) {
-	speed = XFER_UDMA_2;
-    } else if (id->dma_ultra & 0x0008) {
-	speed = XFER_UDMA_1;
-    } else if (id->dma_ultra & 0x0004) {
-	speed = XFER_UDMA_2;
-    } else if (id->dma_ultra & 0x0002) {
-	speed = XFER_UDMA_1;
-    } else if (id->dma_ultra & 0x0001) {
-	speed = XFER_UDMA_0;
-    } else if (id->dma_mword & 0x0004) {
-	speed = XFER_MW_DMA_2;
-    } else if (id->dma_mword & 0x0002) {
-	speed = XFER_MW_DMA_1;
-    } else if (id->dma_mword & 0x0001) {
-	speed = XFER_MW_DMA_0;
-    } else if (id->dma_1word & 0x0004) {
-	speed = XFER_SW_DMA_2;
-    } else {
-	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 4, NULL);
-    }
-
-    (void) it8172_tune_chipset(drive, speed);
-
-    return ((int)((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-	    ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-	    ((id->dma_mword >> 8) & 7) ? ide_dma_on :
-	    ((id->dma_1word >> 8) & 7) ? ide_dma_on :
-	    ide_dma_off_quietly);
-}
-
-static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-    switch (func) {
-    case ide_dma_check:
-	return ide_dmaproc((ide_dma_action_t)it8172_config_chipset_for_dma(drive),
-			   drive);
-    default :
-	break;
-    }
-    /* Other cases are done by generic IDE-DMA code. */
-    return ide_dmaproc(func, drive);
-}
-
-#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_IT8172_TUNING) */
-
-
-unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name)
-{
-    unsigned char progif;
-    
-    /*
-     * Place both IDE interfaces into PCI "native" mode
-     */
-    (void)pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
-    (void)pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05);    
-
-    return IT8172_IDE_IRQ;
-}
-
-
-void __init ide_init_it8172 (ide_hwif_t *hwif)
-{
-    struct pci_dev* dev = hwif->pci_dev;
-    unsigned long cmdBase, ctrlBase;
-    
-    hwif->tuneproc = &it8172_tune_drive;
-    hwif->drives[0].autotune = 1;
-    hwif->drives[1].autotune = 1;
-
-    if (!hwif->dma_base)
-	return;
-
-#ifndef CONFIG_BLK_DEV_IDEDMA
-    hwif->autodma = 0;
-#else /* CONFIG_BLK_DEV_IDEDMA */
-#ifdef CONFIG_IT8172_TUNING
-    hwif->autodma = 1;
-    hwif->dmaproc = &it8172_dmaproc;
-    hwif->speedproc = &it8172_tune_chipset;
-#endif /* CONFIG_IT8172_TUNING */
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
-
-    cmdBase = dev->resource[0].start;
-    ctrlBase = dev->resource[1].start;
-    
-    ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL);
-    memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-    hwif->noprobe = 0;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/Makefile linux-2.4.21/drivers/ide/legacy/Makefile
--- linux-2.4.20/drivers/ide/legacy/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/legacy/Makefile	2002-12-18 18:58:05.000000000 +0000
@@ -0,0 +1,27 @@
+
+O_TARGET := idedriver-legacy.o
+
+obj-y		:=
+obj-m		:=
+
+obj-$(CONFIG_BLK_DEV_ALI14XX)		+= ali14xx.o
+obj-$(CONFIG_BLK_DEV_DTC2278)		+= dtc2278.o
+obj-$(CONFIG_BLK_DEV_HT6560B)		+= ht6560b.o
+obj-$(CONFIG_BLK_DEV_PDC4030)		+= pdc4030.o
+obj-$(CONFIG_BLK_DEV_QD65XX)		+= qd65xx.o
+obj-$(CONFIG_BLK_DEV_UMC8672)		+= umc8672.o
+
+obj-$(CONFIG_BLK_DEV_BUDDHA)		+= buddha.o
+obj-$(CONFIG_BLK_DEV_FALCON_IDE)	+= falconide.o
+obj-$(CONFIG_BLK_DEV_GAYLE)		+= gayle.o
+obj-$(CONFIG_BLK_DEV_MAC_IDE)		+= macide.o
+obj-$(CONFIG_BLK_DEV_Q40IDE)		+= q40ide.o
+
+obj-$(CONFIG_BLK_DEV_IDECS)		+= ide-cs.o
+
+# Last of all
+obj-$(CONFIG_BLK_DEV_HD)		+= hd.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/ali14xx.c linux-2.4.21/drivers/ide/legacy/ali14xx.c
--- linux-2.4.20/drivers/ide/legacy/ali14xx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/legacy/ali14xx.c	2002-12-18 18:58:08.000000000 +0000
@@ -0,0 +1,304 @@
+/*
+ *  linux/drivers/ide/ali14xx.c		Version 0.03	Feb 09, 1996
+ *
+ *  Copyright (C) 1996  Linus Torvalds & author (see below)
+ */
+
+/*
+ * ALI M14xx chipset EIDE controller
+ *
+ * Works for ALI M1439/1443/1445/1487/1489 chipsets.
+ *
+ * Adapted from code developed by derekn@vw.ece.cmu.edu.  -ml
+ * Derek's notes follow:
+ *
+ * I think the code should be pretty understandable,
+ * but I'll be happy to (try to) answer questions.
+ *
+ * The critical part is in the setupDrive function.  The initRegisters
+ * function doesn't seem to be necessary, but the DOS driver does it, so
+ * I threw it in.
+ *
+ * I've only tested this on my system, which only has one disk.  I posted
+ * it to comp.sys.linux.hardware, so maybe some other people will try it
+ * out.
+ *
+ * Derek Noonburg  (derekn@ece.cmu.edu)
+ * 95-sep-26
+ *
+ * Update 96-jul-13:
+ *
+ * I've since upgraded to two disks and a CD-ROM, with no trouble, and
+ * I've also heard from several others who have used it successfully.
+ * This driver appears to work with both the 1443/1445 and the 1487/1489
+ * chipsets.  I've added support for PIO mode 4 for the 1487.  This
+ * seems to work just fine on the 1443 also, although I'm not sure it's
+ * advertised as supporting mode 4.  (I've been running a WDC AC21200 in
+ * mode 4 for a while now with no trouble.)  -Derek
+ */
+
+#undef REALLY_SLOW_IO           /* most systems can safely undef this */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_ALI14XX_MODULE
+# define _IDE_C
+# include "ide_modes.h"
+# undef _IDE_C
+#else
+# include "ide_modes.h"
+#endif /* CONFIG_BLK_DEV_ALI14XX_MODULE */
+
+/* port addresses for auto-detection */
+#define ALI_NUM_PORTS 4
+static int ports[ALI_NUM_PORTS] __initdata = {0x074, 0x0f4, 0x034, 0x0e4};
+
+/* register initialization data */
+typedef struct { u8 reg, data; } RegInitializer;
+
+static RegInitializer initData[] __initdata = {
+	{0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
+	{0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
+	{0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
+	{0x29, 0x00}, {0x2a, 0x00}, {0x2f, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x30, 0x00},
+	{0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0xff},
+	{0x35, 0x03}, {0x00, 0x00}
+};
+
+#define ALI_MAX_PIO 4
+
+/* timing parameter registers for each drive */
+static struct { u8 reg1, reg2, reg3, reg4; } regTab[4] = {
+	{0x03, 0x26, 0x04, 0x27},     /* drive 0 */
+	{0x05, 0x28, 0x06, 0x29},     /* drive 1 */
+	{0x2b, 0x30, 0x2c, 0x31},     /* drive 2 */
+	{0x2d, 0x32, 0x2e, 0x33},     /* drive 3 */
+};
+
+static int basePort;	/* base port address */
+static int regPort;	/* port for register number */
+static int dataPort;	/* port for register data */
+static u8 regOn;	/* output to base port to access registers */
+static u8 regOff;	/* output to base port to close registers */
+
+/*------------------------------------------------------------------------*/
+
+/*
+ * Read a controller register.
+ */
+static inline u8 inReg (u8 reg)
+{
+	outb_p(reg, regPort);
+	return inb(dataPort);
+}
+
+/*
+ * Write a controller register.
+ */
+static void outReg (u8 data, u8 reg)
+{
+	outb_p(reg, regPort);
+	outb_p(data, dataPort);
+}
+
+/*
+ * Set PIO mode for the specified drive.
+ * This function computes timing parameters
+ * and sets controller registers accordingly.
+ */
+static void ali14xx_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	int driveNum;
+	int time1, time2;
+	u8 param1, param2, param3, param4;
+	unsigned long flags;
+	ide_pio_data_t d;
+	int bus_speed = system_bus_clock();
+
+	pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d);
+
+	/* calculate timing, according to PIO mode */
+	time1 = d.cycle_time;
+	time2 = ide_pio_timings[pio].active_time;
+	param3 = param1 = (time2 * bus_speed + 999) / 1000;
+	param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
+	if (pio < 3) {
+		param3 += 8;
+		param4 += 8;
+	}
+	printk(KERN_DEBUG "%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n",
+		drive->name, pio, time1, time2, param1, param2, param3, param4);
+
+	/* stuff timing parameters into controller registers */
+	driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit;
+	spin_lock_irqsave(&io_request_lock, flags);
+	outb_p(regOn, basePort);
+	outReg(param1, regTab[driveNum].reg1);
+	outReg(param2, regTab[driveNum].reg2);
+	outReg(param3, regTab[driveNum].reg3);
+	outReg(param4, regTab[driveNum].reg4);
+	outb_p(regOff, basePort);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+/*
+ * Auto-detect the IDE controller port.
+ */
+static int __init findPort (void)
+{
+	int i;
+	u8 t;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	for (i = 0; i < ALI_NUM_PORTS; ++i) {
+		basePort = ports[i];
+		regOff = inb(basePort);
+		for (regOn = 0x30; regOn <= 0x33; ++regOn) {
+			outb_p(regOn, basePort);
+			if (inb(basePort) == regOn) {
+				regPort = basePort + 4;
+				dataPort = basePort + 8;
+				t = inReg(0) & 0xf0;
+				outb_p(regOff, basePort);
+				local_irq_restore(flags);
+				if (t != 0x50)
+					return 0;
+				return 1;  /* success */
+			}
+		}
+		outb_p(regOff, basePort);
+	}
+	local_irq_restore(flags);
+	return 0;
+}
+
+/*
+ * Initialize controller registers with default values.
+ */
+static int __init initRegisters (void) {
+	RegInitializer *p;
+	u8 t;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	outb_p(regOn, basePort);
+	for (p = initData; p->reg != 0; ++p)
+		outReg(p->data, p->reg);
+	outb_p(0x01, regPort);
+	t = inb(regPort) & 0x01;
+	outb_p(regOff, basePort);
+	local_irq_restore(flags);
+	return t;
+}
+
+int __init probe_ali14xx (void)
+{
+	/* auto-detect IDE controller port */
+	if (!findPort()) {
+		printk(KERN_ERR "ali14xx: not found.\n");
+		return 1;
+	}
+
+	printk(KERN_DEBUG "ali14xx: base= 0x%03x, regOn = 0x%02x.\n", basePort, regOn);
+	ide_hwifs[0].chipset = ide_ali14xx;
+	ide_hwifs[1].chipset = ide_ali14xx;
+	ide_hwifs[0].tuneproc = &ali14xx_tune_drive;
+	ide_hwifs[1].tuneproc = &ali14xx_tune_drive;
+	ide_hwifs[0].mate = &ide_hwifs[1];
+	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
+
+	/* initialize controller registers */
+	if (!initRegisters()) {
+		printk(KERN_ERR "ali14xx: Chip initialization failed.\n");
+		return 1;
+	}
+
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(&ide_hwifs[0]);
+	probe_hwif_init(&ide_hwifs[1]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+	return 0;
+}
+
+void __init ali14xx_release (void)
+{
+	if (ide_hwifs[0].chipset != ide_ali14xx &&
+	    ide_hwifs[1].chipset != ide_ali14xx)
+		return;
+
+	ide_hwifs[0].chipset = ide_unknown;
+	ide_hwifs[1].chipset = ide_unknown;
+	ide_hwifs[0].tuneproc = NULL;
+	ide_hwifs[1].tuneproc = NULL;
+	ide_hwifs[0].mate = NULL;
+	ide_hwifs[1].mate = NULL;
+}
+
+#ifndef MODULE
+/*
+ * init_ali14xx:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_ali14xx (void)
+{
+	/* auto-detect IDE controller port */
+        if (findPort())
+		if (probe_ali14xx())
+			goto no_detect;
+	return;
+
+no_detect:
+	printk(KERN_ERR "ali14xx: not found.\n");
+	ali14xx_release();
+}
+
+#else
+
+MODULE_AUTHOR("see local file");
+MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets");
+MODULE_LICENSE("GPL");
+
+int __init ali14xx_mod_init(void)
+{
+	/* auto-detect IDE controller port */
+	if (findPort())
+		if (probe_ali14xx()) {
+			ali14xx_release();
+			return -ENODEV;
+		}
+
+	if (ide_hwifs[0].chipset != ide_ali14xx &&
+	    ide_hwifs[1].chipset != ide_ali14xx) {
+		ali14xx_release();
+		return -ENODEV;
+	}
+	return 0;
+}
+module_init(ali14xx_mod_init);
+
+void __init ali14xx_mod_exit(void)
+{
+	ali14xx_release();
+}
+module_exit(ali14xx_mod_exit);
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/buddha.c linux-2.4.21/drivers/ide/legacy/buddha.c
--- linux-2.4.20/drivers/ide/legacy/buddha.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/legacy/buddha.c	2002-12-18 18:58:07.000000000 +0000
@@ -0,0 +1,233 @@
+/*
+ *  linux/drivers/ide/buddha.c -- Amiga Buddha, Catweasel and X-Surf IDE Driver
+ *
+ *	Copyright (C) 1997, 2001 by Geert Uytterhoeven and others
+ *
+ *  This driver was written based on the specifications in README.buddha and
+ *  the X-Surf info from Inside_XSurf.txt available at
+ *  http://www.jschoenfeld.com
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ *
+ *  TODO:
+ *    - test it :-)
+ *    - tune the timings using the speed-register
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/zorro.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+
+
+    /*
+     *  The Buddha has 2 IDE interfaces, the Catweasel has 3, X-Surf has 2
+     */
+
+#define BUDDHA_NUM_HWIFS	2
+#define CATWEASEL_NUM_HWIFS	3
+#define XSURF_NUM_HWIFS         2
+
+    /*
+     *  Bases of the IDE interfaces (relative to the board address)
+     */
+
+#define BUDDHA_BASE1	0x800
+#define BUDDHA_BASE2	0xa00
+#define BUDDHA_BASE3	0xc00
+
+#define XSURF_BASE1     0xb000 /* 2.5" Interface */
+#define XSURF_BASE2     0xd000 /* 3.5" Interface */
+
+static u_int buddha_bases[CATWEASEL_NUM_HWIFS] __initdata = {
+    BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
+};
+
+static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = {
+     XSURF_BASE1, XSURF_BASE2
+};
+
+
+    /*
+     *  Offsets from one of the above bases
+     */
+
+#define BUDDHA_DATA	0x00
+#define BUDDHA_ERROR	0x06		/* see err-bits */
+#define BUDDHA_NSECTOR	0x0a		/* nr of sectors to read/write */
+#define BUDDHA_SECTOR	0x0e		/* starting sector */
+#define BUDDHA_LCYL	0x12		/* starting cylinder */
+#define BUDDHA_HCYL	0x16		/* high byte of starting cyl */
+#define BUDDHA_SELECT	0x1a		/* 101dhhhh , d=drive, hhhh=head */
+#define BUDDHA_STATUS	0x1e		/* see status-bits */
+#define BUDDHA_CONTROL	0x11a
+#define XSURF_CONTROL   -1              /* X-Surf has no CS1* (Control/AltStat) */
+
+static int buddha_offsets[IDE_NR_PORTS] __initdata = {
+    BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
+    BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL, -1
+};
+
+static int xsurf_offsets[IDE_NR_PORTS] __initdata = {
+    BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
+    BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, XSURF_CONTROL, -1
+};
+
+    /*
+     *  Other registers
+     */
+
+#define BUDDHA_IRQ1	0xf00		/* MSB = 1, Harddisk is source of */
+#define BUDDHA_IRQ2	0xf40		/* interrupt */
+#define BUDDHA_IRQ3	0xf80
+
+#define XSURF_IRQ1      0x7e
+#define XSURF_IRQ2      0x7e
+
+static int buddha_irqports[CATWEASEL_NUM_HWIFS] __initdata = {
+    BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3
+};
+
+static int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = {
+    XSURF_IRQ1, XSURF_IRQ2
+};
+
+#define BUDDHA_IRQ_MR	0xfc0		/* master interrupt enable */
+
+
+    /*
+     *  Board information
+     */
+
+typedef enum BuddhaType_Enum {
+    BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
+} BuddhaType;
+
+
+    /*
+     *  Check and acknowledge the interrupt status
+     */
+
+static int buddha_ack_intr(ide_hwif_t *hwif)
+{
+    unsigned char ch;
+
+    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    if (!(ch & 0x80))
+	    return 0;
+    return 1;
+}
+
+static int xsurf_ack_intr(ide_hwif_t *hwif)
+{
+    unsigned char ch;
+
+    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    /* X-Surf needs a 0 written to IRQ register to ensure ISA bit A11 stays at 0 */
+    z_writeb(0, hwif->io_ports[IDE_IRQ_OFFSET]); 
+    if (!(ch & 0x80))
+	    return 0;
+    return 1;
+}
+
+    /*
+     *  Probe for a Buddha or Catweasel IDE interface
+     */
+
+void __init buddha_init(void)
+{
+	hw_regs_t hw;
+	int i, index;
+
+	struct zorro_dev *z = NULL;
+	u_long buddha_board = 0;
+	BuddhaType type;
+	int buddha_num_hwifs;
+
+	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
+		unsigned long board;
+		if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
+			buddha_num_hwifs = BUDDHA_NUM_HWIFS;
+			type=BOARD_BUDDHA;
+		} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL) {
+			buddha_num_hwifs = CATWEASEL_NUM_HWIFS;
+			type=BOARD_CATWEASEL;
+		} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF) {
+			buddha_num_hwifs = XSURF_NUM_HWIFS;
+			type=BOARD_XSURF;
+		} else 
+			continue;
+		
+		board = z->resource.start;
+
+/*
+ * FIXME: we now have selectable mmio v/s iomio transports.
+ */
+
+		if(type != BOARD_XSURF) {
+			if (!request_mem_region(board+BUDDHA_BASE1, 0x800, "IDE"))
+				continue;
+		} else {
+			if (!request_mem_region(board+XSURF_BASE1, 0x1000, "IDE"))
+				continue;
+			if (!request_mem_region(board+XSURF_BASE2, 0x1000, "IDE"))
+				goto fail_base2;
+			if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE")) {
+				release_mem_region(board+XSURF_BASE2, 0x1000);
+fail_base2:
+				release_mem_region(board+XSURF_BASE1, 0x1000);
+				continue;
+			}
+		}	  
+		buddha_board = ZTWO_VADDR(board);
+		
+		/* write to BUDDHA_IRQ_MR to enable the board IRQ */
+		/* X-Surf doesn't have this.  IRQs are always on */
+		if (type != BOARD_XSURF)
+			z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
+		
+		for(i=0;i<buddha_num_hwifs;i++) {
+			if(type != BOARD_XSURF) {
+				ide_setup_ports(&hw, (ide_ioreg_t)(buddha_board+buddha_bases[i]),
+						buddha_offsets, 0,
+						(ide_ioreg_t)(buddha_board+buddha_irqports[i]),
+						buddha_ack_intr,
+//						budda_iops,
+						IRQ_AMIGA_PORTS);
+			} else {
+				ide_setup_ports(&hw, (ide_ioreg_t)(buddha_board+xsurf_bases[i]),
+						xsurf_offsets, 0,
+						(ide_ioreg_t)(buddha_board+xsurf_irqports[i]),
+						xsurf_ack_intr,
+//						xsurf_iops,
+						IRQ_AMIGA_PORTS);
+			}	
+			
+			index = ide_register_hw(&hw, NULL);
+			if (index != -1) {
+				printk("ide%d: ", index);
+				switch(type) {
+				case BOARD_BUDDHA:
+					printk("Buddha");
+					break;
+				case BOARD_CATWEASEL:
+					printk("Catweasel");
+					break;
+				case BOARD_XSURF:
+					printk("X-Surf");
+					break;
+				}
+				printk(" IDE interface\n");	    
+			}		      
+		}
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/dtc2278.c linux-2.4.21/drivers/ide/legacy/dtc2278.c
--- linux-2.4.20/drivers/ide/legacy/dtc2278.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/legacy/dtc2278.c	2002-12-18 18:58:08.000000000 +0000
@@ -0,0 +1,203 @@
+/*
+ *  linux/drivers/ide/dtc2278.c		Version 0.02	Feb 10, 1996
+ *
+ *  Copyright (C) 1996  Linus Torvalds & author (see below)
+ */
+
+#undef REALLY_SLOW_IO           /* most systems can safely undef this */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_DTC2278_MODULE
+# define _IDE_C
+# include "ide_modes.h"
+# undef _IDE_C
+#else
+# include "ide_modes.h"
+#endif /* CONFIG_BLK_DEV_DTC2278_MODULE */
+
+/*
+ * Changing this #undef to #define may solve start up problems in some systems.
+ */
+#undef ALWAYS_SET_DTC2278_PIO_MODE
+
+/*
+ * From: andy@cercle.cts.com (Dyan Wile)
+ *
+ * Below is a patch for DTC-2278 - alike software-programmable controllers
+ * The code enables the secondary IDE controller and the PIO4 (3?) timings on
+ * the primary (EIDE). You may probably have to enable the 32-bit support to
+ * get the full speed. You better get the disk interrupts disabled ( hdparm -u0
+ * /dev/hd.. ) for the drives connected to the EIDE interface. (I get my
+ * filesystem  corrupted with -u1, but under heavy disk load only :-)
+ *
+ * This card is now forced to use the "serialize" feature,
+ * and irq-unmasking is disallowed.  If io_32bit is enabled,
+ * it must be done for BOTH drives on each interface.
+ *
+ * This code was written for the DTC2278E, but might work with any of these:
+ *
+ * DTC2278S has only a single IDE interface.
+ * DTC2278D has two IDE interfaces and is otherwise identical to the S version.
+ * DTC2278E also has serial ports and a printer port
+ * DTC2278EB: has onboard BIOS, and "works like a charm" -- Kent Bradford <kent@theory.caltech.edu>
+ *
+ * There may be a fourth controller type. The S and D versions use the
+ * Winbond chip, and I think the E version does also.
+ *
+ */
+
+static void sub22 (char b, char c)
+{
+	int i;
+
+	for(i = 0; i < 3; ++i) {
+		inb(0x3f6);
+		outb_p(b,0xb0);
+		inb(0x3f6);
+		outb_p(c,0xb4);
+		inb(0x3f6);
+		if(inb(0xb4) == c) {
+			outb_p(7,0xb0);
+			inb(0x3f6);
+			return;	/* success */
+		}
+	}
+}
+
+static void tune_dtc2278 (ide_drive_t *drive, u8 pio)
+{
+	unsigned long flags;
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+
+	if (pio >= 3) {
+		spin_lock_irqsave(&io_request_lock, flags);
+		/*
+		 * This enables PIO mode4 (3?) on the first interface
+		 */
+		sub22(1,0xc3);
+		sub22(0,0xa0);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+	} else {
+		/* we don't know how to set it back again.. */
+	}
+
+	/*
+	 * 32bit I/O has to be enabled for *both* drives at the same time.
+	 */
+	drive->io_32bit = 1;
+	HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1;
+}
+
+void __init probe_dtc2278 (void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	/*
+	 * This enables the second interface
+	 */
+	outb_p(4,0xb0);
+	inb(0x3f6);
+	outb_p(0x20,0xb4);
+	inb(0x3f6);
+#ifdef ALWAYS_SET_DTC2278_PIO_MODE
+	/*
+	 * This enables PIO mode4 (3?) on the first interface
+	 * and may solve start-up problems for some people.
+	 */
+	sub22(1,0xc3);
+	sub22(0,0xa0);
+#endif
+	local_irq_restore(flags);
+
+	ide_hwifs[0].serialized = 1;
+	ide_hwifs[1].serialized = 1;
+	ide_hwifs[0].chipset = ide_dtc2278;
+	ide_hwifs[1].chipset = ide_dtc2278;
+	ide_hwifs[0].tuneproc = &tune_dtc2278;
+	ide_hwifs[0].drives[0].no_unmask = 1;
+	ide_hwifs[0].drives[1].no_unmask = 1;
+	ide_hwifs[1].drives[0].no_unmask = 1;
+	ide_hwifs[1].drives[1].no_unmask = 1;
+	ide_hwifs[0].mate = &ide_hwifs[1];
+	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
+
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(&ide_hwifs[0]);
+	probe_hwif_init(&ide_hwifs[1]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+}
+
+void __init dtc2278_release (void)
+{
+	if (ide_hwifs[0].chipset != ide_dtc2278 &&
+	    ide_hwifs[1].chipset != ide_dtc2278)
+		return;
+
+	ide_hwifs[0].serialized = 0;
+	ide_hwifs[1].serialized = 0;
+	ide_hwifs[0].chipset = ide_unknown;
+	ide_hwifs[1].chipset = ide_unknown;
+	ide_hwifs[0].tuneproc = NULL;
+	ide_hwifs[0].drives[0].no_unmask = 0;
+	ide_hwifs[0].drives[1].no_unmask = 0;
+	ide_hwifs[1].drives[0].no_unmask = 0;
+	ide_hwifs[1].drives[1].no_unmask = 0;
+	ide_hwifs[0].mate = NULL;
+	ide_hwifs[1].mate = NULL;
+}
+
+#ifndef MODULE
+/*
+ * init_dtc2278:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_dtc2278 (void)
+{
+	probe_dtc2278();
+}
+
+#else
+
+MODULE_AUTHOR("See Local File");
+MODULE_DESCRIPTION("support of DTC-2278 VLB IDE chipsets");
+MODULE_LICENSE("GPL");
+
+int __init dtc2278_mod_init(void)
+{
+	probe_dtc2278();
+	if (ide_hwifs[0].chipset != ide_dtc2278 &&
+	    ide_hwifs[1].chipset != ide_dtc2278) {
+		dtc2278_release();
+		return -ENODEV;
+	}
+	return 0;
+}
+module_init(dtc2278_mod_init);
+
+void __init dtc2278_mod_exit(void)
+{
+	dtc2278_release();
+}
+module_exit(dtc2278_mod_exit);
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/falconide.c linux-2.4.21/drivers/ide/legacy/falconide.c
--- linux-2.4.20/drivers/ide/legacy/falconide.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/legacy/falconide.c	2002-12-18 18:58:07.000000000 +0000
@@ -0,0 +1,70 @@
+/*
+ *  linux/drivers/ide/falconide.c -- Atari Falcon IDE Driver
+ *
+ *     Created 12 Jul 1997 by Geert Uytterhoeven
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/setup.h>
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/atari_stdma.h>
+
+
+    /*
+     *  Base of the IDE interface
+     */
+
+#define ATA_HD_BASE	0xfff00000
+
+    /*
+     *  Offsets from the above base
+     */
+
+#define ATA_HD_DATA	0x00
+#define ATA_HD_ERROR	0x05		/* see err-bits */
+#define ATA_HD_NSECTOR	0x09		/* nr of sectors to read/write */
+#define ATA_HD_SECTOR	0x0d		/* starting sector */
+#define ATA_HD_LCYL	0x11		/* starting cylinder */
+#define ATA_HD_HCYL	0x15		/* high byte of starting cyl */
+#define ATA_HD_SELECT	0x19		/* 101dhhhh , d=drive, hhhh=head */
+#define ATA_HD_STATUS	0x1d		/* see status-bits */
+#define ATA_HD_CONTROL	0x39
+
+static int falconide_offsets[IDE_NR_PORTS] __initdata = {
+    ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL,
+    ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1
+};
+
+
+    /*
+     *  Probe for a Falcon IDE interface
+     */
+
+void __init falconide_init(void)
+{
+    if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) {
+	hw_regs_t hw;
+	int index;
+
+	ide_setup_ports(&hw, (ide_ioreg_t)ATA_HD_BASE, falconide_offsets,
+			0, 0, NULL,
+//			falconide_iops,
+			IRQ_MFP_IDE);
+	index = ide_register_hw(&hw, NULL);
+
+	if (index != -1)
+	    printk("ide%d: Falcon IDE interface\n", index);
+    }
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/gayle.c linux-2.4.21/drivers/ide/legacy/gayle.c
--- linux-2.4.20/drivers/ide/legacy/gayle.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/legacy/gayle.c	2002-12-18 18:58:04.000000000 +0000
@@ -0,0 +1,187 @@
+/*
+ *  linux/drivers/ide/gayle.c -- Amiga Gayle IDE Driver
+ *
+ *     Created 9 Jul 1997 by Geert Uytterhoeven
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/zorro.h>
+
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/amigayle.h>
+
+
+    /*
+     *  Bases of the IDE interfaces
+     */
+
+#define GAYLE_BASE_4000	0xdd2020	/* A4000/A4000T */
+#define GAYLE_BASE_1200	0xda0000	/* A1200/A600 */
+
+    /*
+     *  Offsets from one of the above bases
+     */
+
+#define GAYLE_DATA	0x00
+#define GAYLE_ERROR	0x06		/* see err-bits */
+#define GAYLE_NSECTOR	0x0a		/* nr of sectors to read/write */
+#define GAYLE_SECTOR	0x0e		/* starting sector */
+#define GAYLE_LCYL	0x12		/* starting cylinder */
+#define GAYLE_HCYL	0x16		/* high byte of starting cyl */
+#define GAYLE_SELECT	0x1a		/* 101dhhhh , d=drive, hhhh=head */
+#define GAYLE_STATUS	0x1e		/* see status-bits */
+#define GAYLE_CONTROL	0x101a
+
+static int gayle_offsets[IDE_NR_PORTS] __initdata = {
+    GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL,
+    GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1
+};
+
+
+    /*
+     *  These are at different offsets from the base
+     */
+
+#define GAYLE_IRQ_4000	0xdd3020	/* MSB = 1, Harddisk is source of */
+#define GAYLE_IRQ_1200	0xda9000	/* interrupt */
+
+
+    /*
+     *  Offset of the secondary port for IDE doublers
+     *  Note that GAYLE_CONTROL is NOT available then!
+     */
+
+#define GAYLE_NEXT_PORT	0x1000
+
+#ifndef CONFIG_BLK_DEV_IDEDOUBLER
+#define GAYLE_NUM_HWIFS		1
+#define GAYLE_NUM_PROBE_HWIFS	GAYLE_NUM_HWIFS
+#define GAYLE_HAS_CONTROL_REG	1
+#define GAYLE_IDEREG_SIZE	0x2000
+#else /* CONFIG_BLK_DEV_IDEDOUBLER */
+#define GAYLE_NUM_HWIFS		2
+#define GAYLE_NUM_PROBE_HWIFS	(ide_doubler ? GAYLE_NUM_HWIFS : \
+					       GAYLE_NUM_HWIFS-1)
+#define GAYLE_HAS_CONTROL_REG	(!ide_doubler)
+#define GAYLE_IDEREG_SIZE	(ide_doubler ? 0x1000 : 0x2000)
+int ide_doubler = 0;	/* support IDE doublers? */
+#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
+
+
+    /*
+     *  Check and acknowledge the interrupt status
+     */
+
+static int gayle_ack_intr_a4000(ide_hwif_t *hwif)
+{
+    unsigned char ch;
+
+    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    if (!(ch & GAYLE_IRQ_IDE))
+	return 0;
+    return 1;
+}
+
+static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
+{
+    unsigned char ch;
+
+    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    if (!(ch & GAYLE_IRQ_IDE))
+	return 0;
+    (void)z_readb(hwif->io_ports[IDE_STATUS_OFFSET]);
+    z_writeb(0x7c, hwif->io_ports[IDE_IRQ_OFFSET]);
+    return 1;
+}
+
+    /*
+     *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
+     */
+
+void __init gayle_init(void)
+{
+    int a4000, i;
+
+    if (!MACH_IS_AMIGA)
+	return;
+
+    if (!(a4000 = AMIGAHW_PRESENT(A4000_IDE)) && !AMIGAHW_PRESENT(A1200_IDE))
+	return;
+
+    for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
+	ide_ioreg_t base, ctrlport, irqport;
+	ide_ack_intr_t *ack_intr;
+	hw_regs_t hw;
+	int index;
+	unsigned long phys_base, res_start, res_n;
+
+	if (a4000) {
+	    phys_base = GAYLE_BASE_4000;
+	    irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_4000);
+	    ack_intr = gayle_ack_intr_a4000;
+	} else {
+	    phys_base = GAYLE_BASE_1200;
+	    irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_1200);
+	    ack_intr = gayle_ack_intr_a1200;
+	}
+/*
+ * FIXME: we now have selectable modes between mmio v/s iomio
+ */
+
+	phys_base += i*GAYLE_NEXT_PORT;
+
+	res_start = ((unsigned long)phys_base) & ~(GAYLE_NEXT_PORT-1);
+	res_n = GAYLE_IDEREG_SIZE;
+
+	if (!request_mem_region(res_start, res_n, "IDE"))
+	    continue;
+
+	base = (ide_ioreg_t)ZTWO_VADDR(phys_base);
+	ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0;
+
+	ide_setup_ports(&hw, base, gayle_offsets,
+			ctrlport, irqport, ack_intr,
+//			gaule_iops,
+			IRQ_AMIGA_PORTS);
+
+	index = ide_register_hw(&hw, NULL);
+	if (index != -1) {
+	    switch (i) {
+		case 0:
+		    printk("ide%d: Gayle IDE interface (A%d style)\n", index,
+			   a4000 ? 4000 : 1200);
+		    break;
+#ifdef CONFIG_BLK_DEV_IDEDOUBLER
+		case 1:
+		    printk("ide%d: IDE doubler\n", index);
+		    break;
+#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
+	    }
+	} else
+	    release_mem_region(res_start, res_n);
+
+#if 1 /* TESTING */
+	if (i == 1) {
+	    volatile u_short *addr = (u_short *)base;
+	    u_short data;
+	    printk("+++ Probing for IDE doubler... ");
+	    *addr = 0xffff;
+	    data = *addr;
+	    printk("probe returned 0x%02x (PLEASE REPORT THIS!!)\n", data);
+	}
+#endif /* TESTING */
+    }
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/hd.c linux-2.4.21/drivers/ide/legacy/hd.c
--- linux-2.4.20/drivers/ide/legacy/hd.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/legacy/hd.c	2002-12-18 18:58:03.000000000 +0000
@@ -0,0 +1,926 @@
+/*
+ *  linux/drivers/ide/hd.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * This is the low-level hd interrupt support. It traverses the
+ * request-list, using interrupts to jump between functions. As
+ * all the functions are called within interrupts, we may not
+ * sleep. Special care is recommended.
+ * 
+ *  modified by Drew Eckhardt to check nr of hd's from the CMOS.
+ *
+ *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
+ *  in the early extended-partition checks and added DM partitions
+ *
+ *  IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
+ *  and general streamlining by Mark Lord.
+ *
+ *  Removed 99% of above. Use Mark's ide driver for those options.
+ *  This is now a lightweight ST-506 driver. (Paul Gortmaker)
+ *
+ *  Modified 1995 Russell King for ARM processor.
+ *
+ *  Bugfix: max_sectors must be <= 255 or the wheels tend to come
+ *  off in a hurry once you queue things up - Paul G. 02/2001
+ */
+  
+/* Uncomment the following if you want verbose error reports. */
+/* #define VERBOSE_ERRORS */
+  
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/fs.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/kernel.h>
+#include <linux/hdreg.h>
+#include <linux/genhd.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/mc146818rtc.h> /* CMOS defines */
+#include <linux/init.h>
+#include <linux/blkpg.h>
+#include <linux/ide.h>
+
+#define REALLY_SLOW_IO
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#define MAJOR_NR HD_MAJOR
+#include <linux/blk.h>
+
+#ifdef __arm__
+#undef  HD_IRQ
+#endif
+#include <asm/irq.h>
+#ifdef __arm__
+#define HD_IRQ IRQ_HARDDISK
+#endif
+
+static int revalidate_hddisk(kdev_t, int);
+
+#define	HD_DELAY	0
+
+#define MAX_ERRORS     16	/* Max read/write errors/sector */
+#define RESET_FREQ      8	/* Reset controller every 8th retry */
+#define RECAL_FREQ      4	/* Recalibrate every 4th retry */
+#define MAX_HD		2
+
+#define STAT_OK		(READY_STAT|SEEK_STAT)
+#define OK_STATUS(s)	(((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK)
+
+static void recal_intr(void);
+static void bad_rw_intr(void);
+
+static char recalibrate[MAX_HD];
+static char special_op[MAX_HD];
+static int access_count[MAX_HD];
+static char busy[MAX_HD];
+static DECLARE_WAIT_QUEUE_HEAD(busy_wait);
+
+static int reset;
+static int hd_error;
+
+#define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0)
+
+/*
+ *  This struct defines the HD's and their types.
+ */
+struct hd_i_struct {
+	unsigned int head,sect,cyl,wpcom,lzone,ctl;
+};
+	
+#ifdef HD_TYPE
+static struct hd_i_struct hd_info[] = { HD_TYPE };
+static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
+#else
+static struct hd_i_struct hd_info[MAX_HD];
+static int NR_HD;
+#endif
+
+static struct hd_struct hd[MAX_HD<<6];
+static int hd_sizes[MAX_HD<<6];
+static int hd_blocksizes[MAX_HD<<6];
+static int hd_hardsectsizes[MAX_HD<<6];
+static int hd_maxsect[MAX_HD<<6];
+
+static struct timer_list device_timer;
+
+#define SET_TIMER 							\
+	do {								\
+		mod_timer(&device_timer, jiffies + TIMEOUT_VALUE);	\
+	} while (0)
+
+#define CLEAR_TIMER del_timer(&device_timer);
+
+#undef SET_INTR
+
+#define SET_INTR(x) \
+if ((DEVICE_INTR = (x)) != NULL) \
+	SET_TIMER; \
+else \
+	CLEAR_TIMER;
+
+
+#if (HD_DELAY > 0)
+unsigned long last_req;
+
+unsigned long read_timer(void)
+{
+	unsigned long t, flags;
+	int i;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	t = jiffies * 11932;
+    	outb_p(0, 0x43);
+	i = inb_p(0x40);
+	i |= inb(0x40) << 8;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return(t - i);
+}
+#endif
+
+void __init hd_setup(char *str, int *ints)
+{
+	int hdind = 0;
+
+	if (ints[0] != 3)
+		return;
+	if (hd_info[0].head != 0)
+		hdind=1;
+	hd_info[hdind].head = ints[2];
+	hd_info[hdind].sect = ints[3];
+	hd_info[hdind].cyl = ints[1];
+	hd_info[hdind].wpcom = 0;
+	hd_info[hdind].lzone = ints[1];
+	hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
+	NR_HD = hdind+1;
+}
+
+static void dump_status (const char *msg, unsigned int stat)
+{
+	unsigned long flags;
+	char devc;
+
+	devc = !QUEUE_EMPTY ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
+	save_flags (flags);
+	sti();
+#ifdef VERBOSE_ERRORS
+	printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff);
+	if (stat & BUSY_STAT)	printk("Busy ");
+	if (stat & READY_STAT)	printk("DriveReady ");
+	if (stat & WRERR_STAT)	printk("WriteFault ");
+	if (stat & SEEK_STAT)	printk("SeekComplete ");
+	if (stat & DRQ_STAT)	printk("DataRequest ");
+	if (stat & ECC_STAT)	printk("CorrectedError ");
+	if (stat & INDEX_STAT)	printk("Index ");
+	if (stat & ERR_STAT)	printk("Error ");
+	printk("}\n");
+	if ((stat & ERR_STAT) == 0) {
+		hd_error = 0;
+	} else {
+		hd_error = inb(HD_ERROR);
+		printk("hd%c: %s: error=0x%02x { ", devc, msg, hd_error & 0xff);
+		if (hd_error & BBD_ERR)		printk("BadSector ");
+		if (hd_error & ECC_ERR)		printk("UncorrectableError ");
+		if (hd_error & ID_ERR)		printk("SectorIdNotFound ");
+		if (hd_error & ABRT_ERR)	printk("DriveStatusError ");
+		if (hd_error & TRK0_ERR)	printk("TrackZeroNotFound ");
+		if (hd_error & MARK_ERR)	printk("AddrMarkNotFound ");
+		printk("}");
+		if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
+			printk(", CHS=%d/%d/%d",
+				(inb(HD_HCYL)<<8) + inb(HD_LCYL),
+				inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
+			if (!QUEUE_EMPTY)
+				printk(", sector=%ld", CURRENT->sector);
+		}
+		printk("\n");
+	}
+#else
+	printk("hd%c: %s: status=0x%02x.\n", devc, msg, stat & 0xff);
+	if ((stat & ERR_STAT) == 0) {
+		hd_error = 0;
+	} else {
+		hd_error = inb(HD_ERROR);
+		printk("hd%c: %s: error=0x%02x.\n", devc, msg, hd_error & 0xff);
+	}
+#endif	/* verbose errors */
+	restore_flags (flags);
+}
+
+void check_status(void)
+{
+	int i = inb_p(HD_STATUS);
+
+	if (!OK_STATUS(i)) {
+		dump_status("check_status", i);
+		bad_rw_intr();
+	}
+}
+
+static int controller_busy(void)
+{
+	int retries = 100000;
+	unsigned char status;
+
+	do {
+		status = inb_p(HD_STATUS);
+	} while ((status & BUSY_STAT) && --retries);
+	return status;
+}
+
+static int status_ok(void)
+{
+	unsigned char status = inb_p(HD_STATUS);
+
+	if (status & BUSY_STAT)
+		return 1;	/* Ancient, but does it make sense??? */
+	if (status & WRERR_STAT)
+		return 0;
+	if (!(status & READY_STAT))
+		return 0;
+	if (!(status & SEEK_STAT))
+		return 0;
+	return 1;
+}
+
+static int controller_ready(unsigned int drive, unsigned int head)
+{
+	int retry = 100;
+
+	do {
+		if (controller_busy() & BUSY_STAT)
+			return 0;
+		outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
+		if (status_ok())
+			return 1;
+	} while (--retry);
+	return 0;
+}
+
+static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
+		unsigned int head,unsigned int cyl,unsigned int cmd,
+		void (*intr_addr)(void))
+{
+	unsigned short port;
+
+#if (HD_DELAY > 0)
+	while (read_timer() - last_req < HD_DELAY)
+		/* nothing */;
+#endif
+	if (reset)
+		return;
+	if (!controller_ready(drive, head)) {
+		reset = 1;
+		return;
+	}
+	SET_INTR(intr_addr);
+	outb_p(hd_info[drive].ctl,HD_CMD);
+	port=HD_DATA;
+	outb_p(hd_info[drive].wpcom>>2,++port);
+	outb_p(nsect,++port);
+	outb_p(sect,++port);
+	outb_p(cyl,++port);
+	outb_p(cyl>>8,++port);
+	outb_p(0xA0|(drive<<4)|head,++port);
+	outb_p(cmd,++port);
+}
+
+static void hd_request (void);
+
+static int drive_busy(void)
+{
+	unsigned int i;
+	unsigned char c;
+
+	for (i = 0; i < 500000 ; i++) {
+		c = inb_p(HD_STATUS);
+		if ((c & (BUSY_STAT | READY_STAT | SEEK_STAT)) == STAT_OK)
+			return 0;
+	}
+	dump_status("reset timed out", c);
+	return 1;
+}
+
+static void reset_controller(void)
+{
+	int	i;
+
+	outb_p(4,HD_CMD);
+	for(i = 0; i < 1000; i++) barrier();
+	outb_p(hd_info[0].ctl & 0x0f,HD_CMD);
+	for(i = 0; i < 1000; i++) barrier();
+	if (drive_busy())
+		printk("hd: controller still busy\n");
+	else if ((hd_error = inb(HD_ERROR)) != 1)
+		printk("hd: controller reset failed: %02x\n",hd_error);
+}
+
+static void reset_hd(void)
+{
+	static int i;
+
+repeat:
+	if (reset) {
+		reset = 0;
+		i = -1;
+		reset_controller();
+	} else {
+		check_status();
+		if (reset)
+			goto repeat;
+	}
+	if (++i < NR_HD) {
+		special_op[i] = recalibrate[i] = 1;
+		hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
+			hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
+		if (reset)
+			goto repeat;
+	} else
+		hd_request();
+}
+
+void do_reset_hd(void)
+{
+	DEVICE_INTR = NULL;
+	reset = 1;
+	reset_hd();
+}
+
+/*
+ * Ok, don't know what to do with the unexpected interrupts: on some machines
+ * doing a reset and a retry seems to result in an eternal loop. Right now I
+ * ignore it, and just set the timeout.
+ *
+ * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
+ * drive enters "idle", "standby", or "sleep" mode, so if the status looks
+ * "good", we just ignore the interrupt completely.
+ */
+void unexpected_hd_interrupt(void)
+{
+	unsigned int stat = inb_p(HD_STATUS);
+
+	if (stat & (BUSY_STAT|DRQ_STAT|ECC_STAT|ERR_STAT)) {
+		dump_status ("unexpected interrupt", stat);
+		SET_TIMER;
+	}
+}
+
+/*
+ * bad_rw_intr() now tries to be a bit smarter and does things
+ * according to the error returned by the controller.
+ * -Mika Liljeberg (liljeber@cs.Helsinki.FI)
+ */
+static void bad_rw_intr(void)
+{
+	int dev;
+
+	if (QUEUE_EMPTY)
+		return;
+	dev = DEVICE_NR(CURRENT->rq_dev);
+	if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
+		end_request(0);
+		special_op[dev] = recalibrate[dev] = 1;
+	} else if (CURRENT->errors % RESET_FREQ == 0)
+		reset = 1;
+	else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
+		special_op[dev] = recalibrate[dev] = 1;
+	/* Otherwise just retry */
+}
+
+static inline int wait_DRQ(void)
+{
+	int retries = 100000, stat;
+
+	while (--retries > 0)
+		if ((stat = inb_p(HD_STATUS)) & DRQ_STAT)
+			return 0;
+	dump_status("wait_DRQ", stat);
+	return -1;
+}
+
+static void read_intr(void)
+{
+	int i, retries = 100000;
+
+	do {
+		i = (unsigned) inb_p(HD_STATUS);
+		if (i & BUSY_STAT)
+			continue;
+		if (!OK_STATUS(i))
+			break;
+		if (i & DRQ_STAT)
+			goto ok_to_read;
+	} while (--retries > 0);
+	dump_status("read_intr", i);
+	bad_rw_intr();
+	hd_request();
+	return;
+ok_to_read:
+	insw(HD_DATA,CURRENT->buffer,256);
+	CURRENT->sector++;
+	CURRENT->buffer += 512;
+	CURRENT->errors = 0;
+	i = --CURRENT->nr_sectors;
+	--CURRENT->current_nr_sectors;
+#ifdef DEBUG
+	printk("hd%c: read: sector %ld, remaining = %ld, buffer=0x%08lx\n",
+		dev+'a', CURRENT->sector, CURRENT->nr_sectors,
+		(unsigned long) CURRENT->buffer+512));
+#endif
+	if (CURRENT->current_nr_sectors <= 0)
+		end_request(1);
+	if (i > 0) {
+		SET_INTR(&read_intr);
+		return;
+	}
+	(void) inb_p(HD_STATUS);
+#if (HD_DELAY > 0)
+	last_req = read_timer();
+#endif
+	if (!QUEUE_EMPTY)
+		hd_request();
+	return;
+}
+
+static void write_intr(void)
+{
+	int i;
+	int retries = 100000;
+
+	do {
+		i = (unsigned) inb_p(HD_STATUS);
+		if (i & BUSY_STAT)
+			continue;
+		if (!OK_STATUS(i))
+			break;
+		if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
+			goto ok_to_write;
+	} while (--retries > 0);
+	dump_status("write_intr", i);
+	bad_rw_intr();
+	hd_request();
+	return;
+ok_to_write:
+	CURRENT->sector++;
+	i = --CURRENT->nr_sectors;
+	--CURRENT->current_nr_sectors;
+	CURRENT->buffer += 512;
+	if (!i || (CURRENT->bh && !SUBSECTOR(i)))
+		end_request(1);
+	if (i > 0) {
+		SET_INTR(&write_intr);
+		outsw(HD_DATA,CURRENT->buffer,256);
+		sti();
+	} else {
+#if (HD_DELAY > 0)
+		last_req = read_timer();
+#endif
+		hd_request();
+	}
+	return;
+}
+
+static void recal_intr(void)
+{
+	check_status();
+#if (HD_DELAY > 0)
+	last_req = read_timer();
+#endif
+	hd_request();
+}
+
+/*
+ * This is another of the error-routines I don't know what to do with. The
+ * best idea seems to just set reset, and start all over again.
+ */
+static void hd_times_out(unsigned long dummy)
+{
+	unsigned int dev;
+
+	DEVICE_INTR = NULL;
+	if (QUEUE_EMPTY)
+		return;
+	disable_irq(HD_IRQ);
+	sti();
+	reset = 1;
+	dev = DEVICE_NR(CURRENT->rq_dev);
+	printk("hd%c: timeout\n", dev+'a');
+	if (++CURRENT->errors >= MAX_ERRORS) {
+#ifdef DEBUG
+		printk("hd%c: too many errors\n", dev+'a');
+#endif
+		end_request(0);
+	}
+	cli();
+	hd_request();
+	enable_irq(HD_IRQ);
+}
+
+int do_special_op (unsigned int dev)
+{
+	if (recalibrate[dev]) {
+		recalibrate[dev] = 0;
+		hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
+		return reset;
+	}
+	if (hd_info[dev].head > 16) {
+		printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
+		end_request(0);
+	}
+	special_op[dev] = 0;
+	return 1;
+}
+
+/*
+ * The driver enables interrupts as much as possible.  In order to do this,
+ * (a) the device-interrupt is disabled before entering hd_request(),
+ * and (b) the timeout-interrupt is disabled before the sti().
+ *
+ * Interrupts are still masked (by default) whenever we are exchanging
+ * data/cmds with a drive, because some drives seem to have very poor
+ * tolerance for latency during I/O. The IDE driver has support to unmask
+ * interrupts for non-broken hardware, so use that driver if required.
+ */
+static void hd_request(void)
+{
+	unsigned int dev, block, nsect, sec, track, head, cyl;
+
+	if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE) return;
+	if (DEVICE_INTR)
+		return;
+repeat:
+	del_timer(&device_timer);
+	sti();
+	INIT_REQUEST;
+	if (reset) {
+		cli();
+		reset_hd();
+		return;
+	}
+	dev = MINOR(CURRENT->rq_dev);
+	block = CURRENT->sector;
+	nsect = CURRENT->nr_sectors;
+	if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects || ((block+nsect) > hd[dev].nr_sects)) {
+#ifdef DEBUG
+		if (dev >= (NR_HD<<6))
+			printk("hd: bad minor number: device=%s\n",
+			       kdevname(CURRENT->rq_dev));
+		else
+			printk("hd%c: bad access: block=%d, count=%d\n",
+				(MINOR(CURRENT->rq_dev)>>6)+'a', block, nsect);
+#endif
+		end_request(0);
+		goto repeat;
+	}
+	block += hd[dev].start_sect;
+	dev >>= 6;
+	if (special_op[dev]) {
+		if (do_special_op(dev))
+			goto repeat;
+		return;
+	}
+	sec   = block % hd_info[dev].sect + 1;
+	track = block / hd_info[dev].sect;
+	head  = track % hd_info[dev].head;
+	cyl   = track / hd_info[dev].head;
+#ifdef DEBUG
+	printk("hd%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx\n",
+		dev+'a', (CURRENT->cmd == READ)?"read":"writ",
+		cyl, head, sec, nsect, (unsigned long) CURRENT->buffer);
+#endif
+	if (CURRENT->cmd == READ) {
+		hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
+		if (reset)
+			goto repeat;
+		return;
+	}
+	if (CURRENT->cmd == WRITE) {
+		hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
+		if (reset)
+			goto repeat;
+		if (wait_DRQ()) {
+			bad_rw_intr();
+			goto repeat;
+		}
+		outsw(HD_DATA,CURRENT->buffer,256);
+		return;
+	}
+	panic("unknown hd-command");
+}
+
+static void do_hd_request (request_queue_t * q)
+{
+	disable_irq(HD_IRQ);
+	hd_request();
+	enable_irq(HD_IRQ);
+}
+
+static int hd_ioctl(struct inode * inode, struct file * file,
+	unsigned int cmd, unsigned long arg)
+{
+	struct hd_geometry *loc = (struct hd_geometry *) arg;
+	int dev;
+
+	if ((!inode) || !(inode->i_rdev))
+		return -EINVAL;
+	dev = DEVICE_NR(inode->i_rdev);
+	if (dev >= NR_HD)
+		return -EINVAL;
+	switch (cmd) {
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry g; 
+			if (!loc)  return -EINVAL;
+			g.heads = hd_info[dev].head;
+			g.sectors = hd_info[dev].sect;
+			g.cylinders = hd_info[dev].cyl;
+			g.start = hd[MINOR(inode->i_rdev)].start_sect;
+			return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; 
+		}
+
+         	case BLKGETSIZE:   /* Return device size */
+			return put_user(hd[MINOR(inode->i_rdev)].nr_sects, 
+					(unsigned long *) arg);
+         	case BLKGETSIZE64:
+			return put_user((u64)hd[MINOR(inode->i_rdev)].nr_sects << 9, 
+					(u64 *) arg);
+
+		case BLKRRPART: /* Re-read partition tables */
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+			return revalidate_hddisk(inode->i_rdev, 1);
+
+		case BLKROSET:
+		case BLKROGET:
+		case BLKRASET:
+		case BLKRAGET:
+		case BLKFLSBUF:
+		case BLKPG:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
+
+		default:
+			return -EINVAL;
+	}
+}
+
+static int hd_open(struct inode * inode, struct file * filp)
+{
+	int target;
+	target =  DEVICE_NR(inode->i_rdev);
+
+	if (target >= NR_HD)
+		return -ENODEV;
+	while (busy[target])
+		sleep_on(&busy_wait);
+	access_count[target]++;
+	return 0;
+}
+
+/*
+ * Releasing a block device means we sync() it, so that it can safely
+ * be forgotten about...
+ */
+static int hd_release(struct inode * inode, struct file * file)
+{
+        int target =  DEVICE_NR(inode->i_rdev);
+	access_count[target]--;
+	return 0;
+}
+
+extern struct block_device_operations hd_fops;
+
+static struct gendisk hd_gendisk = {
+	major:		MAJOR_NR,
+	major_name:	"hd",
+	minor_shift:	6,
+	max_p:		1 << 6,
+	part:		hd,
+	sizes:		hd_sizes,
+	fops:		&hd_fops,
+};
+	
+static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	void (*handler)(void) = DEVICE_INTR;
+
+	DEVICE_INTR = NULL;
+	del_timer(&device_timer);
+	if (!handler)
+		handler = unexpected_hd_interrupt;
+	handler();
+	sti();
+}
+
+static struct block_device_operations hd_fops = {
+	open:		hd_open,
+	release:	hd_release,
+	ioctl:		hd_ioctl,
+};
+
+/*
+ * This is the hard disk IRQ description. The SA_INTERRUPT in sa_flags
+ * means we run the IRQ-handler with interrupts disabled:  this is bad for
+ * interrupt latency, but anything else has led to problems on some
+ * machines.
+ *
+ * We enable interrupts in some of the routines after making sure it's
+ * safe.
+ */
+static void __init hd_geninit(void)
+{
+	int drive;
+
+	for(drive=0; drive < (MAX_HD << 6); drive++) {
+		hd_blocksizes[drive] = 1024;
+		hd_hardsectsizes[drive] = 512;
+		hd_maxsect[drive]=255;
+	}
+	blksize_size[MAJOR_NR] = hd_blocksizes;
+	hardsect_size[MAJOR_NR] = hd_hardsectsizes;
+	max_sectors[MAJOR_NR] = hd_maxsect;
+
+#ifdef __i386__
+	if (!NR_HD) {
+		extern struct drive_info drive_info;
+		unsigned char *BIOS = (unsigned char *) &drive_info;
+		unsigned long flags;
+		int cmos_disks;
+
+		for (drive=0 ; drive<2 ; drive++) {
+			hd_info[drive].cyl = *(unsigned short *) BIOS;
+			hd_info[drive].head = *(2+BIOS);
+			hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
+			hd_info[drive].ctl = *(8+BIOS);
+			hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
+			hd_info[drive].sect = *(14+BIOS);
+#ifdef does_not_work_for_everybody_with_scsi_but_helps_ibm_vp
+			if (hd_info[drive].cyl && NR_HD == drive)
+				NR_HD++;
+#endif
+			BIOS += 16;
+		}
+
+	/*
+		We query CMOS about hard disks : it could be that 
+		we have a SCSI/ESDI/etc controller that is BIOS
+		compatible with ST-506, and thus showing up in our
+		BIOS table, but not register compatible, and therefore
+		not present in CMOS.
+
+		Furthermore, we will assume that our ST-506 drives
+		<if any> are the primary drives in the system, and 
+		the ones reflected as drive 1 or 2.
+
+		The first drive is stored in the high nibble of CMOS
+		byte 0x12, the second in the low nibble.  This will be
+		either a 4 bit drive type or 0xf indicating use byte 0x19 
+		for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
+
+		Needless to say, a non-zero value means we have 
+		an AT controller hard disk for that drive.
+
+		Currently the rtc_lock is a bit academic since this
+		driver is non-modular, but someday... ?         Paul G.
+	*/
+
+		spin_lock_irqsave(&rtc_lock, flags);
+		cmos_disks = CMOS_READ(0x12);
+		spin_unlock_irqrestore(&rtc_lock, flags);
+
+		if (cmos_disks & 0xf0) {
+			if (cmos_disks & 0x0f)
+				NR_HD = 2;
+			else
+				NR_HD = 1;
+		}
+	}
+#endif /* __i386__ */
+#ifdef __arm__
+	if (!NR_HD) {
+		/* We don't know anything about the drive.  This means
+		 * that you *MUST* specify the drive parameters to the
+		 * kernel yourself.
+		 */
+		printk("hd: no drives specified - use hd=cyl,head,sectors"
+			" on kernel command line\n");
+	}
+#endif
+
+	for (drive=0 ; drive < NR_HD ; drive++) {
+		hd[drive<<6].nr_sects = hd_info[drive].head *
+			hd_info[drive].sect * hd_info[drive].cyl;
+		printk ("hd%c: %ldMB, CHS=%d/%d/%d\n", drive+'a',
+			hd[drive<<6].nr_sects / 2048, hd_info[drive].cyl,
+			hd_info[drive].head, hd_info[drive].sect);
+	}
+	if (!NR_HD)
+		return;
+
+	if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd", NULL)) {
+		printk("hd: unable to get IRQ%d for the hard disk driver\n",
+			HD_IRQ);
+		NR_HD = 0;
+		return;
+	}
+	request_region(HD_DATA, 8, "hd");
+	request_region(HD_CMD, 1, "hd(cmd)");
+
+	hd_gendisk.nr_real = NR_HD;
+
+	for(drive=0; drive < NR_HD; drive++)
+		register_disk(&hd_gendisk, MKDEV(MAJOR_NR,drive<<6), 1<<6,
+			&hd_fops, hd_info[drive].head * hd_info[drive].sect *
+			hd_info[drive].cyl);
+}
+
+int __init hd_init(void)
+{
+	if (devfs_register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
+		printk("hd: unable to get major %d for hard disk\n",MAJOR_NR);
+		return -1;
+	}
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
+	read_ahead[MAJOR_NR] = 8;		/* 8 sector (4kB) read-ahead */
+	add_gendisk(&hd_gendisk);
+	init_timer(&device_timer);
+	device_timer.function = hd_times_out;
+	hd_geninit();
+	return 0;
+}
+
+#define DEVICE_BUSY busy[target]
+#define USAGE access_count[target]
+#define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl)
+/* We assume that the BIOS parameters do not change, so the disk capacity
+   will not change */
+#undef MAYBE_REINIT
+#define GENDISK_STRUCT hd_gendisk
+
+/*
+ * This routine is called to flush all partitions and partition tables
+ * for a changed disk, and then re-read the new partition table.
+ * If we are revalidating a disk because of a media change, then we
+ * enter with usage == 0.  If we are using an ioctl, we automatically have
+ * usage == 1 (we need an open channel to use an ioctl :-), so this
+ * is our limit.
+ */
+static int revalidate_hddisk(kdev_t dev, int maxusage)
+{
+	int target;
+	struct gendisk * gdev;
+	int max_p;
+	int start;
+	int i;
+	long flags;
+
+	target = DEVICE_NR(dev);
+	gdev = &GENDISK_STRUCT;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (DEVICE_BUSY || USAGE > maxusage) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return -EBUSY;
+	}
+	DEVICE_BUSY = 1;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	max_p = gdev->max_p;
+	start = target << gdev->minor_shift;
+
+	for (i=max_p - 1; i >=0 ; i--) {
+		int minor = start + i;
+		invalidate_device(MKDEV(MAJOR_NR, minor), 1);
+		gdev->part[minor].start_sect = 0;
+		gdev->part[minor].nr_sects = 0;
+	}
+
+#ifdef MAYBE_REINIT
+	MAYBE_REINIT;
+#endif
+
+	grok_partitions(gdev, target, 1<<6, CAPACITY);
+
+	DEVICE_BUSY = 0;
+	wake_up(&busy_wait);
+	return 0;
+}
+
+static int parse_hd_setup (char *line) {
+	int ints[6];
+
+	(void) get_options(line, ARRAY_SIZE(ints), ints);
+	hd_setup(NULL, ints);
+
+	return 1;
+}
+__setup("hd=", parse_hd_setup);
+
+module_init(hd_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/ht6560b.c linux-2.4.21/drivers/ide/legacy/ht6560b.c
--- linux-2.4.20/drivers/ide/legacy/ht6560b.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/legacy/ht6560b.c	2002-12-18 18:58:04.000000000 +0000
@@ -0,0 +1,430 @@
+/*
+ *  linux/drivers/ide/ht6560b.c		Version 0.07	Feb  1, 2000
+ *
+ *  Copyright (C) 1995-2000  Linus Torvalds & author (see below)
+ */
+
+/*
+ *
+ *  Version 0.01        Initial version hacked out of ide.c
+ *
+ *  Version 0.02        Added support for PIO modes, auto-tune
+ *
+ *  Version 0.03        Some cleanups
+ *
+ *  Version 0.05        PIO mode cycle timings auto-tune using bus-speed
+ *
+ *  Version 0.06        Prefetch mode now defaults no OFF. To set
+ *                      prefetch mode OFF/ON use "hdparm -p8/-p9".
+ *                      Unmask irq is disabled when prefetch mode
+ *                      is enabled.
+ *
+ *  Version 0.07        Trying to fix CD-ROM detection problem.
+ *                      "Prefetch" mode bit OFF for ide disks and
+ *                      ON for anything else.
+ *
+ *
+ *  HT-6560B EIDE-controller support
+ *  To activate controller support use kernel parameter "ide0=ht6560b".
+ *  Use hdparm utility to enable PIO mode support.
+ *
+ *  Author:    Mikko Ala-Fossi            <maf@iki.fi>
+ *             Jan Evert van Grootheest   <janevert@iae.nl>
+ *
+ *  Try:  http://www.maf.iki.fi/~maf/ht6560b/
+ */
+
+#define HT6560B_VERSION "v0.07"
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_HT6560B_MODULE
+# define _IDE_C
+# include "ide_modes.h"
+# undef _IDE_C
+#else
+# include "ide_modes.h"
+#endif /* CONFIG_BLK_DEV_HT6560B_MODULE */
+
+/* #define DEBUG */  /* remove comments for DEBUG messages */
+
+/*
+ * The special i/o-port that HT-6560B uses to configuration:
+ *    bit0 (0x01): "1" selects secondary interface
+ *    bit2 (0x04): "1" enables FIFO function
+ *    bit5 (0x20): "1" enables prefetched data read function  (???)
+ *
+ * The special i/o-port that HT-6560A uses to configuration:
+ *    bit0 (0x01): "1" selects secondary interface
+ *    bit1 (0x02): "1" enables prefetched data read function
+ *    bit2 (0x04): "0" enables multi-master system	      (?)
+ *    bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time	      (?)
+ */
+#define HT_CONFIG_PORT	  0x3e6
+#define HT_CONFIG(drivea) (u8)(((drivea)->drive_data & 0xff00) >> 8)
+/*
+ * FIFO + PREFETCH (both a/b-model)
+ */
+#define HT_CONFIG_DEFAULT 0x1c /* no prefetch */
+/* #define HT_CONFIG_DEFAULT 0x3c */ /* with prefetch */
+#define HT_SECONDARY_IF	  0x01
+#define HT_PREFETCH_MODE  0x20
+
+/*
+ * ht6560b Timing values:
+ *
+ * I reviewed some assembler source listings of htide drivers and found
+ * out how they setup those cycle time interfacing values, as they at Holtek
+ * call them. IDESETUP.COM that is supplied with the drivers figures out
+ * optimal values and fetches those values to drivers. I found out that
+ * they use IDE_SELECT_REG to fetch timings to the ide board right after
+ * interface switching. After that it was quite easy to add code to
+ * ht6560b.c.
+ *
+ * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine
+ * for hda and hdc. But hdb needed higher values to work, so I guess
+ * that sometimes it is necessary to give higher value than IDESETUP
+ * gives.   [see cmd640.c for an extreme example of this. -ml]
+ *
+ * Perhaps I should explain something about these timing values:
+ * The higher nibble of value is the Recovery Time  (rt) and the lower nibble
+ * of the value is the Active Time  (at). Minimum value 2 is the fastest and
+ * the maximum value 15 is the slowest. Default values should be 15 for both.
+ * So 0x24 means 2 for rt and 4 for at. Each of the drives should have
+ * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or
+ * similar. If value is too small there will be all sorts of failures.
+ *
+ * Timing byte consists of
+ *	High nibble:  Recovery Cycle Time  (rt)
+ *	     The valid values range from 2 to 15. The default is 15.
+ *
+ *	Low nibble:   Active Cycle Time	   (at)
+ *	     The valid values range from 2 to 15. The default is 15.
+ *
+ * You can obtain optimized timing values by running Holtek IDESETUP.COM
+ * for DOS. DOS drivers get their timing values from command line, where
+ * the first value is the Recovery Time and the second value is the
+ * Active Time for each drive. Smaller value gives higher speed.
+ * In case of failures you should probably fall back to a higher value.
+ */
+#define HT_TIMING(drivea) (u8)((drivea)->drive_data & 0x00ff)
+#define HT_TIMING_DEFAULT 0xff
+
+/*
+ * This routine handles interface switching for the peculiar hardware design
+ * on the F.G.I./Holtek HT-6560B VLB IDE interface.
+ * The HT-6560B can only enable one IDE port at a time, and requires a
+ * silly sequence (below) whenever we switch between primary and secondary.
+ */
+
+/*
+ * This routine is invoked from ide.c to prepare for access to a given drive.
+ */
+static void ht6560b_selectproc (ide_drive_t *drive)
+{
+	unsigned long flags;
+	static u8 current_select = 0;
+	static u8 current_timing = 0;
+	u8 select, timing;
+	
+	local_irq_save(flags);
+	
+	select = HT_CONFIG(drive);
+	timing = HT_TIMING(drive);
+	
+	if (select != current_select || timing != current_timing) {
+		current_select = select;
+		current_timing = timing;
+		if (drive->media != ide_disk || !drive->present)
+			select |= HT_PREFETCH_MODE;
+		(void) HWIF(drive)->INB(HT_CONFIG_PORT);
+		(void) HWIF(drive)->INB(HT_CONFIG_PORT);
+		(void) HWIF(drive)->INB(HT_CONFIG_PORT);
+		(void) HWIF(drive)->INB(HT_CONFIG_PORT);
+		HWIF(drive)->OUTB(select, HT_CONFIG_PORT);
+		/*
+		 * Set timing for this drive:
+		 */
+		HWIF(drive)->OUTB(timing, IDE_SELECT_REG);
+		(void) HWIF(drive)->INB(IDE_STATUS_REG);
+#ifdef DEBUG
+		printk("ht6560b: %s: select=%#x timing=%#x\n",
+			drive->name, select, timing);
+#endif
+	}
+	local_irq_restore(flags);
+}
+
+/*
+ * Autodetection and initialization of ht6560b
+ */
+static int __init try_to_init_ht6560b(void)
+{
+	u8 orig_value;
+	int i;
+	
+	/* Autodetect ht6560b */
+	if ((orig_value = inb(HT_CONFIG_PORT)) == 0xff)
+		return 0;
+	
+	for (i=3;i>0;i--) {
+		outb(0x00, HT_CONFIG_PORT);
+		if (!( (~inb(HT_CONFIG_PORT)) & 0x3f )) {
+			outb(orig_value, HT_CONFIG_PORT);
+			return 0;
+		}
+	}
+	outb(0x00, HT_CONFIG_PORT);
+	if ((~inb(HT_CONFIG_PORT))& 0x3f) {
+		outb(orig_value, HT_CONFIG_PORT);
+		return 0;
+	}
+	/*
+	 * Ht6560b autodetected
+	 */
+	outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT);
+	outb(HT_TIMING_DEFAULT, 0x1f6);  /* IDE_SELECT_REG */
+	(void) inb(0x1f7);               /* IDE_STATUS_REG */
+	
+	printk("\nht6560b " HT6560B_VERSION
+	       ": chipset detected and initialized"
+#ifdef DEBUG
+	       " with debug enabled"
+#endif
+		);
+	return 1;
+}
+
+static u8 ht_pio2timings(ide_drive_t *drive, u8 pio)
+{
+	int active_time, recovery_time;
+	int active_cycles, recovery_cycles;
+	ide_pio_data_t d;
+	int bus_speed = system_bus_clock();
+	
+        if (pio) {
+		pio = ide_get_best_pio_mode(drive, pio, 5, &d);
+		
+		/*
+		 *  Just like opti621.c we try to calculate the
+		 *  actual cycle time for recovery and activity
+		 *  according system bus speed.
+		 */
+		active_time = ide_pio_timings[pio].active_time;
+		recovery_time = d.cycle_time 
+			- active_time
+			- ide_pio_timings[pio].setup_time;
+		/*
+		 *  Cycle times should be Vesa bus cycles
+		 */
+		active_cycles   = (active_time   * bus_speed + 999) / 1000;
+		recovery_cycles = (recovery_time * bus_speed + 999) / 1000;
+		/*
+		 *  Upper and lower limits
+		 */
+		if (active_cycles   < 2)  active_cycles   = 2;
+		if (recovery_cycles < 2)  recovery_cycles = 2;
+		if (active_cycles   > 15) active_cycles   = 15;
+		if (recovery_cycles > 15) recovery_cycles = 0;  /* 0==16 */
+		
+#ifdef DEBUG
+		printk("ht6560b: drive %s setting pio=%d recovery=%d (%dns) active=%d (%dns)\n", drive->name, pio, recovery_cycles, recovery_time, active_cycles, active_time);
+#endif
+		
+		return (u8)((recovery_cycles << 4) | active_cycles);
+	} else {
+		
+#ifdef DEBUG
+		printk("ht6560b: drive %s setting pio=0\n", drive->name);
+#endif
+		
+		return HT_TIMING_DEFAULT;    /* default setting */
+	}
+}
+
+/*
+ *  Enable/Disable so called prefetch mode
+ */
+static void ht_set_prefetch(ide_drive_t *drive, u8 state)
+{
+	unsigned long flags;
+	int t = HT_PREFETCH_MODE << 8;
+	
+	spin_lock_irqsave(&io_request_lock, flags);
+	
+	/*
+	 *  Prefetch mode and unmask irq seems to conflict
+	 */
+	if (state) {
+		drive->drive_data |= t;   /* enable prefetch mode */
+		drive->no_unmask = 1;
+		drive->unmask = 0;
+	} else {
+		drive->drive_data &= ~t;  /* disable prefetch mode */
+		drive->no_unmask = 0;
+	}
+	
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	
+#ifdef DEBUG
+	printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis"));
+#endif
+}
+
+static void tune_ht6560b (ide_drive_t *drive, u8 pio)
+{
+	unsigned long flags;
+	u8 timing;
+	
+	switch (pio) {
+	case 8:         /* set prefetch off */
+	case 9:         /* set prefetch on */
+		ht_set_prefetch(drive, pio & 1);
+		return;
+	}
+	
+	timing = ht_pio2timings(drive, pio);
+	
+	spin_lock_irqsave(&io_request_lock, flags);
+	
+	drive->drive_data &= 0xff00;
+	drive->drive_data |= timing;
+	
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	
+#ifdef DEBUG
+	printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing);
+#endif
+}
+
+void __init probe_ht6560b (void)
+{
+	int t;
+	
+	request_region(HT_CONFIG_PORT, 1, ide_hwifs[0].name);
+	ide_hwifs[0].chipset = ide_ht6560b;
+	ide_hwifs[1].chipset = ide_ht6560b;
+	ide_hwifs[0].selectproc = &ht6560b_selectproc;
+	ide_hwifs[1].selectproc = &ht6560b_selectproc;
+	ide_hwifs[0].tuneproc = &tune_ht6560b;
+	ide_hwifs[1].tuneproc = &tune_ht6560b;
+	ide_hwifs[0].serialized = 1;  /* is this needed? */
+	ide_hwifs[1].serialized = 1;  /* is this needed? */
+	ide_hwifs[0].mate = &ide_hwifs[1];
+	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
+			
+	/*
+	 * Setting default configurations for drives
+	 */
+	t = (HT_CONFIG_DEFAULT << 8);
+	t |= HT_TIMING_DEFAULT;
+	ide_hwifs[0].drives[0].drive_data = t;
+	ide_hwifs[0].drives[1].drive_data = t;
+	t |= (HT_SECONDARY_IF << 8);
+	ide_hwifs[1].drives[0].drive_data = t;
+	ide_hwifs[1].drives[1].drive_data = t;
+
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(&ide_hwifs[0]);
+	probe_hwif_init(&ide_hwifs[1]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+}
+
+void __init ht6560b_release (void)
+{
+	if (ide_hwifs[0].chipset != ide_ht6560b &&
+	    ide_hwifs[1].chipset != ide_ht6560b)
+                return;
+
+	ide_hwifs[0].chipset = ide_unknown;
+	ide_hwifs[1].chipset = ide_unknown;
+	ide_hwifs[0].tuneproc = NULL;
+	ide_hwifs[1].tuneproc = NULL;
+	ide_hwifs[0].selectproc = NULL;
+	ide_hwifs[1].selectproc = NULL;
+	ide_hwifs[0].serialized = 0;
+	ide_hwifs[1].serialized = 0;
+	ide_hwifs[0].mate = NULL;
+	ide_hwifs[1].mate = NULL;
+
+	ide_hwifs[0].drives[0].drive_data = 0;
+	ide_hwifs[0].drives[1].drive_data = 0;
+	ide_hwifs[1].drives[0].drive_data = 0;
+	ide_hwifs[1].drives[1].drive_data = 0;
+	release_region(HT_CONFIG_PORT, 1);
+}
+
+#ifndef MODULE
+/*
+ * init_ht6560b:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_ht6560b (void)
+{
+	if (check_region(HT_CONFIG_PORT,1)) {
+		printk(KERN_NOTICE "%s: HT_CONFIG_PORT not found\n",
+			__FUNCTION__);
+		return;
+	}
+	if (!try_to_init_ht6560b()) {
+                printk(KERN_NOTICE "%s: HBA not found\n", __FUNCTION__);
+		return;
+	}
+	probe_ht6560b();
+}
+
+#else
+
+MODULE_AUTHOR("See Local File");
+MODULE_DESCRIPTION("HT-6560B EIDE-controller support");
+MODULE_LICENSE("GPL");
+
+int __init ht6560b_mod_init(void)
+{
+	if (check_region(HT_CONFIG_PORT,1)) {
+		printk(KERN_NOTICE "%s: HT_CONFIG_PORT not found\n",
+			__FUNCTION__);
+		return -ENODEV;
+	}
+
+	if (!try_to_init_ht6560b()) {
+		printk(KERN_NOTICE "%s: HBA not found\n", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	probe_ht6560b();
+        if (ide_hwifs[0].chipset != ide_ht6560b &&
+            ide_hwifs[1].chipset != ide_ht6560b) {
+                ht6560b_release();
+                return -ENODEV;
+        }
+        return 0;
+}
+module_init(ht6560b_mod_init);
+
+void __init ht6560b_mod_exit(void)
+{
+        ht6560b_release();
+}
+module_exit(ht6560b_mod_exit);
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/ide-cs.c linux-2.4.21/drivers/ide/legacy/ide-cs.c
--- linux-2.4.20/drivers/ide/legacy/ide-cs.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/legacy/ide-cs.c	2002-12-18 18:58:06.000000000 +0000
@@ -0,0 +1,494 @@
+/*======================================================================
+
+    A driver for PCMCIA IDE/ATA disk cards
+
+    ide_cs.c 1.26 1999/11/16 02:10:49
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU General Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/hdreg.h>
+#include <linux/major.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"ide_cs.c 1.26 1999/11/16 02:10:49 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+MODULE_LICENSE("GPL");
+
+
+/*====================================================================*/
+
+static const char ide_major[] = {
+    IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
+#ifdef IDE4_MAJOR
+    IDE4_MAJOR, IDE5_MAJOR
+#endif
+};
+
+typedef struct ide_info_t {
+    dev_link_t	link;
+    int		ndev;
+    dev_node_t	node;
+    int		hd;
+} ide_info_t;
+
+static void ide_config(dev_link_t *link);
+static void ide_release(u_long arg);
+static int ide_event(event_t event, int priority,
+		     event_callback_args_t *args);
+
+static dev_info_t dev_info = "ide-cs";
+
+static dev_link_t *ide_attach(void);
+static void ide_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    ide_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+======================================================================*/
+
+static dev_link_t *ide_attach(void)
+{
+    ide_info_t *info;
+    dev_link_t *link;
+    client_reg_t client_reg;
+    int i, ret;
+    
+    DEBUG(0, "ide_attach()\n");
+
+    /* Create new ide device */
+    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    if (!info) return NULL;
+    memset(info, 0, sizeof(*info));
+    link = &info->link; link->priv = info;
+
+    link->release.function = &ide_release;
+    link->release.data = (u_long)link;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+    link->io.IOAddrLines = 3;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &ide_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != CS_SUCCESS) {
+	cs_error(link->handle, RegisterClient, ret);
+	ide_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* ide_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void ide_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+    int ret;
+
+    DEBUG(0, "ide_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG)
+	ide_release((u_long)link);
+    
+    if (link->handle) {
+	ret = CardServices(DeregisterClient, link->handle);
+	if (ret != CS_SUCCESS)
+	    cs_error(link->handle, DeregisterClient, ret);
+    }
+    
+    /* Unlink, free device structure */
+    *linkp = link->next;
+    kfree(link->priv);
+    
+} /* ide_detach */
+
+/*======================================================================
+
+    ide_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    ide device available to the system.
+
+======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+int idecs_register (int arg1, int arg2, int irq)
+{
+        hw_regs_t hw;
+        ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
+        hw.irq = irq;
+        hw.chipset = ide_pci; /* this enables IRQ sharing w/ PCI irqs */
+        return ide_register_hw(&hw, NULL);
+}
+
+void ide_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    ide_info_t *info = link->priv;
+    tuple_t tuple;
+    u_short buf[128];
+    cisparse_t parse;
+    config_info_t conf;
+    cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
+    cistpl_cftable_entry_t dflt = { 0 };
+    int i, pass, last_ret, last_fn, hd=-1, io_base, ctl_base;
+
+    DEBUG(0, "ide_config(0x%p)\n", link);
+    
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+    tuple.Attributes = 0;
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+    
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    /* Not sure if this is right... look up the current Vcc */
+    CS_CHECK(GetConfigurationInfo, handle, &conf);
+    link->conf.Vcc = conf.Vcc;
+    
+    pass = io_base = ctl_base = 0;
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    tuple.Attributes = 0;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    while (1) {
+	CFG_CHECK(GetTupleData, handle, &tuple);
+	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+
+	/* Check for matching Vcc, unless we're desperate */
+	if (!pass) {
+	    if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+		if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
+		    goto next_entry;
+	    } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
+		if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000)
+		    goto next_entry;
+	    }
+	}
+	
+	if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
+	    link->conf.Vpp1 = link->conf.Vpp2 =
+		cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+	else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
+	    link->conf.Vpp1 = link->conf.Vpp2 =
+		dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
+	
+	if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+	    cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
+	    link->conf.ConfigIndex = cfg->index;
+	    link->io.BasePort1 = io->win[0].base;
+	    link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+	    if (!(io->flags & CISTPL_IO_16BIT))
+		link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	    if (io->nwin == 2) {
+		link->io.NumPorts1 = 8;
+		link->io.BasePort2 = io->win[1].base;
+		link->io.NumPorts2 = 1;
+		CFG_CHECK(RequestIO, link->handle, &link->io);
+		io_base = link->io.BasePort1;
+		ctl_base = link->io.BasePort2;
+	    } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
+		link->io.NumPorts1 = io->win[0].len;
+		link->io.NumPorts2 = 0;
+		CFG_CHECK(RequestIO, link->handle, &link->io);
+		io_base = link->io.BasePort1;
+		ctl_base = link->io.BasePort1+0x0e;
+	    } else goto next_entry;
+	    /* If we've got this far, we're done */
+	    break;
+	}
+	
+    next_entry:
+	if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
+	if (pass) {
+	    CS_CHECK(GetNextTuple, handle, &tuple);
+	} else if (CardServices(GetNextTuple, handle, &tuple) != 0) {
+	    CS_CHECK(GetFirstTuple, handle, &tuple);
+	    memset(&dflt, 0, sizeof(dflt));
+	    pass++;
+	}
+    }
+    
+    CS_CHECK(RequestIRQ, handle, &link->irq);
+    CS_CHECK(RequestConfiguration, handle, &link->conf);
+
+    /* deal with brain dead IDE resource management */
+    release_region(link->io.BasePort1, link->io.NumPorts1);
+    if (link->io.NumPorts2)
+	release_region(link->io.BasePort2, link->io.NumPorts2);
+
+    /* retry registration in case device is still spinning up */
+    for (i = 0; i < 10; i++) {
+	if (ctl_base)
+	    outb(0x02, ctl_base); /* Set nIEN = disable device interrupts */
+	hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
+	if (hd >= 0) break;
+	if (link->io.NumPorts1 == 0x20) {
+	    if (ctl_base)
+		outb(0x02, ctl_base+0x10);
+	    hd = idecs_register(io_base+0x10, ctl_base+0x10,
+			      link->irq.AssignedIRQ);
+	    if (hd >= 0) {
+		io_base += 0x10; ctl_base += 0x10;
+		break;
+	    }
+	}
+	__set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ/10);
+    }
+    
+    if (hd < 0) {
+	printk(KERN_NOTICE "ide_cs: ide_register() at 0x%03x & 0x%03x"
+	       ", irq %u failed\n", io_base, ctl_base,
+	       link->irq.AssignedIRQ);
+	goto failed;
+    }
+
+    MOD_INC_USE_COUNT;
+    info->ndev = 1;
+    sprintf(info->node.dev_name, "hd%c", 'a'+(hd*2));
+    info->node.major = ide_major[hd];
+    info->node.minor = 0;
+    info->hd = hd;
+    link->dev = &info->node;
+    printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
+	   info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10,
+	   link->conf.Vpp1/10, link->conf.Vpp1%10);
+
+    link->state &= ~DEV_CONFIG_PENDING;
+    return;
+    
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    ide_release((u_long)link);
+
+} /* ide_config */
+
+/*======================================================================
+
+    After a card is removed, ide_release() will unregister the net
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+    
+======================================================================*/
+
+void ide_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    ide_info_t *info = link->priv;
+    
+    DEBUG(0, "ide_release(0x%p)\n", link);
+
+    if (info->ndev) {
+        /* FIXME: if this fails we need to queue the cleanup somehow
+           -- need to investigate the required PCMCIA magic */
+	ide_unregister(info->hd);
+	MOD_DEC_USE_COUNT;
+    }
+
+    request_region(link->io.BasePort1, link->io.NumPorts1,"ide-cs");
+    if (link->io.NumPorts2)
+	request_region(link->io.BasePort2, link->io.NumPorts2,"ide-cs");
+    
+    info->ndev = 0;
+    link->dev = NULL;
+    
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    
+    link->state &= ~DEV_CONFIG;
+
+} /* ide_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the ide drivers from
+    talking to the ports.
+    
+======================================================================*/
+
+int ide_event(event_t event, int priority,
+	      event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+
+    DEBUG(1, "ide_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG)
+	    mod_timer(&link->release, jiffies + HZ/20);
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	ide_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG)
+	    CardServices(ReleaseConfiguration, link->handle);
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (DEV_OK(link))
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	break;
+    }
+    return 0;
+} /* ide_event */
+
+/*====================================================================*/
+
+static int __init init_ide_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "ide_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    register_pccard_driver(&dev_info, &ide_attach, &ide_detach);
+    return 0;
+}
+
+static void __exit exit_ide_cs(void)
+{
+    DEBUG(0, "ide_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	ide_detach(dev_list);
+}
+
+module_init(init_ide_cs);
+module_exit(exit_ide_cs);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/macide.c linux-2.4.21/drivers/ide/legacy/macide.c
--- linux-2.4.20/drivers/ide/legacy/macide.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/legacy/macide.c	2002-12-18 18:58:03.000000000 +0000
@@ -0,0 +1,153 @@
+/*
+ *  linux/drivers/ide/macide.c -- Macintosh IDE Driver
+ *
+ *     Copyright (C) 1998 by Michael Schmitz
+ *
+ *  This driver was written based on information obtained from the MacOS IDE
+ *  driver binary by Mikael Forselius
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+
+#include <asm/machw.h>
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/mac_baboon.h>
+
+#define IDE_BASE 0x50F1A000	/* Base address of IDE controller */
+
+/*
+ * Generic IDE registers as offsets from the base
+ * These match MkLinux so they should be correct.
+ */
+
+#define IDE_DATA	0x00
+#define IDE_ERROR	0x04	/* see err-bits */
+#define IDE_NSECTOR	0x08	/* nr of sectors to read/write */
+#define IDE_SECTOR	0x0c	/* starting sector */
+#define IDE_LCYL	0x10	/* starting cylinder */
+#define IDE_HCYL	0x14	/* high byte of starting cyl */
+#define IDE_SELECT	0x18	/* 101dhhhh , d=drive, hhhh=head */
+#define IDE_STATUS	0x1c	/* see status-bits */
+#define IDE_CONTROL	0x38	/* control/altstatus */
+
+/*
+ * Mac-specific registers
+ */
+
+/*
+ * this register is odd; it doesn't seem to do much and it's
+ * not word-aligned like virtually every other hardware register
+ * on the Mac...
+ */
+
+#define IDE_IFR		0x101	/* (0x101) IDE interrupt flags on Quadra:
+				 *
+				 * Bit 0+1: some interrupt flags
+				 * Bit 2+3: some interrupt enable
+				 * Bit 4:   ??
+				 * Bit 5:   IDE interrupt flag (any hwif)
+				 * Bit 6:   maybe IDE interrupt enable (any hwif) ??
+				 * Bit 7:   Any interrupt condition
+				 */
+
+volatile unsigned char *ide_ifr = (unsigned char *) (IDE_BASE + IDE_IFR);
+
+static int macide_offsets[IDE_NR_PORTS] = {
+    IDE_DATA, IDE_ERROR,  IDE_NSECTOR, IDE_SECTOR, IDE_LCYL,
+    IDE_HCYL, IDE_SELECT, IDE_STATUS,  IDE_CONTROL
+};
+
+int macide_ack_intr(ide_hwif_t* hwif)
+{
+	if (*ide_ifr & 0x20) {
+		*ide_ifr &= ~0x20;
+		return 1;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
+static void macide_mediabay_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int state = baboon->mb_status & 0x04;
+
+	printk(KERN_INFO "macide: media bay %s detected\n", state? "removal":"insertion");
+}
+#endif
+
+/*
+ * Probe for a Macintosh IDE interface
+ */
+
+void macide_init(void)
+{
+	hw_regs_t hw;
+	int index = -1;
+
+	switch (macintosh_config->ide_type) {
+	case MAC_IDE_QUADRA:
+		ide_setup_ports(&hw, (ide_ioreg_t)IDE_BASE, macide_offsets,
+				0, 0, macide_ack_intr,
+//				quadra_ide_iops,
+				IRQ_NUBUS_F);
+		index = ide_register_hw(&hw, NULL);
+		break;
+	case MAC_IDE_PB:
+		ide_setup_ports(&hw, (ide_ioreg_t)IDE_BASE, macide_offsets,
+				0, 0, macide_ack_intr,
+//				macide_pb_iops,
+				IRQ_NUBUS_C);
+		index = ide_register_hw(&hw, NULL);
+		break;
+	case MAC_IDE_BABOON:
+		ide_setup_ports(&hw, (ide_ioreg_t)BABOON_BASE, macide_offsets,
+				0, 0, NULL,
+//				macide_baboon_iops,
+				IRQ_BABOON_1);
+		index = ide_register_hw(&hw, NULL);
+		if (index == -1) break;
+		if (macintosh_config->ident == MAC_MODEL_PB190) {
+
+			/* Fix breakage in ide-disk.c: drive capacity	*/
+			/* is not initialized for drives without a 	*/
+			/* hardware ID, and we can't get that without	*/
+			/* probing the drive which freezes a 190.	*/
+
+			ide_drive_t *drive = &ide_hwifs[index].drives[0];
+        		drive->capacity = drive->cyl*drive->head*drive->sect;
+
+#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
+			request_irq(IRQ_BABOON_2, macide_mediabay_interrupt,
+					IRQ_FLG_FAST, "mediabay",
+					macide_mediabay_interrupt);
+#endif
+		}
+		break;
+
+	default:
+	    return;
+	}
+
+        if (index != -1) {
+		if (macintosh_config->ide_type == MAC_IDE_QUADRA)
+			printk(KERN_INFO "ide%d: Macintosh Quadra IDE interface\n", index);
+		else if (macintosh_config->ide_type == MAC_IDE_PB)
+			printk(KERN_INFO "ide%d: Macintosh Powerbook IDE interface\n", index);
+		else if (macintosh_config->ide_type == MAC_IDE_BABOON)
+			printk(KERN_INFO "ide%d: Macintosh Powerbook Baboon IDE interface\n", index);
+		else
+			printk(KERN_INFO "ide%d: Unknown Macintosh IDE interface\n", index);
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/pdc4030.c linux-2.4.21/drivers/ide/legacy/pdc4030.c
--- linux-2.4.20/drivers/ide/legacy/pdc4030.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/legacy/pdc4030.c	2002-12-18 18:58:04.000000000 +0000
@@ -0,0 +1,858 @@
+/*  -*- linux-c -*-
+ *  linux/drivers/ide/pdc4030.c		Version 0.90  May 27, 1999
+ *
+ *  Copyright (C) 1995-2002  Linus Torvalds & authors (see below)
+ */
+
+/*
+ *  Principal Author/Maintainer:  Peter Denison <promise@pnd-pc.demon.co.uk>
+ *
+ *  This file provides support for the second port and cache of Promise
+ *  IDE interfaces, e.g. DC4030VL, DC4030VL-1 and DC4030VL-2.
+ *
+ *  Thanks are due to Mark Lord for advice and patiently answering stupid
+ *  questions, and all those mugs^H^H^H^Hbrave souls who've tested this,
+ *  especially Andre Hedrick.
+ *
+ *  Version 0.01	Initial version, #include'd in ide.c rather than
+ *                      compiled separately.
+ *                      Reads use Promise commands, writes as before. Drives
+ *                      on second channel are read-only.
+ *  Version 0.02        Writes working on second channel, reads on both
+ *                      channels. Writes fail under high load. Suspect
+ *			transfers of >127 sectors don't work.
+ *  Version 0.03        Brought into line with ide.c version 5.27.
+ *                      Other minor changes.
+ *  Version 0.04        Updated for ide.c version 5.30
+ *                      Changed initialization strategy
+ *  Version 0.05	Kernel integration.  -ml
+ *  Version 0.06	Ooops. Add hwgroup to direct call of ide_intr() -ml
+ *  Version 0.07	Added support for DC4030 variants
+ *			Secondary interface autodetection
+ *  Version 0.08	Renamed to pdc4030.c
+ *  Version 0.09	Obsolete - never released - did manual write request
+ *			splitting before max_sectors[major][minor] available.
+ *  Version 0.10	Updated for 2.1 series of kernels
+ *  Version 0.11	Updated for 2.3 series of kernels
+ *			Autodetection code added.
+ *
+ *  Version 0.90	Transition to BETA code. No lost/unexpected interrupts
+ */
+
+/*
+ * Once you've compiled it in, you'll have to also enable the interface
+ * setup routine from the kernel command line, as in 
+ *
+ *	'linux ide0=dc4030' or 'linux ide1=dc4030'
+ *
+ * It should now work as a second controller also ('ide1=dc4030') but only
+ * if you DON'T have BIOS V4.44, which has a bug. If you have this version
+ * and EPROM programming facilities, you need to fix 4 bytes:
+ * 	2496:	81	81
+ *	2497:	3E	3E
+ *	2498:	22	98	*
+ *	2499:	06	05	*
+ *	249A:	F0	F0
+ *	249B:	01	01
+ *	...
+ *	24A7:	81	81
+ *	24A8:	3E	3E
+ *	24A9:	22	98	*
+ *	24AA:	06	05	*
+ *	24AB:	70	70
+ *	24AC:	01	01
+ *
+ * As of January 1999, Promise Technology Inc. have finally supplied me with
+ * some technical information which has shed a glimmer of light on some of the
+ * problems I was having, especially with writes. 
+ *
+ * There are still potential problems with the robustness and efficiency of
+ * this driver because I still don't understand what the card is doing with
+ * interrupts, however, it has been stable for a while with no reports of ill
+ * effects.
+ */
+
+#define DEBUG_READ
+#define DEBUG_WRITE
+#define __PROMISE_4030
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "pdc4030.h"
+
+/*
+ * promise_selectproc() is invoked by ide.c
+ * in preparation for access to the specified drive.
+ */
+static void promise_selectproc (ide_drive_t *drive)
+{
+	unsigned int number;
+
+	number = (HWIF(drive)->channel << 1) + drive->select.b.unit;
+	HWIF(drive)->OUTB(number, IDE_FEATURE_REG);
+}
+
+/*
+ * pdc4030_cmd handles the set of vendor specific commands that are initiated
+ * by command F0. They all have the same success/failure notification -
+ * 'P' (=0x50) on success, 'p' (=0x70) on failure.
+ */
+int pdc4030_cmd(ide_drive_t *drive, u8 cmd)
+{
+	u32 timeout;
+	u8 status_val;
+
+	promise_selectproc(drive);	/* redundant? */
+	HWIF(drive)->OUTB(0xF3, IDE_SECTOR_REG);
+	HWIF(drive)->OUTB(cmd, IDE_SELECT_REG);
+	HWIF(drive)->OUTB(PROMISE_EXTENDED_COMMAND, IDE_COMMAND_REG);
+	timeout = HZ * 10;
+	timeout += jiffies;
+	do {
+		if(time_after(jiffies, timeout)) {
+			return 2; /* device timed out */
+		}
+		/* Delays at least 10ms to give interface a chance */
+		mdelay(10);
+		status_val = HWIF(drive)->INB(IDE_SECTOR_REG);
+	} while (status_val != 0x50 && status_val != 0x70);
+
+	if(status_val == 0x50)
+		return 0; /* device returned success */
+	else
+		return 1; /* device returned failure */
+}
+
+/*
+ * pdc4030_identify sends a vendor-specific IDENTIFY command to the drive
+ */
+int pdc4030_identify(ide_drive_t *drive)
+{
+	return pdc4030_cmd(drive, PROMISE_IDENTIFY);
+}
+
+int enable_promise_support;
+
+/*
+ * setup_pdc4030()
+ * Completes the setup of a Promise DC4030 controller card, once found.
+ */
+int __init setup_pdc4030(ide_hwif_t *hwif)
+{
+        ide_drive_t *drive;
+	ide_hwif_t *hwif2;
+	struct dc_ident ident;
+	int i;
+	ide_startstop_t startstop;
+	
+	if (!hwif) return 0;
+
+	drive = &hwif->drives[0];
+	hwif2 = &ide_hwifs[hwif->index+1];
+	if (hwif->chipset == ide_pdc4030) /* we've already been found ! */
+		return 1;
+
+	if (hwif->INB(IDE_NSECTOR_REG) == 0xFF ||
+	    hwif->INB(IDE_SECTOR_REG) == 0xFF) {
+		return 0;
+	}
+	if (IDE_CONTROL_REG)
+		hwif->OUTB(0x08, IDE_CONTROL_REG);
+	if (pdc4030_cmd(drive,PROMISE_GET_CONFIG)) {
+		return 0;
+	}
+	if (ide_wait_stat(&startstop, drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) {
+		printk(KERN_INFO
+			"%s: Failed Promise read config!\n",hwif->name);
+		return 0;
+	}
+	hwif->ata_input_data(drive, &ident, SECTOR_WORDS);
+	if (ident.id[1] != 'P' || ident.id[0] != 'T') {
+		return 0;
+	}
+	printk(KERN_INFO "%s: Promise caching controller, ",hwif->name);
+	switch(ident.type) {
+		case 0x43:	printk("DC4030VL-2, "); break;
+		case 0x41:	printk("DC4030VL-1, "); break;
+		case 0x40:	printk("DC4030VL, "); break;
+		default:
+			printk("unknown - type 0x%02x - please report!\n"
+			       ,ident.type);
+			printk("Please e-mail the following data to "
+			       "promise@pnd-pc.demon.co.uk along with\n"
+			       "a description of your card and drives:\n");
+			for (i=0; i < 0x90; i++) {
+				printk("%02x ", ((unsigned char *)&ident)[i]);
+				if ((i & 0x0f) == 0x0f) printk("\n");
+			}
+			return 0;
+	}
+	printk("%dKB cache, ",(int)ident.cache_mem);
+	switch(ident.irq) {
+            case 0x00: hwif->irq = 14; break;
+            case 0x01: hwif->irq = 12; break;
+            default:   hwif->irq = 15; break;
+	}
+	printk("on IRQ %d\n",hwif->irq);
+
+	/*
+	 * Once found and identified, we set up the next hwif in the array
+	 * (hwif2 = ide_hwifs[hwif->index+1]) with the same io ports, irq
+	 * and other settings as the main hwif. This gives us two "mated"
+	 * hwifs pointing to the Promise card.
+	 *
+	 * We also have to shift the default values for the remaining
+	 * interfaces "up by one" to make room for the second interface on the
+	 * same set of values.
+	 */
+
+	hwif->chipset	= hwif2->chipset = ide_pdc4030;
+	hwif->mate	= hwif2;
+	hwif2->mate	= hwif;
+	hwif2->channel	= 1;
+	hwif->rqsize	= hwif2->rqsize = 127;
+	hwif->addressing = hwif2->addressing = 1;
+	hwif->selectproc = hwif2->selectproc = &promise_selectproc;
+	hwif->serialized = hwif2->serialized = 1;
+	/* DC4030 hosted drives need their own identify... */
+	hwif->identify = hwif2->identify = &pdc4030_identify;
+
+	/* Shift the remaining interfaces up by one */
+	for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) {
+		ide_hwif_t *h = &ide_hwifs[i];
+
+#ifdef DEBUG
+		printk(KERN_DEBUG "pdc4030: Shifting i/f %d values to i/f %d\n",i-1,i);
+#endif /* DEBUG */
+		ide_init_hwif_ports(&h->hw, (h-1)->io_ports[IDE_DATA_OFFSET], 0, NULL);
+		memcpy(h->io_ports, h->hw.io_ports, sizeof(h->io_ports));
+		h->noprobe = (h-1)->noprobe;
+	}
+	ide_init_hwif_ports(&hwif2->hw, hwif->io_ports[IDE_DATA_OFFSET], 0, NULL);
+	memcpy(hwif2->io_ports, hwif->hw.io_ports, sizeof(hwif2->io_ports));
+	hwif2->irq = hwif->irq;
+	hwif2->hw.irq = hwif->hw.irq = hwif->irq;
+	for (i=0; i<2 ; i++) {
+		hwif->drives[i].io_32bit = 3;
+		hwif2->drives[i].io_32bit = 3;
+		hwif->drives[i].keep_settings = 1;
+		hwif2->drives[i].keep_settings = 1;
+		if (!ident.current_tm[i].cyl)
+			hwif->drives[i].noprobe = 1;
+		if (!ident.current_tm[i+2].cyl)
+			hwif2->drives[i].noprobe = 1;
+	}
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(&ide_hwifs[hwif->index]);
+	probe_hwif_init(&ide_hwifs[hwif2->index]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+        return 1;
+}
+
+/*
+ * detect_pdc4030()
+ * Tests for the presence of a DC4030 Promise card on this interface
+ * Returns: 1 if found, 0 if not found
+ */
+int __init detect_pdc4030(ide_hwif_t *hwif)
+{
+	ide_drive_t *drive = &hwif->drives[0];
+
+	if (IDE_DATA_REG == 0) { /* Skip test for non-existent interface */
+		return 0;
+	}
+	hwif->OUTB(0xF3, IDE_SECTOR_REG);
+	hwif->OUTB(0x14, IDE_SELECT_REG);
+	hwif->OUTB(PROMISE_EXTENDED_COMMAND, IDE_COMMAND_REG);
+	
+	ide_delay_50ms();
+
+	if (hwif->INB(IDE_ERROR_REG) == 'P' &&
+	    hwif->INB(IDE_NSECTOR_REG) == 'T' &&
+	    hwif->INB(IDE_SECTOR_REG) == 'I') {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+
+#ifndef MODULE
+void __init ide_probe_for_pdc4030(void)
+#else
+int ide_probe_for_pdc4030(void)
+#endif
+{
+	unsigned int	index;
+	ide_hwif_t	*hwif;
+
+#ifndef MODULE
+	if (enable_promise_support == 0)
+		return;
+#endif
+
+	for (index = 0; index < MAX_HWIFS; index++) {
+		hwif = &ide_hwifs[index];
+		if (hwif->chipset == ide_unknown && detect_pdc4030(hwif)) {
+#ifndef MODULE
+			setup_pdc4030(hwif);
+#else
+			return setup_pdc4030(hwif);
+#endif
+		}
+	}
+#ifdef MODULE
+	return 0;
+#endif
+}
+
+void __init release_pdc4030(ide_hwif_t *hwif, ide_hwif_t *mate)
+{
+	hwif->chipset = ide_unknown;
+	hwif->selectproc = NULL;
+	hwif->serialized = 0;
+	hwif->drives[0].io_32bit = 0;
+	hwif->drives[1].io_32bit = 0;
+	hwif->drives[0].keep_settings = 0;
+	hwif->drives[1].keep_settings = 0;
+	hwif->drives[0].noprobe = 0;
+	hwif->drives[1].noprobe = 0;
+
+	if (mate != NULL) {
+		mate->chipset = ide_unknown;
+		mate->selectproc = NULL;
+		mate->serialized = 0;
+		mate->drives[0].io_32bit = 0;
+		mate->drives[1].io_32bit = 0;
+		mate->drives[0].keep_settings = 0;
+		mate->drives[1].keep_settings = 0;
+		mate->drives[0].noprobe = 0;
+		mate->drives[1].noprobe = 0;
+	}
+}
+
+#ifndef MODULE
+/*
+ * init_pdc4030:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_pdc4030(void)
+{
+	enable_promise_support = 1;
+}
+
+#else
+
+MODULE_AUTHOR("Peter Denison");
+MODULE_DESCRIPTION("Support of Promise 4030 VLB series IDE chipsets");
+MODULE_LICENSE("GPL");
+
+int __init pdc4030_mod_init(void)
+{
+	if (enable_promise_support == 0)
+		enable_promise_support = 1;
+
+	if (!ide_probe_for_pdc4030())
+		return -ENODEV;
+        return 0;
+}
+module_init(pdc4030_mod_init);
+
+void __init pdc4030_mod_exit(void)
+{
+	unsigned int    index;
+	ide_hwif_t      *hwif;
+
+	if (enable_promise_support == 0)
+		return;
+ 
+	for (index = 0; index < MAX_HWIFS; index++) {
+		hwif = &ide_hwifs[index];
+		if (hwif->chipset == ide_pdc4030) {
+			ide_hwif_t *mate = &ide_hwifs[hwif->index+1];
+			if (mate->chipset == ide_pdc4030)
+				release_pdc4030(hwif, mate);
+			else
+				release_pdc4030(hwif, NULL);
+                }
+        }
+	enable_promise_support = 0;
+}
+module_exit(pdc4030_mod_exit);
+#endif
+
+/*
+ * promise_read_intr() is the handler for disk read/multread interrupts
+ */
+static ide_startstop_t promise_read_intr (ide_drive_t *drive)
+{
+	int total_remaining;
+	unsigned int sectors_left, sectors_avail, nsect;
+	struct request *rq;
+	ata_status_t status;
+#ifdef CONFIG_IDE_TASKFILE_IO
+	unsigned long flags;
+	char *to;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+	if (!OK_STAT(status.all, DATA_READY, BAD_R_STAT))
+		return DRIVER(drive)->error(drive,
+			"promise_read_intr", status.all);
+
+read_again:
+	do {
+		sectors_left = HWIF(drive)->INB(IDE_NSECTOR_REG);
+		HWIF(drive)->INB(IDE_SECTOR_REG);
+	} while (HWIF(drive)->INB(IDE_NSECTOR_REG) != sectors_left);
+	rq = HWGROUP(drive)->rq;
+	sectors_avail = rq->nr_sectors - sectors_left;
+	if (!sectors_avail)
+		goto read_again;
+
+read_next:
+	rq = HWGROUP(drive)->rq;
+	nsect = rq->current_nr_sectors;
+	if (nsect > sectors_avail)
+		nsect = sectors_avail;
+	sectors_avail -= nsect;
+#ifdef CONFIG_IDE_TASKFILE_IO
+	to = ide_map_buffer(rq, &flags);
+	HWIF(drive)->ata_input_data(drive, to, nsect * SECTOR_WORDS);
+#else /* !CONFIG_IDE_TASKFILE_IO */
+	HWIF(drive)->ata_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+#ifdef DEBUG_READ
+	printk(KERN_DEBUG "%s:  promise_read: sectors(%ld-%ld), "
+	       "buf=0x%08lx, rem=%ld\n", drive->name, rq->sector,
+	       rq->sector+nsect-1,
+#ifdef CONFIG_IDE_TASKFILE_IO
+		(unsigned long) to,
+#else /* !CONFIG_IDE_TASKFILE_IO */
+		(unsigned long) rq->buffer,
+#endif /* CONFIG_IDE_TASKFILE_IO */
+	       rq->nr_sectors-nsect);
+#endif /* DEBUG_READ */
+
+#ifdef CONFIG_IDE_TASKFILE_IO
+	ide_unmap_buffer(to, &flags);
+#else /* !CONFIG_IDE_TASKFILE_IO */
+	rq->buffer += nsect<<9;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+	rq->sector += nsect;
+	rq->errors = 0;
+	rq->nr_sectors -= nsect;
+	total_remaining = rq->nr_sectors;
+	if ((rq->current_nr_sectors -= nsect) <= 0) {
+		DRIVER(drive)->end_request(drive, 1);
+	}
+/*
+ * Now the data has been read in, do the following:
+ * 
+ * if there are still sectors left in the request, 
+ *   if we know there are still sectors available from the interface,
+ *     go back and read the next bit of the request.
+ *   else if DRQ is asserted, there are more sectors available, so
+ *     go back and find out how many, then read them in.
+ *   else if BUSY is asserted, we are going to get an interrupt, so
+ *     set the handler for the interrupt and just return
+ */
+	if (total_remaining > 0) {
+		if (sectors_avail)
+			goto read_next;
+		status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+		if (status.b.drq)
+			goto read_again;
+		if (status.b.bsy) {
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
+			ide_set_handler(drive,
+					&promise_read_intr,
+					WAIT_CMD,
+					NULL);
+#ifdef DEBUG_READ
+			printk(KERN_DEBUG "%s: promise_read: waiting for"
+			       "interrupt\n", drive->name);
+#endif /* DEBUG_READ */
+			return ide_started;
+		}
+		printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left "
+		       "!DRQ !BUSY\n", drive->name);
+		return DRIVER(drive)->error(drive,
+				"promise read intr", status.all);
+	}
+	return ide_stopped;
+}
+
+/*
+ * promise_complete_pollfunc()
+ * This is the polling function for waiting (nicely!) until drive stops
+ * being busy. It is invoked at the end of a write, after the previous poll
+ * has finished.
+ *
+ * Once not busy, the end request is called.
+ */
+static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	struct request *rq = hwgroup->rq;
+	int i;
+
+	if ((HWIF(drive)->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (hwgroup->handler != NULL)
+				BUG();
+			ide_set_handler(drive,
+					&promise_complete_pollfunc,
+					HZ/100,
+					NULL);
+			return ide_started; /* continue polling... */
+		}
+		hwgroup->poll_timeout = 0;
+		printk(KERN_ERR "%s: completion timeout - still busy!\n",
+		       drive->name);
+		return DRIVER(drive)->error(drive, "busy timeout",
+				HWIF(drive)->INB(IDE_STATUS_REG));
+	}
+
+	hwgroup->poll_timeout = 0;
+#ifdef DEBUG_WRITE
+	printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name);
+#endif /* DEBUG_WRITE */
+	for (i = rq->nr_sectors; i > 0; ) {
+		i -= rq->current_nr_sectors;
+		DRIVER(drive)->end_request(drive, 1);
+	}
+	return ide_stopped;
+}
+
+/*
+ * promise_multwrite() transfers a block of up to mcount sectors of data
+ * to a drive as part of a disk multiple-sector write operation.
+ *
+ * Returns 0 on success.
+ *
+ * Note that we may be called from two contexts - the do_rw_disk context
+ * and IRQ context. The IRQ can happen any time after we've output the
+ * full "mcount" number of sectors, so we must make sure we update the
+ * state _before_ we output the final part of the data!
+ */
+int promise_multwrite (ide_drive_t *drive, unsigned int mcount)
+{
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	struct request *rq	= &hwgroup->wrq;
+
+	do {
+		char *buffer;
+		int nsect = rq->current_nr_sectors;
+#ifdef CONFIG_IDE_TASKFILE_IO
+		unsigned long flags;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+		if (nsect > mcount)
+			nsect = mcount;
+		mcount -= nsect;
+#ifdef CONFIG_IDE_TASKFILE_IO
+		buffer = ide_map_buffer(rq, &flags);
+		rq->sector += nsect;
+#else /* !CONFIG_IDE_TASKFILE_IO */
+		buffer = rq->buffer;
+
+		rq->sector += nsect;
+		rq->buffer += nsect << 9;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+		rq->nr_sectors -= nsect;
+		rq->current_nr_sectors -= nsect;
+
+		/* Do we move to the next bh after this? */
+		if (!rq->current_nr_sectors) {
+			struct buffer_head *bh = rq->bh->b_reqnext;
+
+			/* end early early we ran out of requests */
+			if (!bh) {
+				mcount = 0;
+			} else {
+				rq->bh			= bh;
+				rq->current_nr_sectors	= bh->b_size >> 9;
+				rq->hard_cur_sectors = rq->current_nr_sectors;
+				rq->buffer		= bh->b_data;
+			}
+		}
+
+		/*
+		 * Ok, we're all setup for the interrupt
+		 * re-entering us on the last transfer.
+		 */
+		taskfile_output_data(drive, buffer, nsect<<7);
+#ifdef CONFIG_IDE_TASKFILE_IO
+		ide_unmap_buffer(buffer, &flags);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+	} while (mcount);
+
+	return 0;
+}
+
+/*
+ * promise_write_pollfunc() is the handler for disk write completion polling.
+ */
+static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+
+	if (HWIF(drive)->INB(IDE_NSECTOR_REG) != 0) {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (hwgroup->handler != NULL)
+				BUG();
+			ide_set_handler(drive,
+					&promise_write_pollfunc,
+					HZ/100,
+					NULL);
+			return ide_started; /* continue polling... */
+		}
+		hwgroup->poll_timeout = 0;
+		printk(KERN_ERR "%s: write timed-out!\n",drive->name);
+		return DRIVER(drive)->error(drive, "write timeout",
+				HWIF(drive)->INB(IDE_STATUS_REG));
+	}
+
+	/*
+	 * Now write out last 4 sectors and poll for not BUSY
+	 */
+	promise_multwrite(drive, 4);
+	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+	if (hwgroup->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
+#ifdef DEBUG_WRITE
+	printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
+		drive->name, HWIF(drive)->INB(IDE_STATUS_REG));
+#endif /* DEBUG_WRITE */
+	return ide_started;
+}
+
+/*
+ * promise_write() transfers a block of one or more sectors of data to a
+ * drive as part of a disk write operation. All but 4 sectors are transferred
+ * in the first attempt, then the interface is polled (nicely!) for completion
+ * before the final 4 sectors are transferred. There is no interrupt generated
+ * on writes (at least on the DC4030VL-2), we just have to poll for NOT BUSY.
+ */
+static ide_startstop_t promise_write (ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	struct request *rq = &hwgroup->wrq;
+
+#ifdef DEBUG_WRITE
+	printk(KERN_DEBUG "%s: promise_write: sectors(%ld-%ld), "
+	       "buffer=%p\n", drive->name, rq->sector,
+	       rq->sector + rq->nr_sectors - 1, rq->buffer);
+#endif /* DEBUG_WRITE */
+
+	/*
+	 * If there are more than 4 sectors to transfer, do n-4 then go into
+	 * the polling strategy as defined above.
+	 */
+	if (rq->nr_sectors > 4) {
+		if (promise_multwrite(drive, rq->nr_sectors - 4))
+			return ide_stopped;
+		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		if (hwgroup->handler != NULL)	/* paranoia check */
+			BUG();
+		ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
+		return ide_started;
+	} else {
+	/*
+	 * There are 4 or fewer sectors to transfer, do them all in one go
+	 * and wait for NOT BUSY.
+	 */
+		if (promise_multwrite(drive, rq->nr_sectors))
+			return ide_stopped;
+		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		if (hwgroup->handler != NULL)
+			BUG();
+		ide_set_handler(drive,
+				&promise_complete_pollfunc,
+				HZ/100,
+				NULL);
+
+#ifdef DEBUG_WRITE
+		printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
+			"status = %02x\n", drive->name,
+			HWIF(drive)->INB(IDE_STATUS_REG));
+#endif /* DEBUG_WRITE */
+		return ide_started;
+	}
+}
+
+/*
+ * do_pdc4030_io() is called from promise_rw_disk, having had the block number
+ * already set up. It issues a READ or WRITE command to the Promise
+ * controller, assuming LBA has been used to set up the block number.
+ */
+#ifndef CONFIG_IDE_TASKFILE_IO
+ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq)
+{
+#else /* CONFIG_IDE_TASKFILE_IO */
+ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task)
+{
+	struct request *rq	= HWGROUP(drive)->rq;
+	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+	ide_startstop_t startstop;
+	unsigned long timeout;
+	u8 stat = 0;
+
+#ifdef CONFIG_IDE_TASKFILE_IO
+	if (IDE_CONTROL_REG)
+		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
+	SELECT_MASK(drive, 0);
+	HWIF(drive)->OUTB(taskfile->feature, IDE_FEATURE_REG);
+	HWIF(drive)->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to number of sectors to transfer */
+	HWIF(drive)->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
+	/* refers to sector offset or start sector */
+	HWIF(drive)->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
+	HWIF(drive)->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
+	HWIF(drive)->OUTB(taskfile->device_head, IDE_SELECT_REG);
+	HWIF(drive)->OUTB(taskfile->command, IDE_COMMAND_REG);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+	switch(rq->cmd) {
+	case READ:
+#ifndef CONFIG_IDE_TASKFILE_IO
+		HWIF(drive)->OUTB(PROMISE_READ, IDE_COMMAND_REG);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+/*
+ * The card's behaviour is odd at this point. If the data is
+ * available, DRQ will be true, and no interrupt will be
+ * generated by the card. If this is the case, we need to call the 
+ * "interrupt" handler (promise_read_intr) directly. Otherwise, if
+ * an interrupt is going to occur, bit0 of the SELECT register will
+ * be high, so we can set the handler the just return and be interrupted.
+ * If neither of these is the case, we wait for up to 50ms (badly I'm
+ * afraid!) until one of them is.
+ */
+		timeout = jiffies + HZ/20; /* 50ms wait */
+		do {
+			stat = HWIF(drive)->INB(IDE_STATUS_REG);
+			if (stat & DRQ_STAT) {
+				udelay(1);
+				return promise_read_intr(drive);
+			}
+			if (HWIF(drive)->INB(IDE_SELECT_REG) & 0x01) {
+#ifdef DEBUG_READ
+				printk(KERN_DEBUG "%s: read: waiting for "
+						"interrupt\n", drive->name);
+#endif /* DEBUG_READ */
+				ide_set_handler(drive,
+						&promise_read_intr,
+						WAIT_CMD,
+						NULL);
+				return ide_started;
+			}
+			udelay(1);
+		} while (time_before(jiffies, timeout));
+
+		printk(KERN_ERR "%s: reading: No DRQ and not "
+				"waiting - Odd!\n", drive->name);
+		return ide_stopped;
+	case WRITE:
+#ifndef CONFIG_IDE_TASKFILE_IO
+		HWIF(drive)->OUTB(PROMISE_WRITE, IDE_COMMAND_REG);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+		if (ide_wait_stat(&startstop, drive, DATA_READY,
+				drive->bad_wstat, WAIT_DRQ)) {
+			printk(KERN_ERR "%s: no DRQ after issuing "
+				"PROMISE_WRITE\n", drive->name);
+			return startstop;
+	    	}
+		if (!drive->unmask)
+			local_irq_disable();
+		HWGROUP(drive)->wrq = *rq; /* scratchpad */
+		return promise_write(drive);
+	default:
+		printk("KERN_WARNING %s: bad command: %d\n",
+			drive->name, rq->cmd);
+		DRIVER(drive)->end_request(drive, 0);
+		return ide_stopped;
+	}
+}
+
+ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	/* The four drives on the two logical (one physical) interfaces
+	   are distinguished by writing the drive number (0-3) to the
+	   Feature register.
+	   FIXME: Is promise_selectproc now redundant??
+	*/
+	int drive_number = (HWIF(drive)->channel << 1) + drive->select.b.unit;
+#ifndef CONFIG_IDE_TASKFILE_IO
+	ide_hwif_t *hwif = HWIF(drive);
+
+	BUG_ON(rq->nr_sectors > 127);
+
+	if (IDE_CONTROL_REG)
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+
+#ifdef DEBUG
+	printk("%s: %sing: LBAsect=%ld, sectors=%ld, "
+		"buffer=0x%08lx\n", drive->name,
+		(rq->cmd==READ)?"read":"writ", block,
+		rq->nr_sectors, (unsigned long) rq->buffer);
+#endif
+	hwif->OUTB(drive_number, IDE_FEATURE_REG);
+	hwif->OUTB(rq->nr_sectors, IDE_NSECTOR_REG);
+	hwif->OUTB(block,IDE_SECTOR_REG);
+	hwif->OUTB(block>>=8,IDE_LCYL_REG);
+	hwif->OUTB(block>>=8,IDE_HCYL_REG);
+	hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
+
+	return do_pdc4030_io(drive, rq);
+
+#else /* CONFIG_IDE_TASKFILE_IO */
+
+	struct hd_drive_task_hdr	taskfile;
+	ide_task_t			args;
+
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+
+	taskfile.feature	= drive_number;
+	taskfile.sector_count	= rq->nr_sectors;
+	taskfile.sector_number	= block;
+	taskfile.low_cylinder	= (block>>=8);
+	taskfile.high_cylinder	= (block>>=8);
+	taskfile.device_head	= ((block>>8)&0x0f)|drive->select.all;
+	taskfile.command	= (rq->cmd==READ)?PROMISE_READ:PROMISE_WRITE;
+
+	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+	memset(args.hobRegister, 0, sizeof(struct hd_drive_hob_hdr));
+	/* We can't call ide_cmd_type_parser here, since it won't understand
+	   our command, but that doesn't matter, since we don't use the
+	   generic interrupt handlers either. Setup the bits of args that we
+	   do need.
+	*/
+	args.handler		= NULL;
+	args.rq			= (struct request *) rq;
+	rq->special		= (ide_task_t *)&args;
+
+	return do_pdc4030_io(drive, &args);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/pdc4030.h linux-2.4.21/drivers/ide/legacy/pdc4030.h
--- linux-2.4.20/drivers/ide/legacy/pdc4030.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/legacy/pdc4030.h	2002-12-18 18:58:11.000000000 +0000
@@ -0,0 +1,70 @@
+/*
+ *  linux/drivers/ide/pdc4030.h
+ *
+ *  Copyright (C) 1995-1998  Linus Torvalds & authors
+ */
+
+/*
+ * Principal author: Peter Denison <peterd@pnd-pc.demon.co.uk>
+ */
+
+#ifndef IDE_PROMISE_H
+#define IDE_PROMISE_H
+
+#include <linux/config.h>
+
+#ifndef CONFIG_BLK_DEV_PDC4030
+# ifdef _IDE_DISK
+
+# define IS_PDC4030_DRIVE (0)	/* auto-NULLs out pdc4030 code */
+
+ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
+
+ide_startstop_t promise_rw_disk(ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+        return ide_stopped;
+}
+# endif /* _IDE_DISK */
+#else /* CONFIG_BLK_DEV_PDC4030 */
+# ifdef _IDE_DISK
+#  define IS_PDC4030_DRIVE (HWIF(drive)->chipset == ide_pdc4030)
+
+ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
+
+# endif /* _IDE_DISK */
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+
+#ifdef __PROMISE_4030
+#define	PROMISE_EXTENDED_COMMAND	0xF0
+#define	PROMISE_READ			0xF2
+#define	PROMISE_WRITE			0xF3
+/* Extended commands - main command code = 0xf0 */
+#define	PROMISE_GET_CONFIG		0x10
+#define	PROMISE_IDENTIFY		0x20
+
+struct translation_mode {
+	u16	cyl;
+	u8	head;
+	u8	sect;
+};
+
+struct dc_ident {
+	u8	type;
+	u8	unknown1;
+	u8	hw_revision;
+	u8	firmware_major;
+	u8	firmware_minor;
+	u8	bios_address;
+	u8	irq;
+	u8	unknown2;
+	u16	cache_mem;
+	u16	unknown3;
+	u8	id[2];
+	u16	info;
+	struct translation_mode current_tm[4];
+	u8	pad[SECTOR_WORDS*4 - 32];
+};
+
+#endif /* __PROMISE_4030 */
+
+#endif /* IDE_PROMISE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/q40ide.c linux-2.4.21/drivers/ide/legacy/q40ide.c
--- linux-2.4.20/drivers/ide/legacy/q40ide.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/legacy/q40ide.c	2002-12-18 18:58:09.000000000 +0000
@@ -0,0 +1,93 @@
+/*
+ *  linux/drivers/ide/q40ide.c -- Q40 I/O port IDE Driver
+ *
+ *     (c) Richard Zidlicky
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ *
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/ide.h>
+
+    /*
+     *  Bases of the IDE interfaces
+     */
+
+#define Q40IDE_NUM_HWIFS	2
+
+#define PCIDE_BASE1	0x1f0
+#define PCIDE_BASE2	0x170
+#define PCIDE_BASE3	0x1e8
+#define PCIDE_BASE4	0x168
+#define PCIDE_BASE5	0x1e0
+#define PCIDE_BASE6	0x160
+
+static const q40ide_ioreg_t pcide_bases[Q40IDE_NUM_HWIFS] = {
+    PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4  , PCIDE_BASE5,
+    PCIDE_BASE6 */
+};
+
+
+    /*
+     *  Offsets from one of the above bases
+     */
+
+
+/* HD_DATA was redefined in asm-m68k/ide.h */
+#undef HD_DATA
+#define HD_DATA  0x1f0
+
+
+#define PCIDE_REG(x)	((q40ide_ioreg_t)(HD_##x-PCIDE_BASE1))
+
+static const int pcide_offsets[IDE_NR_PORTS] = {
+    PCIDE_REG(DATA), PCIDE_REG(ERROR), PCIDE_REG(NSECTOR), PCIDE_REG(SECTOR),
+    PCIDE_REG(LCYL), PCIDE_REG(HCYL), PCIDE_REG(CURRENT), PCIDE_REG(STATUS),
+    PCIDE_REG(CMD)
+};
+
+static int q40ide_default_irq(q40ide_ioreg_t base)
+{
+           switch (base) { 
+	            case 0x1f0: return 14;
+		    case 0x170: return 15;
+		    case 0x1e8: return 11;
+		    default:
+			return 0;
+	   }
+}
+
+
+
+    /*
+     *  Probe for Q40 IDE interfaces
+     */
+
+void q40ide_init(void)
+{
+    int i;
+
+    if (!MACH_IS_Q40)
+      return ;
+
+    for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
+	hw_regs_t hw;
+
+	ide_setup_ports(&hw,(ide_ioreg_t) pcide_bases[i], (int *)pcide_offsets, 
+			pcide_bases[i]+0x206, 
+			0, NULL,
+//			pcide_iops,
+			q40ide_default_irq(pcide_bases[i]));
+	ide_register_hw(&hw, NULL);
+    }
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/qd65xx.c linux-2.4.21/drivers/ide/legacy/qd65xx.c
--- linux-2.4.20/drivers/ide/legacy/qd65xx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/legacy/qd65xx.c	2002-12-18 18:58:05.000000000 +0000
@@ -0,0 +1,523 @@
+/*
+ *  linux/drivers/ide/qd65xx.c		Version 0.07	Sep 30, 2001
+ *
+ *  Copyright (C) 1996-2001  Linus Torvalds & author (see below)
+ */
+
+/*
+ *  Version 0.03	Cleaned auto-tune, added probe
+ *  Version 0.04	Added second channel tuning
+ *  Version 0.05	Enhanced tuning ; added qd6500 support
+ *  Version 0.06	Added dos driver's list
+ *  Version 0.07	Second channel bug fix 
+ *
+ * QDI QD6500/QD6580 EIDE controller fast support
+ *
+ * Please set local bus speed using kernel parameter idebus
+ * 	for example, "idebus=33" stands for 33Mhz VLbus
+ * To activate controller support, use "ide0=qd65xx"
+ * To enable tuning, use "ide0=autotune"
+ * To enable second channel tuning (qd6580 only), use "ide1=autotune"
+ */
+
+/*
+ * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
+ * Samuel Thibault <samuel.thibault@fnac.net>
+ */
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_QD65XX_MODULE
+# define _IDE_C
+# include "ide_modes.h"
+# undef _IDE_C
+#else
+# include "ide_modes.h"
+#endif /* CONFIG_BLK_DEV_QD65XX_MODULE */
+
+#include "qd65xx.h"
+
+/*
+ * I/O ports are 0x30-0x31 (and 0x32-0x33 for qd6580)
+ *            or 0xb0-0xb1 (and 0xb2-0xb3 for qd6580)
+ *	-- qd6500 is a single IDE interface
+ *	-- qd6580 is a dual IDE interface
+ *
+ * More research on qd6580 being done by willmore@cig.mot.com (David)
+ * More Information given by Petr Soucek (petr@ryston.cz)
+ * http://www.ryston.cz/petr/vlb
+ */
+
+/*
+ * base: Timer1
+ *
+ *
+ * base+0x01: Config (R/O)
+ *
+ * bit 0: ide baseport: 1 = 0x1f0 ; 0 = 0x170 (only useful for qd6500)
+ * bit 1: qd65xx baseport: 1 = 0xb0 ; 0 = 0x30
+ * bit 2: ID3: bus speed: 1 = <=33MHz ; 0 = >33MHz
+ * bit 3: qd6500: 1 = disabled, 0 = enabled
+ *        qd6580: 1
+ * upper nibble:
+ *        qd6500: 1100
+ *        qd6580: either 1010 or 0101
+ *
+ *
+ * base+0x02: Timer2 (qd6580 only)
+ *
+ *
+ * base+0x03: Control (qd6580 only)
+ *
+ * bits 0-3 must always be set 1
+ * bit 4 must be set 1, but is set 0 by dos driver while measuring vlb clock
+ * bit 0 : 1 = Only primary port enabled : channel 0 for hda, channel 1 for hdb
+ *         0 = Primary and Secondary ports enabled : channel 0 for hda & hdb
+ *                                                   channel 1 for hdc & hdd
+ * bit 1 : 1 = only disks on primary port
+ *         0 = disks & ATAPI devices on primary port
+ * bit 2-4 : always 0
+ * bit 5 : status, but of what ?
+ * bit 6 : always set 1 by dos driver
+ * bit 7 : set 1 for non-ATAPI devices on primary port
+ *	(maybe read-ahead and post-write buffer ?)
+ */
+
+static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */
+
+static void qd_write_reg (u8 content, u8 reg)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	outb(content,reg);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+u8 __init qd_read_reg (u8 reg)
+{
+	unsigned long flags;
+	u8 read;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	read = inb(reg);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return read;
+}
+
+/*
+ * qd_select:
+ *
+ * This routine is invoked from ide.c to prepare for access to a given drive.
+ */
+
+static void qd_select (ide_drive_t *drive)
+{
+	u8 index = ((	(QD_TIMREG(drive)) & 0x80 ) >> 7) |
+			(QD_TIMREG(drive) & 0x02);
+
+	if (timings[index] != QD_TIMING(drive))
+		qd_write_reg(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
+}
+
+/*
+ * qd6500_compute_timing
+ *
+ * computes the timing value where
+ *	lower nibble represents active time,   in count of VLB clocks
+ *	upper nibble represents recovery time, in count of VLB clocks
+ */
+
+static u8 qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time)
+{
+	u8 active_cycle,recovery_cycle;
+
+	if (system_bus_clock()<=33) {
+		active_cycle =   9  - IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 2, 9);
+		recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 0, 15);
+	} else {
+		active_cycle =   8  - IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 1, 8);
+		recovery_cycle = 18 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 3, 18);
+	}
+
+	return((recovery_cycle<<4) | 0x08 | active_cycle);
+}
+
+/*
+ * qd6580_compute_timing
+ *
+ * idem for qd6580
+ */
+
+static u8 qd6580_compute_timing (int active_time, int recovery_time)
+{
+	u8 active_cycle   = 17 - IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 2, 17);
+	u8 recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 2, 15);
+
+	return((recovery_cycle<<4) | active_cycle);
+}
+
+/*
+ * qd_find_disk_type
+ *
+ * tries to find timing from dos driver's table
+ */
+
+static int qd_find_disk_type (ide_drive_t *drive,
+		int *active_time, int *recovery_time)
+{
+	struct qd65xx_timing_s *p;
+	char model[40];
+
+	if (!*drive->id->model) return 0;
+
+	strncpy(model,drive->id->model,40);
+	ide_fixstring(model,40,1); /* byte-swap */
+
+	for (p = qd65xx_timing ; p->offset != -1 ; p++) {
+		if (!strncmp(p->model, model+p->offset, 4)) {
+			printk(KERN_DEBUG "%s: listed !\n", drive->name);
+			*active_time = p->active;
+			*recovery_time = p->recovery;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * qd_timing_ok:
+ *
+ * check whether timings don't conflict
+ */
+
+static int qd_timing_ok (ide_drive_t drives[])
+{
+	return (IDE_IMPLY(drives[0].present && drives[1].present,
+			IDE_IMPLY(QD_TIMREG(drives) == QD_TIMREG(drives+1),
+			          QD_TIMING(drives) == QD_TIMING(drives+1))));
+	/* if same timing register, must be same timing */
+}
+
+/*
+ * qd_set_timing:
+ *
+ * records the timing, and enables selectproc as needed
+ */
+
+static void qd_set_timing (ide_drive_t *drive, u8 timing)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	drive->drive_data &= 0xff00;
+	drive->drive_data |= timing;
+	if (qd_timing_ok(hwif->drives)) {
+		qd_select(drive); /* selects once */
+		hwif->selectproc = NULL;
+	} else
+		hwif->selectproc = &qd_select;
+
+	printk(KERN_DEBUG "%s: %#x\n", drive->name, timing);
+}
+
+/*
+ * qd6500_tune_drive
+ */
+
+static void qd6500_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	int active_time   = 175;
+	int recovery_time = 415; /* worst case values from the dos driver */
+
+	if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)
+		&& drive->id->tPIO && (drive->id->field_valid & 0x02)
+		&& drive->id->eide_pio >= 240) {
+
+		printk(KERN_INFO "%s: PIO mode%d\n", drive->name,
+				drive->id->tPIO);
+		active_time = 110;
+		recovery_time = drive->id->eide_pio - 120;
+	}
+
+	qd_set_timing(drive, qd6500_compute_timing(HWIF(drive), active_time, recovery_time));
+}
+
+/*
+ * qd6580_tune_drive
+ */
+
+static void qd6580_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_pio_data_t d;
+	int base = HWIF(drive)->select_data;
+	int active_time   = 175;
+	int recovery_time = 415; /* worst case values from the dos driver */
+
+	if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) {
+		pio = ide_get_best_pio_mode(drive, pio, 255, &d);
+		pio = IDE_MIN(pio,4);
+
+		switch (pio) {
+			case 0: break;
+			case 3:
+				if (d.cycle_time >= 110) {
+					active_time = 86;
+					recovery_time = d.cycle_time - 102;
+				} else
+					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
+				break;
+			case 4:
+				if (d.cycle_time >= 69) {
+					active_time = 70;
+					recovery_time = d.cycle_time - 61;
+				} else
+					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
+				break;
+			default:
+				if (d.cycle_time >= 180) {
+					active_time = 110;
+					recovery_time = d.cycle_time - 120;
+				} else {
+					active_time = ide_pio_timings[pio].active_time;
+					recovery_time = d.cycle_time
+							-active_time;
+				}
+		}
+		printk(KERN_INFO "%s: PIO mode%d\n", drive->name,pio);
+	}
+
+	if (!HWIF(drive)->channel && drive->media != ide_disk) {
+		qd_write_reg(0x5f, QD_CONTROL_PORT);
+		printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO "
+			"and post-write buffer on %s.\n",
+			drive->name, HWIF(drive)->name);
+	}
+
+	qd_set_timing(drive, qd6580_compute_timing(active_time, recovery_time));
+}
+
+/*
+ * qd_testreg
+ *
+ * tests if the given port is a register
+ */
+
+static int __init qd_testreg(int port)
+{
+	u8 savereg;
+	u8 readreg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	savereg = inb_p(port);
+	outb_p(QD_TESTVAL, port);	/* safe value */
+	readreg = inb_p(port);
+	outb(savereg, port);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	if (savereg == QD_TESTVAL) {
+		printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n");
+		printk(KERN_ERR "Please contact maintainers to tell about your hardware\n");
+		printk(KERN_ERR "Assuming qd65xx is not present.\n");
+		return 1;
+	}
+
+	return (readreg != QD_TESTVAL);
+}
+
+/*
+ * qd_setup:
+ *
+ * called to setup an ata channel : adjusts attributes & links for tuning
+ */
+
+void __init qd_setup (int unit, int base, int config, unsigned int data0, unsigned int data1, void (*tuneproc) (ide_drive_t *, u8 pio))
+{
+	ide_hwif_t *hwif = &ide_hwifs[unit];
+
+	hwif->chipset = ide_qd65xx;
+	hwif->channel = unit;
+	hwif->select_data = base;
+	hwif->config_data = config;
+	hwif->drives[0].drive_data = data0;
+	hwif->drives[1].drive_data = data1;
+	hwif->drives[0].io_32bit =
+	hwif->drives[1].io_32bit = 1;
+	hwif->tuneproc = tuneproc;
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(hwif);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+}
+
+/*
+ * qd_unsetup:
+ *
+ * called to unsetup an ata channel : back to default values, unlinks tuning
+ */
+void __init qd_unsetup (int unit)
+{
+	ide_hwif_t *hwif = &ide_hwifs[unit];
+	u8 config = hwif->config_data;
+	int base = hwif->select_data;
+	void *tuneproc = (void *) hwif->tuneproc;
+
+	if (!(hwif->chipset == ide_qd65xx)) return;
+
+	printk(KERN_NOTICE "%s: back to defaults\n", hwif->name);
+
+	hwif->selectproc = NULL;
+	hwif->tuneproc = NULL;
+
+	if (tuneproc == (void *) qd6500_tune_drive) {
+		// will do it for both
+		qd_write_reg(QD6500_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+	} else if (tuneproc == (void *) qd6580_tune_drive) {
+		if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) {
+			qd_write_reg(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+			qd_write_reg(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1]));
+		} else {
+			qd_write_reg(unit?QD6580_DEF_DATA2:QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+		}
+	} else {
+		printk(KERN_WARNING "Unknown qd65xx tuning fonction !\n");
+		printk(KERN_WARNING "keeping settings !\n");
+	}
+}
+
+/*
+ * qd_probe:
+ *
+ * looks at the specified baseport, and if qd found, registers & initialises it
+ * return 1 if another qd may be probed
+ */
+
+int __init qd_probe (int base)
+{
+	u8 config;
+	u8 unit;
+
+	config = qd_read_reg(QD_CONFIG_PORT);
+
+	if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) )
+		return 1;
+
+	unit = ! (config & QD_CONFIG_IDE_BASEPORT);
+
+	if ((config & 0xf0) == QD_CONFIG_QD6500) {
+
+		if (qd_testreg(base)) return 1;		/* bad register */
+
+		/* qd6500 found */
+
+		printk(KERN_NOTICE "%s: qd6500 at %#x\n",
+			ide_hwifs[unit].name, base);
+		
+		printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
+			config, QD_ID3);
+		
+		if (config & QD_CONFIG_DISABLED) {
+			printk(KERN_WARNING "qd6500 is disabled !\n");
+			return 1;
+		}
+
+		qd_setup(unit, base, config, QD6500_DEF_DATA,
+			QD6500_DEF_DATA, &qd6500_tune_drive);
+		return 1;
+	}
+
+	if (((config & 0xf0) == QD_CONFIG_QD6580_A) ||
+	    ((config & 0xf0) == QD_CONFIG_QD6580_B)) {
+
+		u8 control;
+
+		if (qd_testreg(base) || qd_testreg(base+0x02)) return 1;
+			/* bad registers */
+
+		/* qd6580 found */
+
+		control = qd_read_reg(QD_CONTROL_PORT);
+
+		printk(KERN_NOTICE "qd6580 at %#x\n", base);
+		printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n",
+			config, control, QD_ID3);
+
+		if (control & QD_CONTR_SEC_DISABLED) {
+			/* secondary disabled */
+			printk(KERN_INFO "%s: qd6580: single IDE board\n",
+					ide_hwifs[unit].name);
+			qd_setup(unit, base, config | (control << 8),
+				QD6580_DEF_DATA, QD6580_DEF_DATA2,
+				&qd6580_tune_drive);
+			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
+
+			return 1;
+		} else {
+			/* secondary enabled */
+			printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n",
+					ide_hwifs[0].name,ide_hwifs[1].name);
+
+			qd_setup(0, base, config | (control << 8),
+				QD6580_DEF_DATA, QD6580_DEF_DATA,
+				&qd6580_tune_drive);
+			qd_setup(1, base, config | (control << 8),
+				QD6580_DEF_DATA2, QD6580_DEF_DATA2,
+				&qd6580_tune_drive);
+			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
+
+			return 0; /* no other qd65xx possible */
+		}
+	}
+	/* no qd65xx found */
+	return 1;
+}
+
+#ifndef MODULE
+/*
+ * init_qd65xx:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_qd65xx (void)
+{
+	if (qd_probe(0x30)) qd_probe(0xb0);
+}
+
+#else
+
+MODULE_AUTHOR("Samuel Thibault");
+MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
+MODULE_LICENSE("GPL");
+
+int __init qd65xx_mod_init(void)
+{
+	if (qd_probe(0x30)) qd_probe(0xb0);
+	if (ide_hwifs[0].chipset != ide_qd65xx &&
+	    ide_hwifs[1].chipset != ide_qd65xx)
+		return -ENODEV;
+	return 0;
+}
+module_init(qd65xx_mod_init);
+
+void __init qd65xx_mod_exit(void)
+{
+	qd_unsetup(0);
+	qd_unsetup(1);
+}
+module_exit(qd65xx_mod_exit);
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/qd65xx.h linux-2.4.21/drivers/ide/legacy/qd65xx.h
--- linux-2.4.20/drivers/ide/legacy/qd65xx.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/legacy/qd65xx.h	2002-12-18 18:58:05.000000000 +0000
@@ -0,0 +1,140 @@
+/*
+ * linux/drivers/ide/qd65xx.h
+ *
+ * Copyright (c) 2000	Linus Torvalds & authors
+ */
+
+/*
+ * Authors:	Petr Soucek <petr@ryston.cz>
+ * 		Samuel Thibault <samuel.thibault@fnac.net>
+ */
+
+/* truncates a in [b,c] */
+#define IDE_IN(a,b,c)   ( ((a)<(b)) ? (b) : ( (a)>(c) ? (c) : (a)) )
+
+#define IDE_IMPLY(a,b)	((!(a)) || (b))
+
+#define QD_TIM1_PORT		(base)
+#define QD_CONFIG_PORT		(base+0x01)
+#define QD_TIM2_PORT		(base+0x02)
+#define QD_CONTROL_PORT		(base+0x03)
+
+#define QD_CONFIG_IDE_BASEPORT	0x01
+#define QD_CONFIG_BASEPORT	0x02
+#define QD_CONFIG_ID3		0x04
+#define QD_CONFIG_DISABLED	0x08
+#define QD_CONFIG_QD6500	0xc0
+#define QD_CONFIG_QD6580_A	0xa0
+#define QD_CONFIG_QD6580_B	0x50
+
+#define QD_CONTR_SEC_DISABLED	0x01
+
+#define QD_ID3			((config & QD_CONFIG_ID3)!=0)
+
+#define QD_CONFIG(hwif)		((hwif)->config_data & 0x00ff)
+#define QD_CONTROL(hwif)	(((hwif)->config_data & 0xff00) >> 8)
+
+#define QD_TIMING(drive)	(byte)(((drive)->drive_data) & 0x00ff)
+#define QD_TIMREG(drive)	(byte)((((drive)->drive_data) & 0xff00) >> 8)
+
+#define QD6500_DEF_DATA		((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08))
+#define QD6580_DEF_DATA		((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
+#define QD6580_DEF_DATA2	((QD_TIM2_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
+#define QD_DEF_CONTR		(0x40 | ((control & 0x02) ? 0x9f : 0x1f))
+
+#define QD_TESTVAL		0x19	/* safe value */
+
+/* Drive specific timing taken from DOS driver v3.7 */
+
+struct qd65xx_timing_s {
+	char	offset;   /* ofset from the beginning of Model Number" */
+	char	model[4];    /* 4 chars from Model number, no conversion */
+	short	active;   /* active time */
+	short	recovery; /* recovery time */
+} qd65xx_timing [] = {
+	{ 30, "2040", 110, 225 },  /* Conner CP30204			*/
+	{ 30, "2045", 135, 225 },  /* Conner CP30254			*/
+	{ 30, "1040", 155, 325 },  /* Conner CP30104			*/
+	{ 30, "1047", 135, 265 },  /* Conner CP30174			*/
+	{ 30, "5344", 135, 225 },  /* Conner CP3544			*/
+	{ 30, "01 4", 175, 405 },  /* Conner CP-3104			*/
+	{ 27, "C030", 175, 375 },  /* Conner CP3000			*/
+	{  8, "PL42", 110, 295 },  /* Quantum LP240			*/
+	{  8, "PL21", 110, 315 },  /* Quantum LP120			*/
+	{  8, "PL25", 175, 385 },  /* Quantum LP52			*/
+	{  4, "PA24", 110, 285 },  /* WD Piranha SP4200			*/
+	{  6, "2200", 110, 260 },  /* WD Caviar AC2200			*/
+	{  6, "3204", 110, 235 },  /* WD Caviar AC2340			*/
+	{  6, "1202", 110, 265 },  /* WD Caviar AC2120			*/
+	{  0, "DS3-", 135, 315 },  /* Teac SD340			*/
+	{  8, "KM32", 175, 355 },  /* Toshiba MK234			*/
+	{  2, "53A1", 175, 355 },  /* Seagate ST351A			*/
+	{  2, "4108", 175, 295 },  /* Seagate ST1480A			*/
+	{  2, "1344", 175, 335 },  /* Seagate ST3144A			*/
+	{  6, "7 12", 110, 225 },  /* Maxtor 7213A			*/
+	{ 30, "02F4", 145, 295 },  /* Conner 3204F			*/
+	{  2, "1302", 175, 335 },  /* Seagate ST3120A			*/
+	{  2, "2334", 145, 265 },  /* Seagate ST3243A			*/
+	{  2, "2338", 145, 275 },  /* Seagate ST3283A			*/
+	{  2, "3309", 145, 275 },  /* Seagate ST3390A			*/
+	{  2, "5305", 145, 275 },  /* Seagate ST3550A			*/
+	{  2, "4100", 175, 295 },  /* Seagate ST1400A			*/
+	{  2, "4110", 175, 295 },  /* Seagate ST1401A			*/
+	{  2, "6300", 135, 265 },  /* Seagate ST3600A			*/
+	{  2, "5300", 135, 265 },  /* Seagate ST3500A			*/
+	{  6, "7 31", 135, 225 },  /* Maxtor 7131 AT			*/
+	{  6, "7 43", 115, 265 },  /* Maxtor 7345 AT			*/
+	{  6, "7 42", 110, 255 },  /* Maxtor 7245 AT			*/
+	{  6, "3 04", 135, 265 },  /* Maxtor 340 AT			*/
+	{  6, "61 0", 135, 285 },  /* WD AC160				*/
+	{  6, "1107", 135, 235 },  /* WD AC1170				*/
+	{  6, "2101", 110, 220 },  /* WD AC1210				*/
+	{  6, "4202", 135, 245 },  /* WD AC2420				*/
+	{  6, "41 0", 175, 355 },  /* WD Caviar 140			*/
+	{  6, "82 0", 175, 355 },  /* WD Caviar 280			*/
+	{  8, "PL01", 175, 375 },  /* Quantum LP105			*/
+	{  8, "PL25", 110, 295 },  /* Quantum LP525			*/
+	{ 10, "4S 2", 175, 385 },  /* Quantum ELS42			*/
+	{ 10, "8S 5", 175, 385 },  /* Quantum ELS85			*/
+	{ 10, "1S72", 175, 385 },  /* Quantum ELS127			*/
+	{ 10, "1S07", 175, 385 },  /* Quantum ELS170			*/
+	{  8, "ZE42", 135, 295 },  /* Quantum EZ240			*/
+	{  8, "ZE21", 175, 385 },  /* Quantum EZ127			*/
+	{  8, "ZE58", 175, 385 },  /* Quantum EZ85			*/
+	{  8, "ZE24", 175, 385 },  /* Quantum EZ42			*/
+	{ 27, "C036", 155, 325 },  /* Conner CP30064			*/
+	{ 27, "C038", 155, 325 },  /* Conner CP30084			*/
+	{  6, "2205", 110, 255 },  /* WDC AC2250			*/
+	{  2, " CHA", 140, 415 },  /* WDC AH series; WDC AH260, WDC	*/
+	{  2, " CLA", 140, 415 },  /* WDC AL series: WDC AL2120, 2170,	*/
+	{  4, "UC41", 140, 415 },  /* WDC CU140				*/
+	{  6, "1207", 130, 275 },  /* WDC AC2170			*/
+	{  6, "2107", 130, 275 },  /* WDC AC1270			*/
+	{  6, "5204", 130, 275 },  /* WDC AC2540			*/
+	{ 30, "3004", 110, 235 },  /* Conner CP30340			*/
+	{ 30, "0345", 135, 255 },  /* Conner CP30544			*/
+	{ 12, "12A3", 175, 320 },  /* MAXTOR LXT-213A			*/
+	{ 12, "43A0", 145, 240 },  /* MAXTOR LXT-340A			*/
+	{  6, "7 21", 180, 290 },  /* Maxtor 7120 AT			*/
+	{  6, "7 71", 135, 240 },  /* Maxtor 7170 AT			*/
+	{ 12, "45\0000", 110, 205 },   /* MAXTOR MXT-540		*/
+	{  8, "PL11", 180, 290 },  /* QUANTUM LP110A			*/
+	{  8, "OG21", 150, 275 },  /* QUANTUM GO120			*/
+	{ 12, "42A5", 175, 320 },  /* MAXTOR LXT-245A			*/
+	{  2, "2309", 175, 295 },  /* ST3290A				*/
+	{  2, "3358", 180, 310 },  /* ST3385A				*/
+	{  2, "6355", 180, 310 },  /* ST3655A				*/
+	{  2, "1900", 175, 270 },  /* ST9100A				*/
+	{  2, "1954", 175, 270 },  /* ST9145A				*/
+	{  2, "1909", 175, 270 },  /* ST9190AG				*/
+	{  2, "2953", 175, 270 },  /* ST9235A				*/
+	{  2, "1359", 175, 270 },  /* ST3195A				*/
+	{ 24, "3R11", 175, 290 },  /* ALPS ELECTRIC Co.,LTD, DR311C	*/
+	{  0, "2M26", 175, 215 },  /* M262XT-0Ah			*/
+	{  4, "2253", 175, 300 },  /* HP C2235A				*/
+	{  4, "-32A", 145, 245 },  /* H3133-A2				*/
+	{ 30, "0326", 150, 270 },  /* Samsung Electronics 120MB		*/
+	{ 30, "3044", 110, 195 },  /* Conner CFA340A			*/
+	{ 30, "43A0", 110, 195 },  /* Conner CFA340A			*/
+	{ -1, "    ", 175, 415 }   /* unknown disk name			*/
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/umc8672.c linux-2.4.21/drivers/ide/legacy/umc8672.c
--- linux-2.4.20/drivers/ide/legacy/umc8672.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/legacy/umc8672.c	2002-12-18 18:58:06.000000000 +0000
@@ -0,0 +1,237 @@
+/*
+ *  linux/drivers/ide/umc8672.c		Version 0.05	Jul 31, 1996
+ *
+ *  Copyright (C) 1995-1996  Linus Torvalds & author (see below)
+ */
+
+/*
+ *  Principal Author/Maintainer:  PODIEN@hml2.atlas.de (Wolfram Podien)
+ *
+ *  This file provides support for the advanced features
+ *  of the UMC 8672 IDE interface.
+ *
+ *  Version 0.01	Initial version, hacked out of ide.c,
+ *			and #include'd rather than compiled separately.
+ *			This will get cleaned up in a subsequent release.
+ *
+ *  Version 0.02	now configs/compiles separate from ide.c  -ml
+ *  Version 0.03	enhanced auto-tune, fix display bug
+ *  Version 0.05	replace sti() with restore_flags()  -ml
+ *			add detection of possible race condition  -ml
+ */
+
+/*
+ * VLB Controller Support from 
+ * Wolfram Podien
+ * Rohoefe 3
+ * D28832 Achim
+ * Germany
+ *
+ * To enable UMC8672 support there must a lilo line like
+ * append="ide0=umc8672"...
+ * To set the speed according to the abilities of the hardware there must be a
+ * line like
+ * #define UMC_DRIVE0 11
+ * in the beginning of the driver, which sets the speed of drive 0 to 11 (there
+ * are some lines present). 0 - 11 are allowed speed values. These values are
+ * the results from the DOS speed test program supplied from UMC. 11 is the 
+ * highest speed (about PIO mode 3)
+ */
+#define REALLY_SLOW_IO		/* some systems can safely undef this */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_UMC8672_MODULE
+# define _IDE_C
+# include "ide_modes.h"
+# undef _IDE_C
+#else
+# include "ide_modes.h"
+#endif /* CONFIG_BLK_DEV_UMC8672_MODULE */
+
+/*
+ * Default speeds.  These can be changed with "auto-tune" and/or hdparm.
+ */
+#define UMC_DRIVE0      1              /* DOS measured drive speeds */
+#define UMC_DRIVE1      1              /* 0 to 11 allowed */
+#define UMC_DRIVE2      1              /* 11 = Fastest Speed */
+#define UMC_DRIVE3      1              /* In case of crash reduce speed */
+
+static u8 current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3};
+static const u8 pio_to_umc [5] = {0,3,7,10,11};	/* rough guesses */
+
+/*       0    1    2    3    4    5    6    7    8    9    10   11      */
+static const u8 speedtab [3][12] = {
+	{0xf, 0xb, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
+	{0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
+	{0xff,0xcb,0xc0,0x58,0x36,0x33,0x23,0x22,0x21,0x11,0x10,0x0}};
+
+static void out_umc (char port,char wert)
+{
+	outb_p(port,0x108);
+	outb_p(wert,0x109);
+}
+
+static inline u8 in_umc (char port)
+{
+	outb_p(port,0x108);
+	return inb_p(0x109);
+}
+
+static void umc_set_speeds (u8 speeds[])
+{
+	int i, tmp;
+
+	outb_p(0x5A,0x108); /* enable umc */
+
+	out_umc (0xd7,(speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4)));
+	out_umc (0xd6,(speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4)));
+	tmp = 0;
+	for (i = 3; i >= 0; i--) {
+		tmp = (tmp << 2) | speedtab[1][speeds[i]];
+	}
+	out_umc (0xdc,tmp);
+	for (i = 0;i < 4; i++) {
+		out_umc (0xd0+i,speedtab[2][speeds[i]]);
+		out_umc (0xd8+i,speedtab[2][speeds[i]]);
+	}
+	outb_p(0xa5,0x108); /* disable umc */
+
+	printk ("umc8672: drive speeds [0 to 11]: %d %d %d %d\n",
+		speeds[0], speeds[1], speeds[2], speeds[3]);
+}
+
+static void tune_umc (ide_drive_t *drive, u8 pio)
+{
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
+		drive->name, pio, pio_to_umc[pio]);
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (hwgroup && hwgroup->handler != NULL) {
+		printk(KERN_ERR "umc8672: other interface is busy: exiting tune_umc()\n");
+	} else {
+		current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
+		umc_set_speeds (current_speeds);
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+int __init probe_umc8672 (void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (check_region(0x108, 2)) {
+		local_irq_restore(flags);
+		printk(KERN_ERR "umc8672: ports 0x108-0x109 already in use.\n");
+		return 1;
+	}
+	outb_p(0x5A,0x108); /* enable umc */
+	if (in_umc (0xd5) != 0xa0) {
+		local_irq_restore(flags);
+		printk(KERN_ERR "umc8672: not found\n");
+		return 1;  
+	}
+	outb_p(0xa5,0x108); /* disable umc */
+
+	umc_set_speeds (current_speeds);
+	local_irq_restore(flags);
+
+	request_region(0x108, 2, "umc8672");
+	ide_hwifs[0].chipset = ide_umc8672;
+	ide_hwifs[1].chipset = ide_umc8672;
+	ide_hwifs[0].tuneproc = &tune_umc;
+	ide_hwifs[1].tuneproc = &tune_umc;
+	ide_hwifs[0].mate = &ide_hwifs[1];
+	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
+
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(&ide_hwifs[0]);
+	probe_hwif_init(&ide_hwifs[1]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+	return 0;
+}
+
+void __init umc8672_release (void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (ide_hwifs[0].chipset != ide_umc8672 &&
+	    ide_hwifs[1].chipset != ide_umc8672) {
+		local_irq_restore(flags);
+		return;
+	}
+
+	ide_hwifs[0].chipset = ide_unknown;
+	ide_hwifs[1].chipset = ide_unknown;	
+	ide_hwifs[0].tuneproc = NULL;
+	ide_hwifs[1].tuneproc = NULL;
+	ide_hwifs[0].mate = NULL;
+	ide_hwifs[1].mate = NULL;
+	ide_hwifs[0].channel = 0;
+	ide_hwifs[1].channel = 0;
+
+	outb_p(0xa5,0x108); /* disable umc */
+
+	release_region(0x108, 2);
+	local_irq_restore(flags);
+}
+
+#ifndef MODULE
+/*
+ * init_umc8672:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_umc8672 (void)
+{
+	if (probe_umc8672())
+		printk(KERN_ERR "init_umc8672: umc8672 controller not found.\n");
+}
+
+#else
+
+MODULE_AUTHOR("Wolfram Podien");
+MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset");
+MODULE_LICENSE("GPL");
+
+int __init umc8672_mod_init(void)
+{
+	if (probe_umc8672())
+		return -ENODEV;
+	if (ide_hwifs[0].chipset != ide_umc8672 &&
+	    ide_hwifs[1].chipset != ide_umc8672) {
+		umc8672_release();
+		return -ENODEV;
+	}
+	return 0;
+}
+module_init(umc8672_mod_init);
+
+void __init umc8672_mod_exit(void)
+{
+        umc8672_release();
+}
+module_exit(umc8672_mod_exit);
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/macide.c linux-2.4.21/drivers/ide/macide.c
--- linux-2.4.20/drivers/ide/macide.c	2001-01-04 23:25:55.000000000 +0000
+++ linux-2.4.21/drivers/ide/macide.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,147 +0,0 @@
-/*
- *  linux/drivers/ide/macide.c -- Macintosh IDE Driver
- *
- *     Copyright (C) 1998 by Michael Schmitz
- *
- *  This driver was written based on information obtained from the MacOS IDE
- *  driver binary by Mikael Forselius
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-
-#include <asm/machw.h>
-#include <asm/macintosh.h>
-#include <asm/macints.h>
-#include <asm/mac_baboon.h>
-
-#define IDE_BASE 0x50F1A000	/* Base address of IDE controller */
-
-/*
- * Generic IDE registers as offsets from the base
- * These match MkLinux so they should be correct.
- */
-
-#define IDE_DATA	0x00
-#define IDE_ERROR	0x04	/* see err-bits */
-#define IDE_NSECTOR	0x08	/* nr of sectors to read/write */
-#define IDE_SECTOR	0x0c	/* starting sector */
-#define IDE_LCYL	0x10	/* starting cylinder */
-#define IDE_HCYL	0x14	/* high byte of starting cyl */
-#define IDE_SELECT	0x18	/* 101dhhhh , d=drive, hhhh=head */
-#define IDE_STATUS	0x1c	/* see status-bits */
-#define IDE_CONTROL	0x38	/* control/altstatus */
-
-/*
- * Mac-specific registers
- */
-
-/*
- * this register is odd; it doesn't seem to do much and it's
- * not word-aligned like virtually every other hardware register
- * on the Mac...
- */
-
-#define IDE_IFR		0x101	/* (0x101) IDE interrupt flags on Quadra:
-				 *
-				 * Bit 0+1: some interrupt flags
-				 * Bit 2+3: some interrupt enable
-				 * Bit 4:   ??
-				 * Bit 5:   IDE interrupt flag (any hwif)
-				 * Bit 6:   maybe IDE interrupt enable (any hwif) ??
-				 * Bit 7:   Any interrupt condition
-				 */
-
-volatile unsigned char *ide_ifr = (unsigned char *) (IDE_BASE + IDE_IFR);
-
-static int macide_offsets[IDE_NR_PORTS] = {
-    IDE_DATA, IDE_ERROR,  IDE_NSECTOR, IDE_SECTOR, IDE_LCYL,
-    IDE_HCYL, IDE_SELECT, IDE_STATUS,  IDE_CONTROL
-};
-
-int macide_ack_intr(ide_hwif_t* hwif)
-{
-	if (*ide_ifr & 0x20) {
-		*ide_ifr &= ~0x20;
-		return 1;
-	}
-	return 0;
-}
-
-#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
-static void macide_mediabay_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	int state = baboon->mb_status & 0x04;
-
-	printk("macide: media bay %s detected\n", state? "removal":"insertion");
-}
-#endif
-
-/*
- * Probe for a Macintosh IDE interface
- */
-
-void macide_init(void)
-{
-	hw_regs_t hw;
-	int index = -1;
-
-	switch (macintosh_config->ide_type) {
-	case MAC_IDE_QUADRA:
-		ide_setup_ports(&hw, (ide_ioreg_t)IDE_BASE, macide_offsets,
-				0, 0, macide_ack_intr, IRQ_NUBUS_F);
-		index = ide_register_hw(&hw, NULL);
-		break;
-	case MAC_IDE_PB:
-		ide_setup_ports(&hw, (ide_ioreg_t)IDE_BASE, macide_offsets,
-				0, 0, macide_ack_intr, IRQ_NUBUS_C);
-		index = ide_register_hw(&hw, NULL);
-		break;
-	case MAC_IDE_BABOON:
-		ide_setup_ports(&hw, (ide_ioreg_t)BABOON_BASE, macide_offsets,
-				0, 0, NULL, IRQ_BABOON_1);
-		index = ide_register_hw(&hw, NULL);
-		if (index == -1) break;
-		if (macintosh_config->ident == MAC_MODEL_PB190) {
-
-			/* Fix breakage in ide-disk.c: drive capacity	*/
-			/* is not initialized for drives without a 	*/
-			/* hardware ID, and we cna't get that without	*/
-			/* probing the drive which freezes a 190.	*/
-
-			ide_drive_t *drive = &ide_hwifs[index].drives[0];
-        		drive->capacity = drive->cyl*drive->head*drive->sect;
-
-#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
-			request_irq(IRQ_BABOON_2, macide_mediabay_interrupt,
-					IRQ_FLG_FAST, "mediabay",
-					macide_mediabay_interrupt);
-#endif
-		}
-		break;
-
-	default:
-	    return;
-	}
-
-        if (index != -1) {
-		if (macintosh_config->ide_type == MAC_IDE_QUADRA)
-			printk("ide%d: Macintosh Quadra IDE interface\n", index);
-		else if (macintosh_config->ide_type == MAC_IDE_PB)
-			printk("ide%d: Macintosh Powerbook IDE interface\n", index);
-		else if (macintosh_config->ide_type == MAC_IDE_BABOON)
-			printk("ide%d: Macintosh Powerbook Baboon IDE interface\n", index);
-		else
-			printk("ide%d: Unknown Macintosh IDE interface\n", index);
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ns87415.c linux-2.4.21/drivers/ide/ns87415.c
--- linux-2.4.20/drivers/ide/ns87415.c	2000-06-20 14:52:36.000000000 +0000
+++ linux-2.4.21/drivers/ide/ns87415.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,193 +0,0 @@
-/*
- * linux/drivers/ide/ns87415.c		Version 1.01  Mar. 18, 2000
- *
- * Copyright (C) 1997-1998	Mark Lord <mlord@pobox.com>
- * Copyright (C) 1998		Eddie C. Dost <ecd@skynet.be>
- * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
- *
- * Inspired by an earlier effort from David S. Miller <davem@redhat.com>
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
-
-/*
- * This routine either enables/disables (according to drive->present)
- * the IRQ associated with the port (HWIF(drive)),
- * and selects either PIO or DMA handshaking for the next I/O operation.
- */
-static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data;
-	struct pci_dev *dev = hwif->pci_dev;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	new = *old;
-
-	/* Adjust IRQ enable bit */
-	bit = 1 << (8 + hwif->channel);
-	new = drive->present ? (new & ~bit) : (new | bit);
-
-	/* Select PIO or DMA, DMA may only be selected for one drive/channel. */
-	bit   = 1 << (20 + drive->select.b.unit       + (hwif->channel << 1));
-	other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->channel << 1));
-	new = use_dma ? ((new & ~other) | bit) : (new & ~bit);
-
-	if (new != *old) {
-		unsigned char stat;
-
-		/*
-		 * Don't change DMA engine settings while Write Buffers
-		 * are busy.
-		 */
-		(void) pci_read_config_byte(dev, 0x43, &stat);
-		while (stat & 0x03) {
-			udelay(1);
-			(void) pci_read_config_byte(dev, 0x43, &stat);
-		}
-
-		*old = new;
-		(void) pci_write_config_dword(dev, 0x40, new);
-
-		/*
-		 * And let things settle...
-		 */
-		udelay(10);
-	}
-
-	__restore_flags(flags);	/* local CPU only */
-}
-
-static void ns87415_selectproc (ide_drive_t *drive)
-{
-	ns87415_prepare_drive (drive, drive->using_dma);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t	*hwif = HWIF(drive);
-	byte		dma_stat;
-
-	switch (func) {
-		case ide_dma_end: /* returns 1 on error, 0 otherwise */
-			drive->waiting_for_dma = 0;
-			dma_stat = inb(hwif->dma_base+2);
-			outb(inb(hwif->dma_base)&~1, hwif->dma_base);	/* stop DMA */
-			outb(inb(hwif->dma_base)|6, hwif->dma_base);	/* from ERRATA: clear the INTR & ERROR bits */
-			ide_destroy_dmatable(drive);			/* and free any DMA resources */
-			return (dma_stat & 7) != 4;		/* verify good DMA status */
-		case ide_dma_write:
-		case ide_dma_read:
-			ns87415_prepare_drive(drive, 1);	/* select DMA xfer */
-			if (!ide_dmaproc(func, drive))		/* use standard DMA stuff */
-				return 0;
-			ns87415_prepare_drive(drive, 0);	/* DMA failed: select PIO xfer */
-			return 1;
-		case ide_dma_check:
-			if (drive->media != ide_disk)
-				return ide_dmaproc(ide_dma_off_quietly, drive);
-			/* Fallthrough... */
-		default:
-			return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-	}
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-void __init ide_init_ns87415 (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev = hwif->pci_dev;
-	unsigned int ctrl, using_inta;
-	byte progif;
-#ifdef __sparc_v9__
-	int timeout;
-	byte stat;
-#endif
-
-	/* Set a good latency timer and cache line size value. */
-	(void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
-#ifdef __sparc_v9__
-	(void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10);
-#endif
-
-	/*
-	 * We cannot probe for IRQ: both ports share common IRQ on INTA.
-	 * Also, leave IRQ masked during drive probing, to prevent infinite
-	 * interrupts from a potentially floating INTA..
-	 *
-	 * IRQs get unmasked in selectproc when drive is first used.
-	 */
-	(void) pci_read_config_dword(dev, 0x40, &ctrl);
-	(void) pci_read_config_byte(dev, 0x09, &progif);
-	/* is irq in "native" mode? */
-	using_inta = progif & (1 << (hwif->channel << 1));
-	if (!using_inta)
-		using_inta = ctrl & (1 << (4 + hwif->channel));
-	if (hwif->mate) {
-		hwif->select_data = hwif->mate->select_data;
-	} else {
-		hwif->select_data = (unsigned long)
-					&ns87415_control[ns87415_count++];
-		ctrl |= (1 << 8) | (1 << 9);	/* mask both IRQs */
-		if (using_inta)
-			ctrl &= ~(1 << 6);	/* unmask INTA */
-		*((unsigned int *)hwif->select_data) = ctrl;
-		(void) pci_write_config_dword(dev, 0x40, ctrl);
-
-		/*
-		 * Set prefetch size to 512 bytes for both ports,
-		 * but don't turn on/off prefetching here.
-		 */
-		pci_write_config_byte(dev, 0x55, 0xee);
-
-#ifdef __sparc_v9__
-		/*
-		 * XXX: Reset the device, if we don't it will not respond
-		 *      to SELECT_DRIVE() properly during first probe_hwif().
-		 */
-		timeout = 10000;
-		outb(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
-		udelay(10);
-		outb(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
-		do {
-			udelay(50);
-			stat = inb(hwif->io_ports[IDE_STATUS_OFFSET]);
-                	if (stat == 0xff)
-                        	break;
-        	} while ((stat & BUSY_STAT) && --timeout);
-#endif
-	}
-
-	if (hwif->dma_base)
-		outb(0x60, hwif->dma_base + 2);
-
-	if (!using_inta)
-		hwif->irq = hwif->channel ? 15 : 14;	/* legacy mode */
-	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
-		hwif->irq = hwif->mate->irq;	/* share IRQ with mate */
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base)
-		hwif->dmaproc = &ns87415_dmaproc;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	hwif->selectproc = &ns87415_selectproc;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/opti621.c linux-2.4.21/drivers/ide/opti621.c
--- linux-2.4.20/drivers/ide/opti621.c	2001-05-01 23:05:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/opti621.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,316 +0,0 @@
-/*
- *  linux/drivers/ide/opti621.c		Version 0.6	Jan 02, 1999
- *
- *  Copyright (C) 1996-1998  Linus Torvalds & authors (see below)
- */
-
-/*
- * Authors:
- * Jaromir Koutek <miri@punknet.cz>,
- * Jan Harkes <jaharkes@cwi.nl>,
- * Mark Lord <mlord@pobox.com>
- * Some parts of code are from ali14xx.c and from rz1000.c.
- *
- * OPTi is trademark of OPTi, Octek is trademark of Octek.
- *
- * I used docs from OPTi databook, from ftp.opti.com, file 9123-0002.ps
- * and disassembled/traced setupvic.exe (DOS program).
- * It increases kernel code about 2 kB.
- * I don't have this card no more, but I hope I can get some in case
- * of needed development.
- * My card is Octek PIDE 1.01 (on card) or OPTiViC (program).
- * It has a place for a secondary connector in circuit, but nothing
- * is there. Also BIOS says no address for
- * secondary controller (see bellow in ide_init_opti621).
- * I've only tested this on my system, which only has one disk.
- * It's Western Digital WDAC2850, with PIO mode 3. The PCI bus
- * is at 20 MHz (I have DX2/80, I tried PCI at 40, but I got random
- * lockups). I tried the OCTEK double speed CD-ROM and
- * it does not work! But I can't boot DOS also, so it's probably
- * hardware fault. I have connected Conner 80MB, the Seagate 850MB (no
- * problems) and Seagate 1GB (as slave, WD as master). My experiences
- * with the third, 1GB drive: I got 3MB/s (hdparm), but sometimes
- * it slows to about 100kB/s! I don't know why and I have
- * not this drive now, so I can't try it again.
- * I write this driver because I lost the paper ("manual") with
- * settings of jumpers on the card and I have to boot Linux with
- * Loadlin except LILO, cause I have to run the setupvic.exe program
- * already or I get disk errors (my test: rpm -Vf
- * /usr/X11R6/bin/XF86_SVGA - or any big file).
- * Some numbers from hdparm -t /dev/hda:
- * Timing buffer-cache reads:   32 MB in  3.02 seconds =10.60 MB/sec
- * Timing buffered disk reads:  16 MB in  5.52 seconds = 2.90 MB/sec
- * I have 4 Megs/s before, but I don't know why (maybe changes
- * in hdparm test).
- * After release of 0.1, I got some successful reports, so it might work.
- *
- * The main problem with OPTi is that some timings for master
- * and slave must be the same. For example, if you have master
- * PIO 3 and slave PIO 0, driver have to set some timings of
- * master for PIO 0. Second problem is that opti621_tune_drive
- * got only one drive to set, but have to set both drives.
- * This is solved in compute_pios. If you don't set
- * the second drive, compute_pios use ide_get_best_pio_mode
- * for autoselect mode (you can change it to PIO 0, if you want).
- * If you then set the second drive to another PIO, the old value
- * (automatically selected) will be overrided by yours.
- * There is a 25/33MHz switch in configuration
- * register, but driver is written for use at any frequency which get
- * (use idebus=xx to select PCI bus speed).
- * Use ide0=autotune for automatical tune of the PIO modes.
- * If you get strange results, do not use this and set PIO manually
- * by hdparm.
- *
- * Version 0.1, Nov 8, 1996
- * by Jaromir Koutek, for 2.1.8. 
- * Initial version of driver.
- * 
- * Version 0.2
- * Number 0.2 skipped.
- *
- * Version 0.3, Nov 29, 1997
- * by Mark Lord (probably), for 2.1.68
- * Updates for use with new IDE block driver.
- *
- * Version 0.4, Dec 14, 1997
- * by Jan Harkes
- * Fixed some errors and cleaned the code.
- *
- * Version 0.5, Jan 2, 1998
- * by Jaromir Koutek
- * Updates for use with (again) new IDE block driver.
- * Update of documentation.
- * 
- * Version 0.6, Jan 2, 1999
- * by Jaromir Koutek
- * Reversed to version 0.3 of the driver, because
- * 0.5 doesn't work.
- */
-
-#undef REALLY_SLOW_IO	/* most systems can safely undef this */
-#define OPTI621_DEBUG		/* define for debug messages */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#define OPTI621_MAX_PIO 3
-/* In fact, I do not have any PIO 4 drive
- * (address: 25 ns, data: 70 ns, recovery: 35 ns),
- * but OPTi 82C621 is programmable and it can do (minimal values):
- * on 40MHz PCI bus (pulse 25 ns):
- *  address: 25 ns, data: 25 ns, recovery: 50 ns;
- * on 20MHz PCI bus (pulse 50 ns):
- *  address: 50 ns, data: 50 ns, recovery: 100 ns.
- */
-
-/* #define READ_PREFETCH 0 */
-/* Uncommnent for disable read prefetch.
- * There is some readprefetch capatibility in hdparm,
- * but when I type hdparm -P 1 /dev/hda, I got errors
- * and till reset drive is inaccessible.
- * This (hw) read prefetch is safe on my drive.
- */
-
-#ifndef READ_PREFETCH
-#define READ_PREFETCH 0x40 /* read prefetch is enabled */
-#endif /* else read prefetch is disabled */
-
-#define READ_REG 0	/* index of Read cycle timing register */
-#define WRITE_REG 1	/* index of Write cycle timing register */
-#define CNTRL_REG 3	/* index of Control register */
-#define STRAP_REG 5	/* index of Strap register */
-#define MISC_REG 6	/* index of Miscellaneous register */
-
-int reg_base;
-
-#define PIO_NOT_EXIST 254
-#define PIO_DONT_KNOW 255
-
-/* there are stored pio numbers from other calls of opti621_tune_drive */
-
-static void compute_pios(ide_drive_t *drive, byte pio)
-/* Store values into drive->drive_data
- *	second_contr - 0 for primary controller, 1 for secondary
- *	slave_drive - 0 -> pio is for master, 1 -> pio is for slave
- *	pio - PIO mode for selected drive (for other we don't know)
- */
-{
-	int d;
-	ide_hwif_t *hwif = HWIF(drive);
-
-	drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL);
-	for (d = 0; d < 2; ++d) {
-		drive = &hwif->drives[d];
-		if (drive->present) {
-			if (drive->drive_data == PIO_DONT_KNOW)
-				drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL);
-#ifdef OPTI621_DEBUG
-			printk("%s: Selected PIO mode %d\n", drive->name, drive->drive_data);
-#endif
-		} else {
-			drive->drive_data = PIO_NOT_EXIST;
-		}
-	}
-}
-
-int cmpt_clk(int time, int bus_speed)
-/* Returns (rounded up) time in clocks for time in ns,
- * with bus_speed in MHz.
- * Example: bus_speed = 40 MHz, time = 80 ns
- * 1000/40 = 25 ns (clk value),
- * 80/25 = 3.2, rounded up to 4 (I hope ;-)).
- * Use idebus=xx to select right frequency.
- */
-{
-	return ((time*bus_speed+999)/1000);
-}
-
-static void write_reg(byte value, int reg)
-/* Write value to register reg, base of register
- * is at reg_base (0x1f0 primary, 0x170 secondary,
- * if not changed by PCI configuration).
- * This is from setupvic.exe program.
- */
-{
-	inw(reg_base+1);
-	inw(reg_base+1);
-	outb(3, reg_base+2);
-	outb(value, reg_base+reg);
-	outb(0x83, reg_base+2);
-}
-
-static byte read_reg(int reg)
-/* Read value from register reg, base of register
- * is at reg_base (0x1f0 primary, 0x170 secondary,
- * if not changed by PCI configuration).
- * This is from setupvic.exe program.
- */
-{
-	byte ret;
-	inw(reg_base+1);
-	inw(reg_base+1);
-	outb(3, reg_base+2);
-	ret=inb(reg_base+reg);
-	outb(0x83, reg_base+2);
-	return ret;
-}
-
-typedef struct pio_clocks_s {
-	int	address_time;	/* Address setup (clocks) */
-	int	data_time;	/* Active/data pulse (clocks) */
-	int	recovery_time;	/* Recovery time (clocks) */
-} pio_clocks_t;
-
-static void compute_clocks(int pio, pio_clocks_t *clks)
-{
-        if (pio != PIO_NOT_EXIST) {
-        	int adr_setup, data_pls;
-		int bus_speed = system_bus_clock();
-
- 	       	adr_setup = ide_pio_timings[pio].setup_time;
-  	      	data_pls = ide_pio_timings[pio].active_time;
-	  	clks->address_time = cmpt_clk(adr_setup, bus_speed);
-	     	clks->data_time = cmpt_clk(data_pls, bus_speed);
-     		clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time
-     			- adr_setup-data_pls, bus_speed);
-     		if (clks->address_time<1) clks->address_time = 1;
-     		if (clks->address_time>4) clks->address_time = 4;
-     		if (clks->data_time<1) clks->data_time = 1;
-     		if (clks->data_time>16) clks->data_time = 16;
-     		if (clks->recovery_time<2) clks->recovery_time = 2;
-     		if (clks->recovery_time>17) clks->recovery_time = 17;
-	} else {
-		clks->address_time = 1;
-		clks->data_time = 1;
-		clks->recovery_time = 2;
-		/* minimal values */
-	}
- 
-}
-
-/* Main tune procedure, called from tuneproc. */
-static void opti621_tune_drive (ide_drive_t *drive, byte pio)
-{
-	/* primary and secondary drives share some registers,
-	 * so we have to program both drives
-	 */
-	unsigned long flags;
-	byte pio1, pio2;
-	pio_clocks_t first, second;
-	int ax, drdy;
-	byte cycle1, cycle2, misc;
-	ide_hwif_t *hwif = HWIF(drive);
-
-	/* sets drive->drive_data for both drives */
-	compute_pios(drive, pio);
- 	pio1 = hwif->drives[0].drive_data;
- 	pio2 = hwif->drives[1].drive_data;
-
-	compute_clocks(pio1, &first);
-	compute_clocks(pio2, &second);
-
-	/* ax = max(a1,a2) */
-	ax = (first.address_time < second.address_time) ? second.address_time : first.address_time;
-
-	drdy = 2; /* DRDY is default 2 (by OPTi Databook) */
-
-	cycle1 = ((first.data_time-1)<<4)  | (first.recovery_time-2);
-	cycle2 = ((second.data_time-1)<<4) | (second.recovery_time-2);
-	misc = READ_PREFETCH | ((ax-1)<<4) | ((drdy-2)<<1);
-
-#ifdef OPTI621_DEBUG
-	printk("%s: master: address: %d, data: %d, recovery: %d, drdy: %d [clk]\n",
-		hwif->name, ax, first.data_time, first.recovery_time, drdy);
-	printk("%s: slave:  address: %d, data: %d, recovery: %d, drdy: %d [clk]\n",
-		hwif->name, ax, second.data_time, second.recovery_time, drdy);
-#endif
-
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-
-     	reg_base = hwif->io_ports[IDE_DATA_OFFSET];
-	outb(0xc0, reg_base+CNTRL_REG);	/* allow Register-B */
-	outb(0xff, reg_base+5);		/* hmm, setupvic.exe does this ;-) */
-	inb(reg_base+CNTRL_REG); 	/* if reads 0xff, adapter not exist? */
-	read_reg(CNTRL_REG);		/* if reads 0xc0, no interface exist? */
-	read_reg(STRAP_REG);		/* read version, probably 0 */
-
-	/* program primary drive */
-	write_reg(0,      MISC_REG);	/* select Index-0 for Register-A */
-	write_reg(cycle1, READ_REG);	/* set read cycle timings */
-	write_reg(cycle1, WRITE_REG);	/* set write cycle timings */
-
-	/* program secondary drive */
-	write_reg(1,      MISC_REG);	/* select Index-1 for Register-B */
-	write_reg(cycle2, READ_REG);	/* set read cycle timings */
-	write_reg(cycle2, WRITE_REG);	/* set write cycle timings */
-
-	write_reg(0x85, CNTRL_REG);	/* use Register-A for drive 0 */
-					/* use Register-B for drive 1 */
-
- 	write_reg(misc, MISC_REG);	/* set address setup, DRDY timings,   */
- 					/*  and read prefetch for both drives */
-
-	restore_flags(flags);	/* all CPUs */
-}
-
-/*
- * ide_init_opti621() is called once for each hwif found at boot.
- */
-void __init ide_init_opti621 (ide_hwif_t *hwif)
-{
-	hwif->drives[0].drive_data = PIO_DONT_KNOW;
-	hwif->drives[1].drive_data = PIO_DONT_KNOW;
-	hwif->tuneproc = &opti621_tune_drive;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/Makefile linux-2.4.21/drivers/ide/pci/Makefile
--- linux-2.4.20/drivers/ide/pci/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/Makefile	2002-12-18 18:58:02.000000000 +0000
@@ -0,0 +1,42 @@
+
+O_TARGET := idedriver-pci.o
+
+obj-y		:=
+obj-m		:=
+
+obj-$(CONFIG_BLK_DEV_ADMA100)		+= adma100.o
+obj-$(CONFIG_BLK_DEV_AEC62XX)		+= aec62xx.o
+obj-$(CONFIG_BLK_DEV_ALI15X3)		+= alim15x3.o
+obj-$(CONFIG_BLK_DEV_AMD74XX)		+= amd74xx.o
+obj-$(CONFIG_BLK_DEV_CMD640)		+= cmd640.o
+obj-$(CONFIG_BLK_DEV_CMD64X)		+= cmd64x.o
+obj-$(CONFIG_BLK_DEV_CS5530)		+= cs5530.o
+obj-$(CONFIG_BLK_DEV_CY82C693)		+= cy82c693.o
+obj-$(CONFIG_BLK_DEV_HPT34X)		+= hpt34x.o
+obj-$(CONFIG_BLK_DEV_HPT366)		+= hpt366.o
+#obj-$(CONFIG_BLK_DEV_HPT37X)		+= hpt37x.o
+obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
+obj-$(CONFIG_BLK_DEV_IT8172)		+= it8172.o
+obj-$(CONFIG_BLK_DEV_NS87415)		+= ns87415.o
+obj-$(CONFIG_BLK_DEV_NFORCE)		+= nvidia.o
+obj-$(CONFIG_BLK_DEV_OPTI621)		+= opti621.o
+obj-$(CONFIG_BLK_DEV_PDC202XX_OLD)	+= pdc202xx_old.o
+obj-$(CONFIG_BLK_DEV_PDC202XX_NEW)	+= pdc202xx_new.o
+obj-$(CONFIG_BLK_DEV_PDC_ADMA)		+= pdcadma.o ide-adma.o
+obj-$(CONFIG_BLK_DEV_PIIX)		+= piix.o
+obj-$(CONFIG_BLK_DEV_RZ1000)		+= rz1000.o
+obj-$(CONFIG_BLK_DEV_SVWKS)		+= serverworks.o
+obj-$(CONFIG_BLK_DEV_SC1200)		+= sc1200.o
+obj-$(CONFIG_BLK_DEV_SIIMAGE)		+= siimage.o
+obj-$(CONFIG_BLK_DEV_SIS5513)		+= sis5513.o
+obj-$(CONFIG_BLK_DEV_SL82C105)		+= sl82c105.o
+obj-$(CONFIG_BLK_DEV_SLC90E66)		+= slc90e66.o
+obj-$(CONFIG_BLK_DEV_TRM290)		+= trm290.o
+obj-$(CONFIG_BLK_DEV_VIA82CXXX)		+= via82cxxx.o
+
+# Must appear at the end of the block
+obj-$(CONFIG_BLK_DEV_GENERIC)		+= generic.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/adma100.c linux-2.4.21/drivers/ide/pci/adma100.c
--- linux-2.4.20/drivers/ide/pci/adma100.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/adma100.c	2002-12-18 18:58:04.000000000 +0000
@@ -0,0 +1,30 @@
+/*
+ *  linux/drivers/ide/adma100.c -- basic support for Pacific Digital ADMA-100 boards
+ *
+ *     Created 09 Apr 2002 by Mark Lord
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+void __init ide_init_adma100 (ide_hwif_t *hwif)
+{
+	unsigned long  phy_admctl = pci_resource_start(hwif->pci_dev, 4) + 0x80 + (hwif->channel * 0x20);
+	void *v_admctl;
+
+	hwif->autodma = 0;		// not compatible with normal IDE DMA transfers
+	hwif->dma_base = 0;		// disable DMA completely
+	hwif->io_ports[IDE_CONTROL_OFFSET] += 4;	// chip needs offset of 6 instead of 2
+	v_admctl = ioremap_nocache(phy_admctl, 1024);	// map config regs, so we can turn on drive IRQs
+	*((unsigned short *)v_admctl) &= 3;		// enable aIEN; preserve PIO mode
+	iounmap(v_admctl);				// all done; unmap config regs
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/adma100.h linux-2.4.21/drivers/ide/pci/adma100.h
--- linux-2.4.20/drivers/ide/pci/adma100.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/adma100.h	2002-12-18 18:58:02.000000000 +0000
@@ -0,0 +1,36 @@
+#ifndef ADMA_100_H
+#define ADMA_100_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+extern void init_setup_pdcadma(struct pci_dev *, ide_pci_device_t *);
+extern unsigned int init_chipset_pdcadma(struct pci_dev *, const char *);
+extern void init_hwif_pdcadma(ide_hwif_t *);
+extern void init_dma_pdcadma(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t pdcadma_chipsets[] __devinitdata = {
+	{
+		.vendor		= PCI_VENDOR_ID_PDC,
+		.device		= PCI_DEVICE_ID_PDC_1841,
+		.name		= "ADMA100",
+		.init_setup	= init_setup_pdcadma,
+		.init_chipset	= init_chipset_pdcadma,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdcadma,
+		.init_dma	= init_dma_pdcadma,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+}
+
+#endif /* ADMA_100_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/aec62xx.c linux-2.4.21/drivers/ide/pci/aec62xx.c
--- linux-2.4.20/drivers/ide/pci/aec62xx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/aec62xx.c	2002-12-18 18:58:06.000000000 +0000
@@ -0,0 +1,563 @@
+/*
+ * linux/drivers/ide/aec62xx.c		Version 0.11	March 27, 2002
+ *
+ * Copyright (C) 1999-2002	Andre Hedrick <andre@linux-ide.org>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "aec62xx.h"
+
+#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 aec62xx_proc = 0;
+
+#define AEC_MAX_DEVS		5
+
+static struct pci_dev *aec_devs[AEC_MAX_DEVS];
+static int n_aec_devs;
+
+#undef DEBUG_AEC_REGS
+
+static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	char *chipset_nums[] = {"error", "error", "error", "error",
+				"error", "error", "850UF",   "860",
+				 "860R",   "865",  "865R", "error"  };
+	int i;
+
+	for (i = 0; i < n_aec_devs; i++) {
+		struct pci_dev *dev	= aec_devs[i];
+		unsigned long iobase = pci_resource_start(dev, 4);
+		u8 c0 = 0, c1 = 0, art	= 0;
+#ifdef DEBUG_AEC_REGS
+		u8 uart			= 0;
+#endif /* DEBUG_AEC_REGS */
+
+		c0 = inb(iobase + 0x02);
+		c1 = inb(iobase + 0x0a);
+
+		p += sprintf(p, "\nController: %d\n", i);
+		p += sprintf(p, "Chipset: AEC%s\n", chipset_nums[dev->device]);
+
+		p += sprintf(p, "--------------- Primary Channel "
+				"---------------- Secondary Channel "
+				"-------------\n");
+		(void) pci_read_config_byte(dev, 0x4a, &art);
+		p += sprintf(p, "                %sabled ",
+			(art&0x02)?" en":"dis");
+		p += sprintf(p, "                        %sabled\n",
+			(art&0x04)?" en":"dis");
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"-------- drive0 ---------- drive1 ------\n");
+		p += sprintf(p, "DMA enabled:    %s              %s ",
+			(c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ");
+		p += sprintf(p, "            %s               %s\n",
+			(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no ");
+
+		if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+			(void) pci_read_config_byte(dev, 0x54, &art);
+			p += sprintf(p, "DMA Mode:       %s(%s)",
+				(c0&0x20)?((art&0x03)?"UDMA":" DMA"):" PIO",
+				(art&0x02)?"2":(art&0x01)?"1":"0");
+			p += sprintf(p, "          %s(%s)",
+				(c0&0x40)?((art&0x0c)?"UDMA":" DMA"):" PIO",
+				(art&0x08)?"2":(art&0x04)?"1":"0");
+			p += sprintf(p, "         %s(%s)",
+				(c1&0x20)?((art&0x30)?"UDMA":" DMA"):" PIO",
+				(art&0x20)?"2":(art&0x10)?"1":"0");
+			p += sprintf(p, "           %s(%s)\n",
+				(c1&0x40)?((art&0xc0)?"UDMA":" DMA"):" PIO",
+				(art&0x80)?"2":(art&0x40)?"1":"0");
+#ifdef DEBUG_AEC_REGS
+			(void) pci_read_config_byte(dev, 0x40, &art);
+			p += sprintf(p, "Active:         0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x42, &art);
+			p += sprintf(p, "             0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x44, &art);
+			p += sprintf(p, "            0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x46, &art);
+			p += sprintf(p, "              0x%02x\n", art);
+			(void) pci_read_config_byte(dev, 0x41, &art);
+			p += sprintf(p, "Recovery:       0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x43, &art);
+			p += sprintf(p, "             0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x45, &art);
+			p += sprintf(p, "            0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x47, &art);
+			p += sprintf(p, "              0x%02x\n", art);
+#endif /* DEBUG_AEC_REGS */
+		} else {
+			/*
+			 * case PCI_DEVICE_ID_ARTOP_ATP860:
+			 * case PCI_DEVICE_ID_ARTOP_ATP860R:
+			 * case PCI_DEVICE_ID_ARTOP_ATP865:
+			 * case PCI_DEVICE_ID_ARTOP_ATP865R:
+			 */
+			(void) pci_read_config_byte(dev, 0x44, &art);
+			p += sprintf(p, "DMA Mode:       %s(%s)",
+				(c0&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
+				((art&0x07)==0x07)?"6":
+				((art&0x06)==0x06)?"5":
+				((art&0x05)==0x05)?"4":
+				((art&0x04)==0x04)?"3":
+				((art&0x03)==0x03)?"2":
+				((art&0x02)==0x02)?"1":
+				((art&0x01)==0x01)?"0":"?");
+			p += sprintf(p, "          %s(%s)",
+				(c0&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
+				((art&0x70)==0x70)?"6":
+				((art&0x60)==0x60)?"5":
+				((art&0x50)==0x50)?"4":
+				((art&0x40)==0x40)?"3":
+				((art&0x30)==0x30)?"2":
+				((art&0x20)==0x20)?"1":
+				((art&0x10)==0x10)?"0":"?");
+			(void) pci_read_config_byte(dev, 0x45, &art);
+			p += sprintf(p, "         %s(%s)",
+				(c1&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
+				((art&0x07)==0x07)?"6":
+				((art&0x06)==0x06)?"5":
+				((art&0x05)==0x05)?"4":
+				((art&0x04)==0x04)?"3":
+				((art&0x03)==0x03)?"2":
+				((art&0x02)==0x02)?"1":
+				((art&0x01)==0x01)?"0":"?");
+			p += sprintf(p, "           %s(%s)\n",
+				(c1&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
+				((art&0x70)==0x70)?"6":
+				((art&0x60)==0x60)?"5":
+				((art&0x50)==0x50)?"4":
+				((art&0x40)==0x40)?"3":
+				((art&0x30)==0x30)?"2":
+				((art&0x20)==0x20)?"1":
+				((art&0x10)==0x10)?"0":"?");
+#ifdef DEBUG_AEC_REGS
+			(void) pci_read_config_byte(dev, 0x40, &art);
+			p += sprintf(p, "Active:         0x%02x", HIGH_4(art));
+			(void) pci_read_config_byte(dev, 0x41, &art);
+			p += sprintf(p, "             0x%02x", HIGH_4(art));
+			(void) pci_read_config_byte(dev, 0x42, &art);
+			p += sprintf(p, "            0x%02x", HIGH_4(art));
+			(void) pci_read_config_byte(dev, 0x43, &art);
+			p += sprintf(p, "              0x%02x\n", HIGH_4(art));
+			(void) pci_read_config_byte(dev, 0x40, &art);
+			p += sprintf(p, "Recovery:       0x%02x", LOW_4(art));
+			(void) pci_read_config_byte(dev, 0x41, &art);
+			p += sprintf(p, "             0x%02x", LOW_4(art));
+			(void) pci_read_config_byte(dev, 0x42, &art);
+			p += sprintf(p, "            0x%02x", LOW_4(art));
+			(void) pci_read_config_byte(dev, 0x43, &art);
+			p += sprintf(p, "              0x%02x\n", LOW_4(art));
+			(void) pci_read_config_byte(dev, 0x49, &uart);
+			p += sprintf(p, "reg49h = 0x%02x ", uart);
+			(void) pci_read_config_byte(dev, 0x4a, &uart);
+			p += sprintf(p, "reg4ah = 0x%02x\n", uart);
+#endif /* DEBUG_AEC_REGS */
+		}
+	}
+	return p-buffer;/* => must be less than 4k! */
+}
+#endif	/* defined(DISPLAY_AEC62xx_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/*
+ * TO DO: active tuning and correction of cards without a bios.
+ */
+static u8 pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+	for ( ; chipset_table->xfer_speed ; chipset_table++)
+		if (chipset_table->xfer_speed == speed) {
+			return chipset_table->chipset_settings;
+		}
+	return chipset_table->chipset_settings;
+}
+
+static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+	for ( ; chipset_table->xfer_speed ; chipset_table++)
+		if (chipset_table->xfer_speed == speed) {
+			return chipset_table->ultra_settings;
+		}
+	return chipset_table->ultra_settings;
+}
+
+static u8 aec62xx_ratemask (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 mode;
+
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_ARTOP_ATP865:
+		case PCI_DEVICE_ID_ARTOP_ATP865R:
+#if 0
+			mode = (hwif->INB(hwif->dma_master) & 0x10) ? 4 : 3;
+#else
+			mode = (hwif->INB(((hwif->channel) ?
+					hwif->mate->dma_status :
+					hwif->dma_status)) & 0x10) ? 4 : 3;
+#endif
+			break;
+		case PCI_DEVICE_ID_ARTOP_ATP860:
+		case PCI_DEVICE_ID_ARTOP_ATP860R:
+			mode = 2;
+			break;
+		case PCI_DEVICE_ID_ARTOP_ATP850UF:
+		default:
+			return 1;
+	}
+
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static int aec6210_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u16 d_conf		= 0;
+	u8 speed	= ide_rate_filter(aec62xx_ratemask(drive), xferspeed);
+	u8 ultra = 0, ultra_conf = 0;
+	u8 tmp0 = 0, tmp1 = 0, tmp2 = 0;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf);
+	tmp0 = pci_bus_clock_list(speed, BUSCLOCK(dev));
+	SPLIT_BYTE(tmp0,tmp1,tmp2);
+	MAKE_WORD(d_conf,tmp1,tmp2);
+	pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf);
+
+	tmp1 = 0x00;
+	tmp2 = 0x00;
+	pci_read_config_byte(dev, 0x54, &ultra);
+	tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn))));
+	ultra_conf = pci_bus_clock_list_ultra(speed, BUSCLOCK(dev));
+	tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
+	pci_write_config_byte(dev, 0x54, tmp2);
+	local_irq_restore(flags);
+	return(ide_config_drive_speed(drive, speed));
+}
+
+static int aec6260_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed	= ide_rate_filter(aec62xx_ratemask(drive), xferspeed);
+	u8 unit		= (drive->select.b.unit & 0x01);
+	u8 tmp1 = 0, tmp2 = 0;
+	u8 ultra = 0, drive_conf = 0, ultra_conf = 0;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf);
+	drive_conf = pci_bus_clock_list(speed, BUSCLOCK(dev));
+	pci_write_config_byte(dev, 0x40|drive->dn, drive_conf);
+
+	pci_read_config_byte(dev, (0x44|hwif->channel), &ultra);
+	tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit))));
+	ultra_conf = pci_bus_clock_list_ultra(speed, BUSCLOCK(dev));
+	tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
+	pci_write_config_byte(dev, (0x44|hwif->channel), tmp2);
+	local_irq_restore(flags);
+	return(ide_config_drive_speed(drive, speed));
+}
+
+static int aec62xx_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	switch (HWIF(drive)->pci_dev->device) {
+		case PCI_DEVICE_ID_ARTOP_ATP865:
+		case PCI_DEVICE_ID_ARTOP_ATP865R:
+		case PCI_DEVICE_ID_ARTOP_ATP860:
+		case PCI_DEVICE_ID_ARTOP_ATP860R:
+			return ((int) aec6260_tune_chipset(drive, speed));
+		case PCI_DEVICE_ID_ARTOP_ATP850UF:
+			return ((int) aec6210_tune_chipset(drive, speed));
+		default:
+			return -1;
+	}
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, aec62xx_ratemask(drive));	
+
+	if (!(speed))
+		return 0;
+
+	(void) aec62xx_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	u8 speed = 0;
+	u8 new_pio = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+	switch(pio) {
+		case 5:		speed = new_pio; break;
+		case 4:		speed = XFER_PIO_4; break;
+		case 3:		speed = XFER_PIO_3; break;
+		case 2:		speed = XFER_PIO_2; break;
+		case 1:		speed = XFER_PIO_1; break;
+		default:	speed = XFER_PIO_0; break;
+	}
+	(void) aec62xx_tune_chipset(drive, speed);
+}
+
+static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		aec62xx_tune_drive(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static int aec62xx_irq_timeout (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_ARTOP_ATP860:
+		case PCI_DEVICE_ID_ARTOP_ATP860R:
+		case PCI_DEVICE_ID_ARTOP_ATP865:
+		case PCI_DEVICE_ID_ARTOP_ATP865R:
+			printk(" AEC62XX time out ");
+#if 0
+			{
+				int i = 0;
+				u8 reg49h = 0;
+				pci_read_config_byte(HWIF(drive)->pci_dev, 0x49, &reg49h);
+				for (i=0;i<256;i++)
+					pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h|0x10);
+				pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h & ~0x10);
+			}
+			return 0;
+#endif
+		default:
+			break;
+	}
+#if 0
+	{
+		ide_hwif_t *hwif	= HWIF(drive);
+		struct pci_dev *dev	= hwif->pci_dev;
+		u8 tmp1 = 0, tmp2 = 0, mode6 = 0;
+
+		pci_read_config_byte(dev, 0x44, &tmp1);
+		pci_read_config_byte(dev, 0x45, &tmp2);
+		printk(" AEC6280 r44=%x r45=%x ",tmp1,tmp2);
+		mode6 = HWIF(drive)->INB(((hwif->channel) ?
+					   hwif->mate->dma_status :
+					   hwif->dma_status));
+		printk(" AEC6280 133=%x ", (mode6 & 0x10));
+	}
+#endif
+	return 0;
+}
+
+static unsigned int __init init_chipset_aec62xx (struct pci_dev *dev, const char *name)
+{
+	int bus_speed = system_bus_clock();
+
+	if (dev->resource[PCI_ROM_RESOURCE].start) {
+		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
+	}
+
+#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
+	aec_devs[n_aec_devs++] = dev;
+
+	if (!aec62xx_proc) {
+		aec62xx_proc = 1;
+		ide_pci_register_host_proc(&aec62xx_procs[0]);
+	}
+#endif /* DISPLAY_AEC62XX_TIMINGS && CONFIG_PROC_FS */
+
+	if (bus_speed <= 33)
+		pci_set_drvdata(dev, (void *) aec6xxx_33_base);
+	else
+		pci_set_drvdata(dev, (void *) aec6xxx_34_base);
+
+	return dev->irq;
+}
+
+static void __init init_hwif_aec62xx (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->tuneproc = &aec62xx_tune_drive;
+	hwif->speedproc = &aec62xx_tune_chipset;
+
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+		hwif->serialized = hwif->channel;
+		hwif->no_dsc = 1;
+	}
+
+	if (hwif->mate)
+		hwif->mate->serialized = hwif->serialized;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	hwif->ide_dma_check	= &aec62xx_config_drive_xfer_rate;
+	hwif->ide_dma_lostirq	= &aec62xx_irq_timeout;
+	hwif->ide_dma_timeout	= &aec62xx_irq_timeout;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_aec62xx (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+		u8 reg54h = 0;
+		unsigned long flags;
+
+		spin_lock_irqsave(&ide_lock, flags);
+		pci_read_config_byte(dev, 0x54, &reg54h);
+		pci_write_config_byte(dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F));
+		spin_unlock_irqrestore(&ide_lock, flags);
+	} else {
+		u8 ata66	= 0;
+		pci_read_config_byte(hwif->pci_dev, 0x49, &ata66);
+	        if (!(hwif->udma_four))
+			hwif->udma_four = (ata66&(hwif->channel?0x02:0x01))?0:1;
+	}
+
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_aec62xx (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_aec6x80 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	unsigned long bar4reg = pci_resource_start(dev, 4);
+
+	if (inb(bar4reg+2) & 0x10) {
+		strcpy(d->name, "AEC6880");
+		if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)
+			strcpy(d->name, "AEC6880R");
+	} else {
+		strcpy(d->name, "AEC6280");
+		if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)
+			strcpy(d->name, "AEC6280R");
+	}
+
+	ide_setup_pci_device(dev, d);
+}
+
+/**
+ *	aec62xx_init_one	-	called when a AEC is found
+ *	@dev: the aec62xx device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit aec62xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &aec62xx_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id aec62xx_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
+	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
+	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
+	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "AEC62xx IDE",
+	.id_table	= aec62xx_pci_tbl,
+	.probe		= aec62xx_init_one,
+};
+
+static int aec62xx_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void aec62xx_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(aec62xx_ide_init);
+module_exit(aec62xx_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for ARTOP AEC62xx IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/aec62xx.h linux-2.4.21/drivers/ide/pci/aec62xx.h
--- linux-2.4.20/drivers/ide/pci/aec62xx.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/aec62xx.h	2002-12-18 18:58:04.000000000 +0000
@@ -0,0 +1,171 @@
+#ifndef AEC62XX_H
+#define AEC62XX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_AEC62XX_TIMINGS
+
+struct chipset_bus_clock_list_entry {
+	byte		xfer_speed;
+	byte		chipset_settings;
+	byte		ultra_settings;
+};
+
+struct chipset_bus_clock_list_entry aec6xxx_33_base [] = {
+	{	XFER_UDMA_6,	0x31,	0x07	},
+	{	XFER_UDMA_5,	0x31,	0x06	},
+	{	XFER_UDMA_4,	0x31,	0x05	},
+	{	XFER_UDMA_3,	0x31,	0x04	},
+	{	XFER_UDMA_2,	0x31,	0x03	},
+	{	XFER_UDMA_1,	0x31,	0x02	},
+	{	XFER_UDMA_0,	0x31,	0x01	},
+
+	{	XFER_MW_DMA_2,	0x31,	0x00	},
+	{	XFER_MW_DMA_1,	0x31,	0x00	},
+	{	XFER_MW_DMA_0,	0x0a,	0x00	},
+	{	XFER_PIO_4,	0x31,	0x00	},
+	{	XFER_PIO_3,	0x33,	0x00	},
+	{	XFER_PIO_2,	0x08,	0x00	},
+	{	XFER_PIO_1,	0x0a,	0x00	},
+	{	XFER_PIO_0,	0x00,	0x00	},
+	{	0,		0x00,	0x00	}
+};
+
+struct chipset_bus_clock_list_entry aec6xxx_34_base [] = {
+	{	XFER_UDMA_6,	0x41,	0x06	},
+	{	XFER_UDMA_5,	0x41,	0x05	},
+	{	XFER_UDMA_4,	0x41,	0x04	},
+	{	XFER_UDMA_3,	0x41,	0x03	},
+	{	XFER_UDMA_2,	0x41,	0x02	},
+	{	XFER_UDMA_1,	0x41,	0x01	},
+	{	XFER_UDMA_0,	0x41,	0x01	},
+
+	{	XFER_MW_DMA_2,	0x41,	0x00	},
+	{	XFER_MW_DMA_1,	0x42,	0x00	},
+	{	XFER_MW_DMA_0,	0x7a,	0x00	},
+	{	XFER_PIO_4,	0x41,	0x00	},
+	{	XFER_PIO_3,	0x43,	0x00	},
+	{	XFER_PIO_2,	0x78,	0x00	},
+	{	XFER_PIO_1,	0x7a,	0x00	},
+	{	XFER_PIO_0,	0x70,	0x00	},
+	{	0,		0x00,	0x00	}
+};
+
+
+#ifndef HIGH_4
+#define HIGH_4(H)		((H)=(H>>4))
+#endif
+#ifndef LOW_4
+#define LOW_4(L)		((L)=(L-((L>>4)<<4)))
+#endif
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+#ifndef MAKE_WORD
+#define MAKE_WORD(W,HB,LB)	((W)=((HB<<8)+LB))
+#endif
+
+#define BUSCLOCK(D)	\
+	((struct chipset_bus_clock_list_entry *) pci_get_drvdata((D)))
+
+#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 aec62xx_proc;
+
+static int aec62xx_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t aec62xx_procs[] __initdata = {
+	{
+		.name		= "aec62xx",
+		.set		= 1,
+		.get_info	= aec62xx_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_AEC62XX_TIMINGS && CONFIG_PROC_FS */
+
+static void init_setup_aec6x80(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_aec62xx(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_aec62xx(struct pci_dev *, const char *);
+static void init_hwif_aec62xx(ide_hwif_t *);
+static void init_dma_aec62xx(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_ARTOP,
+		.device		= PCI_DEVICE_ID_ARTOP_ATP850UF,
+		.name		= "AEC6210",
+		.init_setup	= init_setup_aec62xx,
+		.init_chipset	= init_chipset_aec62xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_aec62xx,
+		.init_dma	= init_dma_aec62xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_ARTOP,
+		.device		= PCI_DEVICE_ID_ARTOP_ATP860,
+		.name		= "AEC6260",
+		.init_setup	= init_setup_aec62xx,
+		.init_chipset	= init_chipset_aec62xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_aec62xx,
+		.init_dma	= init_dma_aec62xx,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_ARTOP,
+		.device		= PCI_DEVICE_ID_ARTOP_ATP860R,
+		.name		= "AEC6260R",
+		.init_setup	= init_setup_aec62xx,
+		.init_chipset	= init_chipset_aec62xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_aec62xx,
+		.init_dma	= init_dma_aec62xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+		.bootable	= NEVER_BOARD,
+		.extra		= 0,
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_ARTOP,
+		.device		= PCI_DEVICE_ID_ARTOP_ATP865,
+		.name		= "AEC6X80",
+		.init_setup	= init_setup_aec6x80,
+		.init_chipset	= init_chipset_aec62xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_aec62xx,
+		.init_dma	= init_dma_aec62xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 4 */
+		.vendor		= PCI_VENDOR_ID_ARTOP,
+		.device		= PCI_DEVICE_ID_ARTOP_ATP865R,
+		.name		= "AEC6X80R",
+		.init_setup	= init_setup_aec6x80,
+		.init_chipset	= init_chipset_aec62xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_aec62xx,
+		.init_dma	= init_dma_aec62xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	}
+};
+
+#endif /* AEC62XX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/alim15x3.c linux-2.4.21/drivers/ide/pci/alim15x3.c
--- linux-2.4.20/drivers/ide/pci/alim15x3.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/alim15x3.c	2002-12-18 18:58:10.000000000 +0000
@@ -0,0 +1,898 @@
+/*
+ * linux/drivers/ide/alim15x3.c		Version 0.15	2002/08/19
+ *
+ *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
+ *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
+ *  Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer
+ *
+ *  Copyright (C) 1998-2000 Andre Hedrick (andre@linux-ide.org)
+ *  May be copied or modified under the terms of the GNU General Public License
+ *  Copyright (C) 2002 Alan Cox <alan@redhat.com>
+ *
+ *  (U)DMA capable version of ali 1533/1543(C), 1535(D)
+ *
+ **********************************************************************
+ *  9/7/99 --Parts from the above author are included and need to be
+ *  converted into standard interface, once I finish the thought.
+ *
+ *  Recent changes
+ *	Don't use LBA48 mode on ALi <= 0xC4
+ *	Don't poke 0x79 with a non ALi northbridge
+ *	Don't flip undefined bits on newer chipsets (fix Fujitsu laptop hang)
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "alim15x3.h"
+
+/*
+ *	ALi devices are not plug in. Otherwise these static values would
+ *	need to go. They ought to go away anyway
+ */
+ 
+static u8 m5229_revision;
+static u8 chip_is_1543c_e;
+static struct pci_dev *isa_dev;
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 ali_proc = 0;
+
+static struct pci_dev *bmide_dev;
+
+static char *fifo[4] = {
+	"FIFO Off",
+	"FIFO On ",
+	"DMA mode",
+	"PIO mode" };
+
+static char *udmaT[8] = {
+	"1.5T",
+	"  2T",
+	"2.5T",
+	"  3T",
+	"3.5T",
+	"  4T",
+	"  6T",
+	"  8T"
+};
+
+static char *channel_status[8] = {
+	"OK            ",
+	"busy          ",
+	"DRQ           ",
+	"DRQ busy      ",
+	"error         ",
+	"error busy    ",
+	"error DRQ     ",
+	"error DRQ busy"
+};
+
+/**
+ *	ali_get_info		-	generate proc file for ALi IDE
+ *	@buffer: buffer to fill
+ *	@addr: address of user start in buffer
+ *	@offset: offset into 'file'
+ *	@count: buffer count
+ *
+ *	Walks the Ali devices and outputs summary data on the tuning and
+ *	anything else that will help with debugging
+ */
+ 
+static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	unsigned long bibma;
+	u8 reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1, c0, c1, rev, tmp;
+	char *q, *p = buffer;
+
+	/* fetch rev. */
+	pci_read_config_byte(bmide_dev, 0x08, &rev);
+	if (rev >= 0xc1)	/* M1543C or newer */
+		udmaT[7] = " ???";
+	else
+		fifo[3]  = "   ???  ";
+
+	/* first fetch bibma: */
+	
+	bibma = pci_resource_start(bmide_dev, 4);
+
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte
+	 * registers to investigate:
+	 */
+	c0 = inb(bibma + 0x02);
+	c1 = inb(bibma + 0x0a);
+
+	p += sprintf(p,
+		"\n                                Ali M15x3 Chipset.\n");
+	p += sprintf(p,
+		"                                ------------------\n");
+	pci_read_config_byte(bmide_dev, 0x78, &reg53h);
+	p += sprintf(p, "PCI Clock: %d.\n", reg53h);
+
+	pci_read_config_byte(bmide_dev, 0x53, &reg53h);
+	p += sprintf(p,
+		"CD_ROM FIFO:%s, CD_ROM DMA:%s\n",
+		(reg53h & 0x02) ? "Yes" : "No ",
+		(reg53h & 0x01) ? "Yes" : "No " );
+	pci_read_config_byte(bmide_dev, 0x74, &reg53h);
+	p += sprintf(p,
+		"FIFO Status: contains %d Words, runs%s%s\n\n",
+		(reg53h & 0x3f),
+		(reg53h & 0x40) ? " OVERWR" : "",
+		(reg53h & 0x80) ? " OVERRD." : "." );
+
+	p += sprintf(p,
+		"-------------------primary channel"
+		"-------------------secondary channel"
+		"---------\n\n");
+
+	pci_read_config_byte(bmide_dev, 0x09, &reg53h);
+	p += sprintf(p,
+		"channel status:       %s"
+		"                               %s\n",
+		(reg53h & 0x20) ? "On " : "Off",
+		(reg53h & 0x10) ? "On " : "Off" );
+
+	p += sprintf(p,
+		"both channels togth:  %s"
+		"                               %s\n",
+		(c0&0x80) ? "No " : "Yes",
+		(c1&0x80) ? "No " : "Yes" );
+
+	pci_read_config_byte(bmide_dev, 0x76, &reg53h);
+	p += sprintf(p,
+		"Channel state:        %s                    %s\n",
+		channel_status[reg53h & 0x07],
+		channel_status[(reg53h & 0x70) >> 4] );
+
+	pci_read_config_byte(bmide_dev, 0x58, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x5c, &reg5yh);
+	p += sprintf(p,
+		"Add. Setup Timing:    %dT"
+		"                                %dT\n",
+		(reg5xh & 0x07) ? (reg5xh & 0x07) : 8,
+		(reg5yh & 0x07) ? (reg5yh & 0x07) : 8 );
+
+	pci_read_config_byte(bmide_dev, 0x59, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x5d, &reg5yh);
+	p += sprintf(p,
+		"Command Act. Count:   %dT"
+		"                                %dT\n"
+		"Command Rec. Count:   %dT"
+		"                               %dT\n\n",
+		(reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
+		(reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8, 
+		(reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
+		(reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16 );
+
+	p += sprintf(p,
+		"----------------drive0-----------drive1"
+		"------------drive0-----------drive1------\n\n");
+	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 " );
+
+	pci_read_config_byte(bmide_dev, 0x54, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x55, &reg5yh);
+	q = "FIFO threshold:   %2d Words         %2d Words"
+		"          %2d Words         %2d Words\n";
+	if (rev < 0xc1) {
+		if ((rev == 0x20) &&
+		    (pci_read_config_byte(bmide_dev, 0x4f, &tmp), (tmp &= 0x20))) {
+			p += sprintf(p, q, 8, 8, 8, 8);
+		} else {
+			p += sprintf(p, q,
+				(reg5xh & 0x03) + 12,
+				((reg5xh & 0x30)>>4) + 12,
+				(reg5yh & 0x03) + 12,
+				((reg5yh & 0x30)>>4) + 12 );
+		}
+	} else {
+		int t1 = (tmp = (reg5xh & 0x03)) ? (tmp << 3) : 4;
+		int t2 = (tmp = ((reg5xh & 0x30)>>4)) ? (tmp << 3) : 4;
+		int t3 = (tmp = (reg5yh & 0x03)) ? (tmp << 3) : 4;
+		int t4 = (tmp = ((reg5yh & 0x30)>>4)) ? (tmp << 3) : 4;
+		p += sprintf(p, q, t1, t2, t3, t4);
+	}
+
+#if 0
+	p += sprintf(p, 
+		"FIFO threshold:   %2d Words         %2d Words"
+		"          %2d Words         %2d Words\n",
+		(reg5xh & 0x03) + 12,
+		((reg5xh & 0x30)>>4) + 12,
+		(reg5yh & 0x03) + 12,
+		((reg5yh & 0x30)>>4) + 12 );
+#endif
+
+	p += sprintf(p,
+		"FIFO mode:        %s         %s          %s         %s\n",
+		fifo[((reg5xh & 0x0c) >> 2)],
+		fifo[((reg5xh & 0xc0) >> 6)],
+		fifo[((reg5yh & 0x0c) >> 2)],
+		fifo[((reg5yh & 0xc0) >> 6)] );
+
+	pci_read_config_byte(bmide_dev, 0x5a, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x5b, &reg5xh1);
+	pci_read_config_byte(bmide_dev, 0x5e, &reg5yh);
+	pci_read_config_byte(bmide_dev, 0x5f, &reg5yh1);
+
+	p += sprintf(p,/*
+		"------------------drive0-----------drive1"
+		"------------drive0-----------drive1------\n")*/
+		"Dt RW act. Cnt    %2dT              %2dT"
+		"               %2dT              %2dT\n"
+		"Dt RW rec. Cnt    %2dT              %2dT"
+		"               %2dT              %2dT\n\n",
+		(reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
+		(reg5xh1 & 0x70) ? ((reg5xh1 & 0x70) >> 4) : 8,
+		(reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8,
+		(reg5yh1 & 0x70) ? ((reg5yh1 & 0x70) >> 4) : 8,
+		(reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
+		(reg5xh1 & 0x0f) ? (reg5xh1 & 0x0f) : 16,
+		(reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16,
+		(reg5yh1 & 0x0f) ? (reg5yh1 & 0x0f) : 16 );
+
+	p += sprintf(p,
+		"-----------------------------------UDMA Timings"
+		"--------------------------------\n\n");
+
+	pci_read_config_byte(bmide_dev, 0x56, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x57, &reg5yh);
+	p += sprintf(p,
+		"UDMA:             %s               %s"
+		"                %s               %s\n"
+		"UDMA timings:     %s             %s"
+		"              %s             %s\n\n",
+		(reg5xh & 0x08) ? "OK" : "No",
+		(reg5xh & 0x80) ? "OK" : "No",
+		(reg5yh & 0x08) ? "OK" : "No",
+		(reg5yh & 0x80) ? "OK" : "No",
+		udmaT[(reg5xh & 0x07)],
+		udmaT[(reg5xh & 0x70) >> 4],
+		udmaT[reg5yh & 0x07],
+		udmaT[(reg5yh & 0x70) >> 4] );
+
+	return p-buffer; /* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/**
+ *	ali15x3_tune_drive	-	set up a drive
+ *	@drive: drive to tune
+ *	@pio: unused
+ *
+ *	Select the best PIO timing for the drive in question. Then
+ *	program the controller for this drive set up
+ */
+ 
+static void ali15x3_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_pio_data_t d;
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	int s_time, a_time, c_time;
+	u8 s_clc, a_clc, r_clc;
+	unsigned long flags;
+	int bus_speed = system_bus_clock();
+	int port = hwif->channel ? 0x5c : 0x58;
+	int portFIFO = hwif->channel ? 0x55 : 0x54;
+	u8 cd_dma_fifo = 0;
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, &d);
+	s_time = ide_pio_timings[pio].setup_time;
+	a_time = ide_pio_timings[pio].active_time;
+	if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
+		s_clc = 0;
+	if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8)
+		a_clc = 0;
+	c_time = ide_pio_timings[pio].cycle_time;
+
+#if 0
+	if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16)
+		r_clc = 0;
+#endif
+
+	if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) {
+		r_clc = 1;
+	} else {
+		if (r_clc >= 16)
+			r_clc = 0;
+	}
+	local_irq_save(flags);
+	
+	/* 
+	 * PIO mode => ATA FIFO on, ATAPI FIFO off
+	 */
+	pci_read_config_byte(dev, portFIFO, &cd_dma_fifo);
+	if (drive->media==ide_disk) {
+		if (hwif->channel) {
+			pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0x0F) | 0x50);
+		} else {
+			pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0xF0) | 0x05);
+		}
+	} else {
+		if (hwif->channel) {
+			pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0x0F);
+		} else {
+			pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0xF0);
+		}
+	}
+	
+	pci_write_config_byte(dev, port, s_clc);
+	pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc);
+	local_irq_restore(flags);
+
+	/*
+	 * setup   active  rec
+	 * { 70,   165,    365 },   PIO Mode 0
+	 * { 50,   125,    208 },   PIO Mode 1
+	 * { 30,   100,    110 },   PIO Mode 2
+	 * { 30,   80,     70  },   PIO Mode 3 with IORDY
+	 * { 25,   70,     25  },   PIO Mode 4 with IORDY  ns
+	 * { 20,   50,     30  }    PIO Mode 5 with IORDY (nonstandard)
+	 */
+
+}
+
+/**
+ *	ali15x3_can_ultra	-	check for ultra DMA support
+ *	@drive: drive to do the check
+ *
+ *	Check the drive and controller revisions. Return 0 if UDMA is
+ *	not available, or 1 if UDMA can be used. The actual rules for
+ *	the ALi are
+ *		No UDMA on revisions <= 0x20
+ *		Disk only for revisions < 0xC2
+ *		Not WDC drives for revisions < 0xC2
+ *
+ *	FIXME: WDC ifdef needs to die
+ */
+ 
+static u8 ali15x3_can_ultra (ide_drive_t *drive)
+{
+#ifndef CONFIG_WDC_ALI15X3
+	struct hd_driveid *id	= drive->id;
+#endif /* CONFIG_WDC_ALI15X3 */
+
+	if (m5229_revision <= 0x20) {
+		return 0;
+	} else if ((m5229_revision < 0xC2) &&
+#ifndef CONFIG_WDC_ALI15X3
+		   ((chip_is_1543c_e && strstr(id->model, "WDC ")) ||
+		    (drive->media!=ide_disk))) {
+#else /* CONFIG_WDC_ALI15X3 */
+		   (drive->media!=ide_disk)) {
+#endif /* CONFIG_WDC_ALI15X3 */
+		return 0;
+	} else {
+		return 1;
+	}
+}
+
+/**
+ *	ali15x3_ratemask	-	generate DMA mode list
+ *	@drive: drive to compute against
+ *
+ *	Generate a list of the available DMA modes for the drive. 
+ *	FIXME: this function contains lots of bogus masking we can dump
+ *
+ *	Return the highest available mode (UDMA33, UDMA66, UDMA100,..)
+ */
+ 
+static u8 ali15x3_ratemask (ide_drive_t *drive)
+{
+	u8 mode = 0, can_ultra	= ali15x3_can_ultra(drive);
+
+	if (m5229_revision >= 0xC4 && can_ultra) {
+		mode = 3;
+	} else if (m5229_revision >= 0xC2 && can_ultra) {
+		mode = 2;
+	} else if (can_ultra) {
+		return 1;
+	} else {
+		return 0;
+	}
+
+	/*
+	 *	If the drive sees no suitable cable then UDMA 33
+	 *	is the highest permitted mode
+	 */
+	 
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+/**
+ *	ali15x3_tune_chipset	-	set up chiset for new speed
+ *	@drive: drive to configure for
+ *	@xferspeed: desired speed
+ *
+ *	Configure the hardware for the desired IDE transfer mode.
+ *	We also do the needed drive configuration through helpers
+ */
+ 
+static int ali15x3_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed	= ide_rate_filter(ali15x3_ratemask(drive), xferspeed);
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 tmpbyte		= 0x00;
+	int m5229_udma		= (hwif->channel) ? 0x57 : 0x56;
+
+	if (speed < XFER_UDMA_0) {
+		u8 ultra_enable	= (unit) ? 0x7f : 0xf7;
+		/*
+		 * clear "ultra enable" bit
+		 */
+		pci_read_config_byte(dev, m5229_udma, &tmpbyte);
+		tmpbyte &= ultra_enable;
+		pci_write_config_byte(dev, m5229_udma, tmpbyte);
+
+		if (speed < XFER_SW_DMA_0)
+			ali15x3_tune_drive(drive, speed);
+	} else {
+		pci_read_config_byte(dev, m5229_udma, &tmpbyte);
+		tmpbyte &= (0x0f << ((1-unit) << 2));
+		/*
+		 * enable ultra dma and set timing
+		 */
+		tmpbyte |= ((0x08 | ((4-speed)&0x07)) << (unit << 2));
+		pci_write_config_byte(dev, m5229_udma, tmpbyte);
+		if (speed >= XFER_UDMA_3) {
+			pci_read_config_byte(dev, 0x4b, &tmpbyte);
+			tmpbyte |= 1;
+			pci_write_config_byte(dev, 0x4b, tmpbyte);
+		}
+	}
+	return (ide_config_drive_speed(drive, speed));
+}
+
+
+/**
+ *	config_chipset_for_dma	-	set up DMA mode
+ *	@drive: drive to configure for
+ *
+ *	Place a drive into DMA mode and tune the chipset for
+ *	the selected speed.
+ *
+ *	Returns true if DMA mode can be used
+ */
+ 
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, ali15x3_ratemask(drive));
+
+	if (!(speed))
+		return 0;
+
+	(void) ali15x3_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+/**
+ *	ali15x3_config_drive_for_dma	-	configure for DMA
+ *	@drive: drive to configure
+ *
+ *	Configure a drive for DMA operation. If DMA is not possible we
+ *	drop the drive into PIO mode instead.
+ *
+ *	FIXME: exactly what are we trying to return here
+ */
+ 
+static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	if ((m5229_revision<=0x20) && (drive->media!=ide_disk))
+		return hwif->ide_dma_off_quietly(drive);
+
+	drive->init_speed = 0;
+
+	if ((id != NULL) && ((id->capability & 1) != 0) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hwif->tuneproc(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+/**
+ *	ali15x3_dma_write	-	do a DMA IDE write
+ *	@drive:	drive to issue write for
+ *
+ *	Returns 1 if the DMA write cannot be performed, zero on 
+ *	success.
+ */
+ 
+static int ali15x3_dma_write (ide_drive_t *drive)
+{
+	if ((m5229_revision < 0xC2) && (drive->media != ide_disk))
+		return 1;	/* try PIO instead of DMA */
+	return __ide_dma_write(drive);
+}
+
+/**
+ *	init_chipset_ali15x3	-	Initialise an ALi IDE controller
+ *	@dev: PCI device
+ *	@name: Name of the controller
+ *
+ *	This function initializes the ALI IDE controller and where 
+ *	appropriate also sets up the 1533 southbridge.
+ */
+  
+static unsigned int __init init_chipset_ali15x3 (struct pci_dev *dev, const char *name)
+{
+	unsigned long flags;
+	u8 tmpbyte;
+	struct pci_dev *north = pci_find_slot(0, PCI_DEVFN(0,0));
+
+	pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision);
+
+	isa_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!ali_proc) {
+		ali_proc = 1;
+		bmide_dev = dev;
+		ide_pci_register_host_proc(&ali_procs[0]);
+	}
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+	local_irq_save(flags);
+
+	if (m5229_revision < 0xC2) {
+		/*
+		 * revision 0x20 (1543-E, 1543-F)
+		 * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E)
+		 * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7
+		 */
+		pci_read_config_byte(dev, 0x4b, &tmpbyte);
+		/*
+		 * clear bit 7
+		 */
+		pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
+		local_irq_restore(flags);
+		return 0;
+	}
+
+	/*
+	 * 1543C-B?, 1535, 1535D, 1553
+	 * Note 1: not all "motherboard" support this detection
+	 * Note 2: if no udma 66 device, the detection may "error".
+	 *         but in this case, we will not set the device to
+	 *         ultra 66, the detection result is not important
+	 */
+
+	/*
+	 * enable "Cable Detection", m5229, 0x4b, bit3
+	 */
+	pci_read_config_byte(dev, 0x4b, &tmpbyte);
+	pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08);
+
+	/*
+	 * We should only tune the 1533 enable if we are using an ALi
+	 * North bridge. We might have no north found on some zany
+	 * box without a device at 0:0.0. The ALi bridge will be at
+	 * 0:0.0 so if we didn't find one we know what is cooking.
+	 */
+	if (north && north->vendor != PCI_VENDOR_ID_AL) {
+		local_irq_restore(flags);
+	        return 0;
+	}
+
+	/*
+	 * set south-bridge's enable bit, m1533, 0x79
+	 */
+
+	pci_read_config_byte(isa_dev, 0x79, &tmpbyte);
+	if (m5229_revision == 0xC2) {
+		/*
+		 * 1543C-B0 (m1533, 0x79, bit 2)
+		 */
+		pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04);
+	} else if (m5229_revision >= 0xC3) {
+		/*
+		 * 1553/1535 (m1533, 0x79, bit 1)
+		 */
+		pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
+	}
+
+	local_irq_restore(flags);
+	return 0;
+}
+
+/**
+ *	ata66_ali15x3	-	check for UDMA 66 support
+ *	@hwif: IDE interface
+ *
+ *	This checks if the controller and the cable are capable
+ *	of UDMA66 transfers. It doesn't check the drives.
+ *	But see note 2 below!
+ *
+ *	FIXME: frobs bits that are not defined on newer ALi devicea
+ */
+
+static unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned int ata66	= 0;
+	u8 cable_80_pin[2]	= { 0, 0 };
+
+	unsigned long flags;
+	u8 tmpbyte;
+
+	local_irq_save(flags);
+
+	if (m5229_revision >= 0xC2) {
+		/*
+		 * Ultra66 cable detection (from Host View)
+		 * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin
+		 */
+		pci_read_config_byte(dev, 0x4a, &tmpbyte);
+		/*
+		 * 0x4a, bit0 is 0 => primary channel
+		 * has 80-pin (from host view)
+		 */
+		if (!(tmpbyte & 0x01)) cable_80_pin[0] = 1;
+		/*
+		 * 0x4a, bit1 is 0 => secondary channel
+		 * has 80-pin (from host view)
+		 */
+		if (!(tmpbyte & 0x02)) cable_80_pin[1] = 1;
+		/*
+		 * Allow ata66 if cable of current channel has 80 pins
+		 */
+		ata66 = (hwif->channel)?cable_80_pin[1]:cable_80_pin[0];
+	} else {
+		/*
+		 * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
+		 */
+		pci_read_config_byte(isa_dev, 0x5e, &tmpbyte);
+		chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0;
+	}
+
+	/*
+	 * CD_ROM DMA on (m5229, 0x53, bit0)
+	 *      Enable this bit even if we want to use PIO
+	 * PIO FIFO off (m5229, 0x53, bit1)
+	 *      The hardware will use 0x54h and 0x55h to control PIO FIFO
+	 *	(Not on later devices it seems)
+	 *
+	 *	0x53 changes meaning on later revs - we must no touch
+	 *	bit 1 on them. Need to check if 0x20 is the right break
+	 */
+	 
+	pci_read_config_byte(dev, 0x53, &tmpbyte);
+	
+	if(m5229_revision <= 0x20)
+		tmpbyte = (tmpbyte & (~0x02)) | 0x01;
+	else
+		tmpbyte |= 0x01;
+
+	pci_write_config_byte(dev, 0x53, tmpbyte);
+
+	local_irq_restore(flags);
+
+	return(ata66);
+}
+
+/**
+ *	init_hwif_common_ali15x3	-	Set up ALI IDE hardware
+ *	@hwif: IDE interface
+ *
+ *	Initialize the IDE structure side of the ALi 15x3 driver.
+ */
+ 
+static void __init init_hwif_common_ali15x3 (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->tuneproc = &ali15x3_tune_drive;
+	hwif->speedproc = &ali15x3_tune_chipset;
+
+	/* Don't use LBA48 on ALi devices before rev 0xC5 */
+	hwif->addressing = (m5229_revision <= 0xC4) ? 1 : 0;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	if (m5229_revision > 0x20)
+		hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+        if (m5229_revision >= 0x20) {
+                /*
+                 * M1543C or newer for DMAing
+                 */
+                hwif->ide_dma_check = &ali15x3_config_drive_for_dma;
+                hwif->ide_dma_write = &ali15x3_dma_write;
+		if (!noautodma)
+			hwif->autodma = 1;
+		if (!(hwif->udma_four))
+			hwif->udma_four = ata66_ali15x3(hwif);
+	}
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+/**
+ *	init_hwif_ali15x3	-	Initialize the ALI IDE x86 stuff
+ *	@hwif: interface to configure
+ *
+ *	Obtain the IRQ tables for an ALi based IDE solution on the PC
+ *	class platforms. This part of the code isn't applicable to the
+ *	Sparc systems
+ */
+
+static void __init init_hwif_ali15x3 (ide_hwif_t *hwif)
+{
+	u8 ideic, inmir;
+	s8 irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
+				      1, 11, 0, 12, 0, 14, 0, 15 };
+	int irq;
+	
+	hwif->irq = hwif->channel ? 15 : 14;
+
+	if (isa_dev) {
+		/*
+		 * read IDE interface control
+		 */
+		pci_read_config_byte(isa_dev, 0x58, &ideic);
+
+		/* bit0, bit1 */
+		ideic = ideic & 0x03;
+
+		/* get IRQ for IDE Controller */
+		if ((hwif->channel && ideic == 0x03) ||
+		    (!hwif->channel && !ideic)) {
+			/*
+			 * get SIRQ1 routing table
+			 */
+			pci_read_config_byte(isa_dev, 0x44, &inmir);
+			inmir = inmir & 0x0f;
+			irq = irq_routing_table[inmir];
+		} else if (hwif->channel && !(ideic & 0x01)) {
+			/*
+			 * get SIRQ2 routing table
+			 */
+			pci_read_config_byte(isa_dev, 0x75, &inmir);
+			inmir = inmir & 0x0f;
+			irq = irq_routing_table[inmir];
+		}
+		if(irq >= 0)
+			hwif->irq = irq;
+	}
+
+	init_hwif_common_ali15x3(hwif);
+}
+
+/**
+ *	init_dma_ali15x3	-	set up DMA on ALi15x3
+ *	@hwif: IDE interface
+ *	@dmabase: DMA interface base PCI address
+ *
+ *	Set up the DMA functionality on the ALi 15x3. For the ALi
+ *	controllers this is generic so we can let the generic code do
+ *	the actual work.
+ */
+
+static void __init init_dma_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	if (m5229_revision < 0x20)
+		return;
+	if (!(hwif->channel))
+		hwif->OUTB(hwif->INB(dmabase+2) & 0x60, dmabase+2);
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+
+/**
+ *	alim15x3_init_one	-	set up an ALi15x3 IDE controller
+ *	@dev: PCI device to set up
+ *
+ *	Perform the actual set up for an ALi15x3 that has been found by the
+ *	hot plug layer.
+ */
+ 
+static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &ali15x3_chipsets[id->driver_data];
+	
+	if(pci_find_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_IGP, NULL))
+	{
+		printk(KERN_ERR "Warning: ATI Radeon IGP Northbridge is not supported by Linux\n");
+		return 1;
+	}
+#if defined(CONFIG_SPARC64)
+	d->init_hwif = init_hwif_common_ali15x3;
+#endif /* CONFIG_SPARC64 */
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+
+static struct pci_device_id alim15x3_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "ALI15x3 IDE",
+	.id_table	= alim15x3_pci_tbl,
+	.probe		= alim15x3_init_one,
+};
+
+static int ali15x3_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void ali15x3_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(ali15x3_ide_init);
+module_exit(ali15x3_ide_exit);
+
+MODULE_AUTHOR("Michael Aubry, Andrzej Krzysztofowicz, CJ, Andre Hedrick, Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for ALi 15x3 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/alim15x3.h linux-2.4.21/drivers/ide/pci/alim15x3.h
--- linux-2.4.20/drivers/ide/pci/alim15x3.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/alim15x3.h	2002-12-18 18:58:02.000000000 +0000
@@ -0,0 +1,55 @@
+#ifndef ALI15X3_H
+#define ALI15X3_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_ALI_TIMINGS
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 ali_proc;
+
+static int ali_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t ali_procs[] __initdata = {
+	{
+		.name		= "ali",
+		.set		= 1,
+		.get_info	= ali_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_ALI_TIMINGS && CONFIG_PROC_FS */
+
+static unsigned int init_chipset_ali15x3(struct pci_dev *, const char *);
+static void init_hwif_common_ali15x3(ide_hwif_t *);
+static void init_hwif_ali15x3(ide_hwif_t *);
+static void init_dma_ali15x3(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t ali15x3_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_AL,
+		.device		= PCI_DEVICE_ID_AL_M5229,
+		.name		= "ALI15X3",
+		.init_chipset	= init_chipset_ali15x3,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_ali15x3,
+		.init_dma	= init_dma_ali15x3,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* ALI15X3 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/amd74xx.c linux-2.4.21/drivers/ide/pci/amd74xx.c
--- linux-2.4.20/drivers/ide/pci/amd74xx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/amd74xx.c	2002-12-18 18:58:01.000000000 +0000
@@ -0,0 +1,425 @@
+/*
+ * linux/drivers/ide/amd74xx.c		Version 0.05	June 9, 2000
+ *
+ * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "amd74xx.h"
+
+#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 amd74xx_proc = 0;
+
+static struct pci_dev *bmide_dev;
+
+static int amd74xx_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	u32 bibma = pci_resource_start(bmide_dev, 4);
+	u8 c0 = 0, c1 = 0;
+
+	/*
+	 * 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);
+
+	p += sprintf(p, "\n                                "
+			"AMD %04X VIPER Chipset.\n", bmide_dev->device);
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled "
+			"                        %sabled\n",
+			(c0&0x80) ? "dis" : " en",
+			(c1&0x80) ? "dis" : " en");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	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 " );
+	p += sprintf(p, "UDMA\n");
+	p += sprintf(p, "DMA\n");
+	p += sprintf(p, "PIO\n");
+
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static int amd74xx_mode5_check (struct pci_dev *dev)
+{
+	switch(dev->device) {
+		case PCI_DEVICE_ID_AMD_VIPER_7411:
+		case PCI_DEVICE_ID_AMD_VIPER_7441:
+		case PCI_DEVICE_ID_AMD_8111_IDE:
+			return 1;
+		default:
+			return 0;
+	}
+}
+
+static unsigned int amd74xx_swdma_check (struct pci_dev *dev)
+{
+	unsigned int class_rev;
+
+	if (amd74xx_mode5_check(dev))
+		return 1;
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+	return ((int) (class_rev >= 7) ? 1 : 0);
+}
+
+static u8 amd74xx_ratemask (ide_drive_t *drive)
+{
+	u8 mode;
+
+        switch(HWIF(drive)->pci_dev->device) {
+		case PCI_DEVICE_ID_AMD_8111_IDE:
+		case PCI_DEVICE_ID_AMD_VIPER_7441:
+		case PCI_DEVICE_ID_AMD_VIPER_7411:
+			mode = 3;
+			break;
+		case PCI_DEVICE_ID_AMD_VIPER_7409:
+			mode = 2;
+			break;
+		case PCI_DEVICE_ID_AMD_COBRA_7401:
+			return 1;
+		default:
+			return 0;
+	}
+
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+
+	return mode;
+}
+
+/*
+ * Here is where all the hard work goes to program the chipset.
+ */
+static int amd74xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	u8 drive_pci[]		= { 0x53, 0x52, 0x51, 0x50 };
+	u8 drive_pci2[]		= { 0x4b, 0x4a, 0x49, 0x48 };
+#if 0
+	u8 ultra_rate[]		= { 0x42, 0x41, 0x40, 0x44, 0x45, 0x46 };
+	u8 mwdma_rate[]		= { 0x77, 0x21, 0x20 };
+	u8 swdma_rate[]		= { 0xA8, 0x65, 0x42 };
+	u8 pio_rate[]		= { 0xA8, 0x65, 0x42, 0x22, 0x20};
+#endif
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed	= ide_rate_filter(amd74xx_ratemask(drive), xferspeed);
+	u8 ultra_timing	= 0, dma_pio_timing = 0, pio_timing = 0;
+
+	pci_read_config_byte(dev, drive_pci[drive->dn], &ultra_timing);
+	pci_read_config_byte(dev, drive_pci2[drive->dn], &dma_pio_timing);
+	pci_read_config_byte(dev, 0x4c, &pio_timing);
+
+	ultra_timing	&= ~0xC7;
+	dma_pio_timing	&= ~0xFF;
+	pio_timing	&= ~(0x03 << drive->dn);
+
+	switch(speed) {
+		case XFER_UDMA_7:
+		case XFER_UDMA_6:
+			speed = XFER_UDMA_5;
+		case XFER_UDMA_5:
+			ultra_timing |= 0x46;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_4:
+			ultra_timing |= 0x45;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_3:
+			ultra_timing |= 0x44;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_2:
+			ultra_timing |= 0x40;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_1:
+			ultra_timing |= 0x41;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_0:
+			ultra_timing |= 0x42;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_MW_DMA_2:
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_MW_DMA_1:
+			dma_pio_timing |= 0x21;
+			break;
+		case XFER_MW_DMA_0:
+			dma_pio_timing |= 0x77;
+			break;
+		case XFER_SW_DMA_2:
+			dma_pio_timing |= 0x42;
+			break;
+		case XFER_SW_DMA_1:
+			dma_pio_timing |= 0x65;
+			break;
+		case XFER_SW_DMA_0:
+			dma_pio_timing |= 0xA8;
+			break;
+		case XFER_PIO_4:
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_PIO_3:
+			dma_pio_timing |= 0x22;
+			break;
+		case XFER_PIO_2:
+			dma_pio_timing |= 0x42;
+			break;
+		case XFER_PIO_1:
+			dma_pio_timing |= 0x65;
+			break;
+		case XFER_PIO_0:
+		default:
+			dma_pio_timing |= 0xA8;
+			break;
+        }
+
+	pio_timing |= (0x03 << drive->dn);
+
+	pci_write_config_byte(dev, drive_pci[drive->dn], ultra_timing);
+	pci_write_config_byte(dev, drive_pci2[drive->dn], dma_pio_timing);
+	pci_write_config_byte(dev, 0x4c, pio_timing);
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static void amd74xx_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	(void) amd74xx_tune_chipset(drive, (XFER_PIO_0 + pio));
+}
+
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, amd74xx_ratemask(drive));
+
+	if (!(speed))
+		return 0;
+
+	(void) amd74xx_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int amd74xx_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		amd74xx_tune_drive(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static unsigned int __init init_chipset_amd74xx (struct pci_dev *dev, const char *name)
+{
+	if (!amd74xx_swdma_check(dev))
+		printk("%s: disabling single-word DMA support (revision < C4)\n", name);
+
+#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!amd74xx_proc) {
+		amd74xx_proc = 1;
+		bmide_dev = dev;
+		ide_pci_register_host_proc(&amd74xx_procs[0]);
+	}
+#endif /* DISPLAY_VIPER_TIMINGS && CONFIG_PROC_FS */
+
+	return 0;
+}
+
+static unsigned int __init ata66_amd74xx (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 cable_80_pin[2]	= { 0, 0 };
+	u8 ata66		= 0;
+	u8 tmpbyte;
+
+	/*
+	 * Ultra66 cable detection (from Host View)
+	 * 7411, 7441, 0x42, bit0: primary, bit2: secondary 80 pin
+	 */
+	pci_read_config_byte(dev, 0x42, &tmpbyte);
+
+	/*
+	 * 0x42, bit0 is 1 => primary channel
+	 * has 80-pin (from host view)
+	 */
+	if (tmpbyte & 0x01) cable_80_pin[0] = 1;
+
+	/*
+	 * 0x42, bit2 is 1 => secondary channel
+	 * has 80-pin (from host view)
+	 */
+	if (tmpbyte & 0x04) cable_80_pin[1] = 1;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_AMD_COBRA_7401:
+			cable_80_pin[hwif->channel] = 0;
+			return 0;
+		case PCI_DEVICE_ID_AMD_8111_IDE:
+		case PCI_DEVICE_ID_AMD_VIPER_7441:
+		case PCI_DEVICE_ID_AMD_VIPER_7411:
+			ata66 = (hwif->channel) ?
+				cable_80_pin[1] :
+				cable_80_pin[0];
+		default:
+			break;
+	}
+	return (unsigned int) ata66;
+}
+
+static void __init init_hwif_amd74xx (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->tuneproc = &amd74xx_tune_drive;
+	hwif->speedproc = &amd74xx_tune_chipset;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x07;
+	if (amd74xx_swdma_check(hwif->pci_dev))
+		hwif->swdma_mask = 0x07;
+
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66_amd74xx(hwif);
+	hwif->ide_dma_check = &amd74xx_config_drive_xfer_rate;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_amd74xx (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	if (!(hwif->channel))
+		hwif->OUTB(hwif->INB(dmabase+2) & 0x60, dmabase+2);
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+
+static int __devinit amd74xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &amd74xx_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id amd74xx_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7441,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, 	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "AMD IDE",
+	.id_table	= amd74xx_pci_tbl,
+	.probe		= amd74xx_init_one,
+};
+
+static int amd74xx_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void amd74xx_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(amd74xx_ide_init);
+module_exit(amd74xx_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for AMD IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/amd74xx.h linux-2.4.21/drivers/ide/pci/amd74xx.h
--- linux-2.4.20/drivers/ide/pci/amd74xx.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/amd74xx.h	2002-12-18 18:58:06.000000000 +0000
@@ -0,0 +1,106 @@
+#ifndef AMD74XX_H
+#define AMD74XX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_VIPER_TIMINGS
+
+#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 amd74xx_proc;
+
+static int amd74xx_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t amd74xx_procs[] __initdata = {
+	{
+		name:		"amd74xx",
+		set:		1,
+		get_info:	amd74xx_get_info,
+		parent:		NULL,
+	},
+};
+#endif  /* defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static unsigned int init_chipset_amd74xx(struct pci_dev *, const char *);
+static void init_hwif_amd74xx(ide_hwif_t *);
+static void init_dma_amd74xx(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_AMD,
+		device:		PCI_DEVICE_ID_AMD_COBRA_7401,
+		name:		"AMD7401",
+		init_chipset:	init_chipset_amd74xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_amd74xx,
+		init_dma:	init_dma_amd74xx,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},
+		bootable:	ON_BOARD,
+		extra:		0
+	},{	/* 1 */
+		vendor:		PCI_VENDOR_ID_AMD,
+		device:		PCI_DEVICE_ID_AMD_VIPER_7409,
+		name:		"AMD7409",
+		init_chipset:	init_chipset_amd74xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_amd74xx,
+		init_dma:	init_dma_amd74xx,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},
+		bootable:	ON_BOARD,
+		extra:		0
+	},{	/* 2 */
+		vendor:		PCI_VENDOR_ID_AMD,
+		device:		PCI_DEVICE_ID_AMD_VIPER_7411,
+		name:		"AMD7411",
+		init_chipset:	init_chipset_amd74xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_amd74xx,
+		init_dma:	init_dma_amd74xx,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},
+		bootable:	ON_BOARD,
+		extra:		0
+	},{	/* 3 */
+		vendor:		PCI_VENDOR_ID_AMD,
+		device:		PCI_DEVICE_ID_AMD_OPUS_7441,
+		name:		"AMD7441",
+		init_chipset:	init_chipset_amd74xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_amd74xx,
+		init_dma:	init_dma_amd74xx,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},
+		bootable:	ON_BOARD,
+		extra:		0
+	},{	/* 4 */
+		vendor:		PCI_VENDOR_ID_AMD,
+		device:		PCI_DEVICE_ID_AMD_8111_IDE,
+		name:		"AMD8111",
+		init_chipset:	init_chipset_amd74xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_amd74xx,
+		init_dma:	init_dma_amd74xx,
+		autodma:	AUTODMA,
+		channels:	2,
+		enablebits:	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},
+		bootable:	ON_BOARD,
+		extra:		0
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* AMD74XX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cmd640.c linux-2.4.21/drivers/ide/pci/cmd640.c
--- linux-2.4.20/drivers/ide/pci/cmd640.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/cmd640.c	2002-12-18 18:58:07.000000000 +0000
@@ -0,0 +1,886 @@
+/*
+ *  linux/drivers/ide/cmd640.c		Version 1.02  Sep 01, 1996
+ *
+ *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below)
+ */
+
+/*
+ *  Original authors:	abramov@cecmow.enet.dec.com (Igor Abramov)
+ *  			mlord@pobox.com (Mark Lord)
+ *
+ *  See linux/MAINTAINERS for address of current maintainer.
+ *
+ *  This file provides support for the advanced features and bugs
+ *  of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
+ *
+ *  These chips are basically fucked by design, and getting this driver
+ *  to work on every motherboard design that uses this screwed chip seems
+ *  bloody well impossible.  However, we're still trying.
+ *
+ *  Version 0.97 worked for everybody.
+ *
+ *  User feedback is essential.  Many thanks to the beta test team:
+ *
+ *  A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com,
+ *  bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz,
+ *  chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de,
+ *  derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de,
+ *  flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net,
+ *  j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net,
+ *  kerouac@ssnet.com, meskes@informatik.rwth-aachen.de, hzoli@cs.elte.hu,
+ *  peter@udgaard.isgtec.com, phil@tazenda.demon.co.uk, roadcapw@cfw.com,
+ *  s0033las@sun10.vsz.bme.hu, schaffer@tam.cornell.edu, sjd@slip.net,
+ *  steve@ei.org, ulrpeg@bigcomm.gun.de, ism@tardis.ed.ac.uk, mack@cray.com
+ *  liug@mama.indstate.edu, and others.
+ *
+ *  Version 0.01	Initial version, hacked out of ide.c,
+ *			and #include'd rather than compiled separately.
+ *			This will get cleaned up in a subsequent release.
+ *
+ *  Version 0.02	Fixes for vlb initialization code, enable prefetch
+ *			for versions 'B' and 'C' of chip by default,
+ *			some code cleanup.
+ *
+ *  Version 0.03	Added reset of secondary interface,
+ *			and black list for devices which are not compatible
+ *			with prefetch mode. Separate function for setting
+ *			prefetch is added, possibly it will be called some
+ *			day from ioctl processing code.
+ *
+ *  Version 0.04	Now configs/compiles separate from ide.c
+ *
+ *  Version 0.05	Major rewrite of interface timing code.
+ *			Added new function cmd640_set_mode to set PIO mode
+ *			from ioctl call. New drives added to black list.
+ *
+ *  Version 0.06	More code cleanup. Prefetch is enabled only for
+ *			detected hard drives, not included in prefetch
+ *			black list.
+ *
+ *  Version 0.07	Changed to more conservative drive tuning policy.
+ *			Unknown drives, which report PIO < 4 are set to
+ *			(reported_PIO - 1) if it is supported, or to PIO0.
+ *			List of known drives extended by info provided by
+ *			CMD at their ftp site.
+ *
+ *  Version 0.08	Added autotune/noautotune support.
+ *
+ *  Version 0.09	Try to be smarter about 2nd port enabling.
+ *  Version 0.10	Be nice and don't reset 2nd port.
+ *  Version 0.11	Try to handle more weird situations.
+ *
+ *  Version 0.12	Lots of bug fixes from Laszlo Peter
+ *			irq unmasking disabled for reliability.
+ *			try to be even smarter about the second port.
+ *			tidy up source code formatting.
+ *  Version 0.13	permit irq unmasking again.
+ *  Version 0.90	massive code cleanup, some bugs fixed.
+ *			defaults all drives to PIO mode0, prefetch off.
+ *			autotune is OFF by default, with compile time flag.
+ *			prefetch can be turned OFF/ON using "hdparm -p8/-p9"
+ *			 (requires hdparm-3.1 or newer)
+ *  Version 0.91	first release to linux-kernel list.
+ *  Version 0.92	move initial reg dump to separate callable function
+ *			change "readahead" to "prefetch" to avoid confusion
+ *  Version 0.95	respect original BIOS timings unless autotuning.
+ *			tons of code cleanup and rearrangement.
+ *			added CONFIG_BLK_DEV_CMD640_ENHANCED option
+ *			prevent use of unmask when prefetch is on
+ *  Version 0.96	prevent use of io_32bit when prefetch is off
+ *  Version 0.97	fix VLB secondary interface for sjd@slip.net
+ *			other minor tune-ups:  0.96 was very good.
+ *  Version 0.98	ignore PCI version when disabled by BIOS
+ *  Version 0.99	display setup/active/recovery clocks with PIO mode
+ *  Version 1.00	Mmm.. cannot depend on PCMD_ENA in all systems
+ *  Version 1.01	slow/fast devsel can be selected with "hdparm -p6/-p7"
+ *			 ("fast" is necessary for 32bit I/O in some systems)
+ *  Version 1.02	fix bug that resulted in slow "setup times"
+ *			 (patch courtesy of Zoltan Hidvegi)
+ */
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+#define CMD640_PREFETCH_MASKS 1
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+
+/*
+ * This flag is set in ide.c by the parameter:  ide0=cmd640_vlb
+ */
+int cmd640_vlb = 0;
+
+/*
+ * CMD640 specific registers definition.
+ */
+
+#define VID		0x00
+#define DID		0x02
+#define PCMD		0x04
+#define   PCMD_ENA	0x01
+#define PSTTS		0x06
+#define REVID		0x08
+#define PROGIF		0x09
+#define SUBCL		0x0a
+#define BASCL		0x0b
+#define BaseA0		0x10
+#define BaseA1		0x14
+#define BaseA2		0x18
+#define BaseA3		0x1c
+#define INTLINE		0x3c
+#define INPINE		0x3d
+
+#define	CFR		0x50
+#define   CFR_DEVREV		0x03
+#define   CFR_IDE01INTR		0x04
+#define	  CFR_DEVID		0x18
+#define	  CFR_AT_VESA_078h	0x20
+#define	  CFR_DSA1		0x40
+#define	  CFR_DSA0		0x80
+
+#define CNTRL		0x51
+#define	  CNTRL_DIS_RA0		0x40
+#define   CNTRL_DIS_RA1		0x80
+#define	  CNTRL_ENA_2ND		0x08
+
+#define	CMDTIM		0x52
+#define	ARTTIM0		0x53
+#define	DRWTIM0		0x54
+#define ARTTIM1 	0x55
+#define DRWTIM1		0x56
+#define ARTTIM23	0x57
+#define   ARTTIM23_DIS_RA2	0x04
+#define   ARTTIM23_DIS_RA3	0x08
+#define DRWTIM23	0x58
+#define BRST		0x59
+
+/*
+ * Registers and masks for easy access by drive index:
+ */
+static u8 prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
+static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
+
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+
+static u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
+static u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23};
+
+/*
+ * Current cmd640 timing values for each drive.
+ * The defaults for each are the slowest possible timings.
+ */
+static u8 setup_counts[4]    = {4, 4, 4, 4};     /* Address setup count (in clocks) */
+static u8 active_counts[4]   = {16, 16, 16, 16}; /* Active count   (encoded) */
+static u8 recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */
+
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+/*
+ * These are initialized to point at the devices we control
+ */
+static ide_hwif_t  *cmd_hwif0, *cmd_hwif1;
+static ide_drive_t *cmd_drives[4];
+
+/*
+ * Interface to access cmd640x registers
+ */
+static unsigned int cmd640_key;
+static void (*put_cmd640_reg)(u16 reg, u8 val);
+static u8 (*get_cmd640_reg)(u16 reg);
+
+/*
+ * This is read from the CFR reg, and is used in several places.
+ */
+static unsigned int cmd640_chip_version;
+
+/*
+ * The CMD640x chip does not support DWORD config write cycles, but some
+ * of the BIOSes use them to implement the config services.
+ * Therefore, we must use direct IO instead.
+ */
+
+/* PCI method 1 access */
+
+static void put_cmd640_reg_pci1 (u16 reg, u8 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb_p((reg & 0xfc) | cmd640_key, 0xcf8);
+	outb_p(val, (reg & 3) | 0xcfc);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+static u8 get_cmd640_reg_pci1 (u16 reg)
+{
+	u8 b;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb_p((reg & 0xfc) | cmd640_key, 0xcf8);
+	b = inb_p((reg & 3) | 0xcfc);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return b;
+}
+
+/* PCI method 2 access (from CMD datasheet) */
+
+static void put_cmd640_reg_pci2 (u16 reg, u8 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb_p(0x10, 0xcf8);
+	outb_p(val, cmd640_key + reg);
+	outb_p(0, 0xcf8);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+static u8 get_cmd640_reg_pci2 (u16 reg)
+{
+	u8 b;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb_p(0x10, 0xcf8);
+	b = inb_p(cmd640_key + reg);
+	outb_p(0, 0xcf8);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return b;
+}
+
+/* VLB access */
+
+static void put_cmd640_reg_vlb (u16 reg, u8 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb_p(reg, cmd640_key);
+	outb_p(val, cmd640_key + 4);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+static u8 get_cmd640_reg_vlb (u16 reg)
+{
+	u8 b;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb_p(reg, cmd640_key);
+	b = inb_p(cmd640_key + 4);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return b;
+}
+
+static int __init match_pci_cmd640_device (void)
+{
+	const u8 ven_dev[4] = {0x95, 0x10, 0x40, 0x06};
+	unsigned int i;
+	for (i = 0; i < 4; i++) {
+		if (get_cmd640_reg(i) != ven_dev[i])
+			return 0;
+	}
+#ifdef STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT
+	if ((get_cmd640_reg(PCMD) & PCMD_ENA) == 0) {
+		printk("ide: cmd640 on PCI disabled by BIOS\n");
+		return 0;
+	}
+#endif /* STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT */
+	return 1; /* success */
+}
+
+/*
+ * Probe for CMD640x -- pci method 1
+ */
+static int __init probe_for_cmd640_pci1 (void)
+{
+	get_cmd640_reg = get_cmd640_reg_pci1;
+	put_cmd640_reg = put_cmd640_reg_pci1;
+	for (cmd640_key = 0x80000000;
+	     cmd640_key <= 0x8000f800;
+	     cmd640_key += 0x800) {
+		if (match_pci_cmd640_device())
+			return 1; /* success */
+	}
+	return 0;
+}
+
+/*
+ * Probe for CMD640x -- pci method 2
+ */
+static int __init probe_for_cmd640_pci2 (void)
+{
+	get_cmd640_reg = get_cmd640_reg_pci2;
+	put_cmd640_reg = put_cmd640_reg_pci2;
+	for (cmd640_key = 0xc000; cmd640_key <= 0xcf00; cmd640_key += 0x100) {
+		if (match_pci_cmd640_device())
+			return 1; /* success */
+	}
+	return 0;
+}
+
+/*
+ * Probe for CMD640x -- vlb
+ */
+static int __init probe_for_cmd640_vlb (void)
+{
+	u8 b;
+
+	get_cmd640_reg = get_cmd640_reg_vlb;
+	put_cmd640_reg = put_cmd640_reg_vlb;
+	cmd640_key = 0x178;
+	b = get_cmd640_reg(CFR);
+	if (b == 0xff || b == 0x00 || (b & CFR_AT_VESA_078h)) {
+		cmd640_key = 0x78;
+		b = get_cmd640_reg(CFR);
+		if (b == 0xff || b == 0x00 || !(b & CFR_AT_VESA_078h))
+			return 0;
+	}
+	return 1; /* success */
+}
+
+/*
+ *  Returns 1 if an IDE interface/drive exists at 0x170,
+ *  Returns 0 otherwise.
+ */
+static int __init secondary_port_responding (void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+
+	outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET);	/* select drive0 */
+	udelay(100);
+	if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x0a) {
+		outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */
+		udelay(100);
+		if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) {
+			spin_unlock_irqrestore(&ide_lock, flags);
+			return 0; /* nothing responded */
+		}
+	}
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return 1; /* success */
+}
+
+#ifdef CMD640_DUMP_REGS
+/*
+ * Dump out all cmd640 registers.  May be called from ide.c
+ */
+static void cmd640_dump_regs (void)
+{
+	unsigned int reg = cmd640_vlb ? 0x50 : 0x00;
+
+	/* Dump current state of chip registers */
+	printk("ide: cmd640 internal register dump:");
+	for (; reg <= 0x59; reg++) {
+		if (!(reg & 0x0f))
+			printk("\n%04x:", reg);
+		printk(" %02x", get_cmd640_reg(reg));
+	}
+	printk("\n");
+}
+#endif
+
+/*
+ * Check whether prefetch is on for a drive,
+ * and initialize the unmask flags for safe operation.
+ */
+static void __init check_prefetch (unsigned int index)
+{
+	ide_drive_t *drive = cmd_drives[index];
+	u8 b = get_cmd640_reg(prefetch_regs[index]);
+
+	if (b & prefetch_masks[index]) {	/* is prefetch off? */
+		drive->no_unmask = 0;
+		drive->no_io_32bit = 1;
+		drive->io_32bit = 0;
+	} else {
+#if CMD640_PREFETCH_MASKS
+		drive->no_unmask = 1;
+		drive->unmask = 0;
+#endif
+		drive->no_io_32bit = 0;
+	}
+}
+
+/*
+ * Figure out which devices we control
+ */
+static void __init setup_device_ptrs (void)
+{
+	unsigned int i;
+
+	cmd_hwif0 = &ide_hwifs[0]; /* default, if not found below */
+	cmd_hwif1 = &ide_hwifs[1]; /* default, if not found below */
+	for (i = 0; i < MAX_HWIFS; i++) {
+		ide_hwif_t *hwif = &ide_hwifs[i];
+		if (hwif->chipset == ide_unknown || hwif->chipset == ide_generic) {
+			if (hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0)
+				cmd_hwif0 = hwif;
+			else if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
+				cmd_hwif1 = hwif;
+		}
+	}
+	cmd_drives[0] = &cmd_hwif0->drives[0];
+	cmd_drives[1] = &cmd_hwif0->drives[1];
+	cmd_drives[2] = &cmd_hwif1->drives[0];
+	cmd_drives[3] = &cmd_hwif1->drives[1];
+}
+
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+
+/*
+ * Sets prefetch mode for a drive.
+ */
+static void set_prefetch_mode (unsigned int index, int mode)
+{
+	ide_drive_t *drive = cmd_drives[index];
+	int reg = prefetch_regs[index];
+	u8 b;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	b = get_cmd640_reg(reg);
+	if (mode) {	/* want prefetch on? */
+#if CMD640_PREFETCH_MASKS
+		drive->no_unmask = 1;
+		drive->unmask = 0;
+#endif
+		drive->no_io_32bit = 0;
+		b &= ~prefetch_masks[index];	/* enable prefetch */
+	} else {
+		drive->no_unmask = 0;
+		drive->no_io_32bit = 1;
+		drive->io_32bit = 0;
+		b |= prefetch_masks[index];	/* disable prefetch */
+	}
+	put_cmd640_reg(reg, b);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/*
+ * Dump out current drive clocks settings
+ */
+static void display_clocks (unsigned int index)
+{
+	u8 active_count, recovery_count;
+
+	active_count = active_counts[index];
+	if (active_count == 1)
+		++active_count;
+	recovery_count = recovery_counts[index];
+	if (active_count > 3 && recovery_count == 1)
+		++recovery_count;
+	if (cmd640_chip_version > 1)
+		recovery_count += 1;  /* cmd640b uses (count + 1)*/
+	printk(", clocks=%d/%d/%d\n", setup_counts[index], active_count, recovery_count);
+}
+
+/*
+ * Pack active and recovery counts into single byte representation
+ * used by controller
+ */
+inline static u8 pack_nibbles (u8 upper, u8 lower)
+{
+	return ((upper & 0x0f) << 4) | (lower & 0x0f);
+}
+
+/*
+ * This routine retrieves the initial drive timings from the chipset.
+ */
+static void __init retrieve_drive_counts (unsigned int index)
+{
+	u8 b;
+
+	/*
+	 * Get the internal setup timing, and convert to clock count
+	 */
+	b = get_cmd640_reg(arttim_regs[index]) & ~0x3f;
+	switch (b) {
+		case 0x00: b = 4; break;
+		case 0x80: b = 3; break;
+		case 0x40: b = 2; break;
+		default:   b = 5; break;
+	}
+	setup_counts[index] = b;
+
+	/*
+	 * Get the active/recovery counts
+	 */
+	b = get_cmd640_reg(drwtim_regs[index]);
+	active_counts[index]   = (b >> 4)   ? (b >> 4)   : 0x10;
+	recovery_counts[index] = (b & 0x0f) ? (b & 0x0f) : 0x10;
+}
+
+
+/*
+ * This routine writes the prepared setup/active/recovery counts
+ * for a drive into the cmd640 chipset registers to active them.
+ */
+static void program_drive_counts (unsigned int index)
+{
+	unsigned long flags;
+	u8 setup_count    = setup_counts[index];
+	u8 active_count   = active_counts[index];
+	u8 recovery_count = recovery_counts[index];
+
+	/*
+	 * Set up address setup count and drive read/write timing registers.
+	 * Primary interface has individual count/timing registers for
+	 * each drive.  Secondary interface has one common set of registers,
+	 * so we merge the timings, using the slowest value for each timing.
+	 */
+	if (index > 1) {
+		unsigned int mate;
+		if (cmd_drives[mate = index ^ 1]->present) {
+			if (setup_count < setup_counts[mate])
+				setup_count = setup_counts[mate];
+			if (active_count < active_counts[mate])
+				active_count = active_counts[mate];
+			if (recovery_count < recovery_counts[mate])
+				recovery_count = recovery_counts[mate];
+		}
+	}
+
+	/*
+	 * Convert setup_count to internal chipset representation
+	 */
+	switch (setup_count) {
+		case 4:	 setup_count = 0x00; break;
+		case 3:	 setup_count = 0x80; break;
+		case 1:
+		case 2:	 setup_count = 0x40; break;
+		default: setup_count = 0xc0; /* case 5 */
+	}
+
+	/*
+	 * Now that everything is ready, program the new timings
+	 */
+	spin_lock_irqsave(&ide_lock, flags);
+	/*
+	 * Program the address_setup clocks into ARTTIM reg,
+	 * and then the active/recovery counts into the DRWTIM reg
+	 * (this converts counts of 16 into counts of zero -- okay).
+	 */
+	setup_count |= get_cmd640_reg(arttim_regs[index]) & 0x3f;
+	put_cmd640_reg(arttim_regs[index], setup_count);
+	put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count));
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/*
+ * Set a specific pio_mode for a drive
+ */
+static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle_time)
+{
+	int setup_time, active_time, recovery_time, clock_time;
+	u8 setup_count, active_count, recovery_count, recovery_count2, cycle_count;
+	int bus_speed = system_bus_clock();
+
+	if (pio_mode > 5)
+		pio_mode = 5;
+	setup_time  = ide_pio_timings[pio_mode].setup_time;
+	active_time = ide_pio_timings[pio_mode].active_time;
+	recovery_time = cycle_time - (setup_time + active_time);
+	clock_time = 1000 / bus_speed;
+	cycle_count = (cycle_time + clock_time - 1) / clock_time;
+
+	setup_count = (setup_time + clock_time - 1) / clock_time;
+
+	active_count = (active_time + clock_time - 1) / clock_time;
+	if (active_count < 2)
+		active_count = 2; /* minimum allowed by cmd640 */
+
+	recovery_count = (recovery_time + clock_time - 1) / clock_time;
+	recovery_count2 = cycle_count - (setup_count + active_count);
+	if (recovery_count2 > recovery_count)
+		recovery_count = recovery_count2;
+	if (recovery_count < 2)
+		recovery_count = 2; /* minimum allowed by cmd640 */
+	if (recovery_count > 17) {
+		active_count += recovery_count - 17;
+		recovery_count = 17;
+	}
+	if (active_count > 16)
+		active_count = 16; /* maximum allowed by cmd640 */
+	if (cmd640_chip_version > 1)
+		recovery_count -= 1;  /* cmd640b uses (count + 1)*/
+	if (recovery_count > 16)
+		recovery_count = 16; /* maximum allowed by cmd640 */
+
+	setup_counts[index]    = setup_count;
+	active_counts[index]   = active_count;
+	recovery_counts[index] = recovery_count;
+
+	/*
+	 * In a perfect world, we might set the drive pio mode here
+	 * (using WIN_SETFEATURE) before continuing.
+	 *
+	 * But we do not, because:
+	 *	1) this is the wrong place to do it (proper is do_special() in ide.c)
+	 * 	2) in practice this is rarely, if ever, necessary
+	 */
+	program_drive_counts (index);
+}
+
+/*
+ * Drive PIO mode selection:
+ */
+static void cmd640_tune_drive (ide_drive_t *drive, u8 mode_wanted)
+{
+	u8 b;
+	ide_pio_data_t  d;
+	unsigned int index = 0;
+
+	while (drive != cmd_drives[index]) {
+		if (++index > 3) {
+			printk("%s: bad news in cmd640_tune_drive\n", drive->name);
+			return;
+		}
+	}
+	switch (mode_wanted) {
+		case 6: /* set fast-devsel off */
+		case 7: /* set fast-devsel on */
+			mode_wanted &= 1;
+			b = get_cmd640_reg(CNTRL) & ~0x27;
+			if (mode_wanted)
+				b |= 0x27;
+			put_cmd640_reg(CNTRL, b);
+			printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis");
+			return;
+
+		case 8: /* set prefetch off */
+		case 9: /* set prefetch on */
+			mode_wanted &= 1;
+			set_prefetch_mode(index, mode_wanted);
+			printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");
+			return;
+	}
+
+	(void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
+	cmd640_set_mode (index, d.pio_mode, d.cycle_time);
+
+	printk ("%s: selected cmd640 PIO mode%d (%dns)%s",
+		drive->name,
+		d.pio_mode,
+		d.cycle_time,
+		d.overridden ? " (overriding vendor mode)" : "");
+	display_clocks(index);
+	return;
+}
+
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+static int pci_conf1(void)
+{
+	u32 tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb(0x01, 0xCFB);
+	tmp = inl(0xCF8);
+	outl(0x80000000, 0xCF8);
+	if (inl(0xCF8) == 0x80000000) {
+		outl(tmp, 0xCF8);
+		spin_unlock_irqrestore(&ide_lock, flags);
+		return 1;
+	}
+	outl(tmp, 0xCF8);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return 0;
+}
+
+static int pci_conf2(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb(0x00, 0xCFB);
+	outb(0x00, 0xCF8);
+	outb(0x00, 0xCFA);
+	if (inb(0xCF8) == 0x00 && inb(0xCF8) == 0x00) {
+		spin_unlock_irqrestore(&ide_lock, flags);
+		return 1;
+	}
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return 0;
+}
+
+/*
+ * Probe for a cmd640 chipset, and initialize it if found.  Called from ide.c
+ */
+int __init ide_probe_for_cmd640x (void)
+{
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+	int second_port_toggled = 0;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+	int second_port_cmd640 = 0;
+	const char *bus_type, *port2;
+	unsigned int index;
+	u8 b, cfr;
+
+	if (cmd640_vlb && probe_for_cmd640_vlb()) {
+		bus_type = "VLB";
+	} else {
+		cmd640_vlb = 0;
+		/* Find out what kind of PCI probing is supported otherwise
+		   Justin Gibbs will sulk.. */
+		if (pci_conf1() && probe_for_cmd640_pci1())
+			bus_type = "PCI (type1)";
+		else if (pci_conf2() && probe_for_cmd640_pci2())
+			bus_type = "PCI (type2)";
+		else
+			return 0;
+	}
+	/*
+	 * Undocumented magic (there is no 0x5b reg in specs)
+	 */
+	put_cmd640_reg(0x5b, 0xbd);
+	if (get_cmd640_reg(0x5b) != 0xbd) {
+		printk(KERN_ERR "ide: cmd640 init failed: wrong value in reg 0x5b\n");
+		return 0;
+	}
+	put_cmd640_reg(0x5b, 0);
+
+#ifdef CMD640_DUMP_REGS
+	CMD640_DUMP_REGS;
+#endif
+
+	/*
+	 * Documented magic begins here
+	 */
+	cfr = get_cmd640_reg(CFR);
+	cmd640_chip_version = cfr & CFR_DEVREV;
+	if (cmd640_chip_version == 0) {
+		printk ("ide: bad cmd640 revision: %d\n", cmd640_chip_version);
+		return 0;
+	}
+
+	/*
+	 * Initialize data for primary port
+	 */
+	setup_device_ptrs ();
+	printk("%s: buggy cmd640%c interface on %s, config=0x%02x\n",
+	       cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr);
+	cmd_hwif0->chipset = ide_cmd640;
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+	cmd_hwif0->tuneproc = &cmd640_tune_drive;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+	/*
+	 * Ensure compatibility by always using the slowest timings
+	 * for access to the drive's command register block,
+	 * and reset the prefetch burstsize to default (512 bytes).
+	 *
+	 * Maybe we need a way to NOT do these on *some* systems?
+	 */
+	put_cmd640_reg(CMDTIM, 0);
+	put_cmd640_reg(BRST, 0x40);
+
+	/*
+	 * Try to enable the secondary interface, if not already enabled
+	 */
+	if (cmd_hwif1->noprobe) {
+		port2 = "not probed";
+	} else {
+		b = get_cmd640_reg(CNTRL);
+		if (secondary_port_responding()) {
+			if ((b & CNTRL_ENA_2ND)) {
+				second_port_cmd640 = 1;
+				port2 = "okay";
+			} else if (cmd640_vlb) {
+				second_port_cmd640 = 1;
+				port2 = "alive";
+			} else
+				port2 = "not cmd640";
+		} else {
+			put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */
+			if (secondary_port_responding()) {
+				second_port_cmd640 = 1;
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+				second_port_toggled = 1;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+				port2 = "enabled";
+			} else {
+				put_cmd640_reg(CNTRL, b); /* restore original setting */
+				port2 = "not responding";
+			}
+		}
+	}
+
+	/*
+	 * Initialize data for secondary cmd640 port, if enabled
+	 */
+	if (second_port_cmd640) {
+		cmd_hwif0->serialized = 1;
+		cmd_hwif1->serialized = 1;
+		cmd_hwif1->chipset = ide_cmd640;
+		cmd_hwif0->mate = cmd_hwif1;
+		cmd_hwif1->mate = cmd_hwif0;
+		cmd_hwif1->channel = 1;
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+		cmd_hwif1->tuneproc = &cmd640_tune_drive;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+	}
+	printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
+		cmd_hwif0->serialized ? "" : "not ", port2);
+
+	/*
+	 * Establish initial timings/prefetch for all drives.
+	 * Do not unnecessarily disturb any prior BIOS setup of these.
+	 */
+	for (index = 0; index < (2 + (second_port_cmd640 << 1)); index++) {
+		ide_drive_t *drive = cmd_drives[index];
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+		if (drive->autotune || ((index > 1) && second_port_toggled)) {
+	 		/*
+	 		 * Reset timing to the slowest speed and turn off prefetch.
+			 * This way, the drive identify code has a better chance.
+			 */
+			setup_counts    [index] = 4;	/* max possible */
+			active_counts   [index] = 16;	/* max possible */
+			recovery_counts [index] = 16;	/* max possible */
+			program_drive_counts (index);
+			set_prefetch_mode (index, 0);
+			printk("cmd640: drive%d timings/prefetch cleared\n", index);
+		} else {
+			/*
+			 * Record timings/prefetch without changing them.
+			 * This preserves any prior BIOS setup.
+			 */
+			retrieve_drive_counts (index);
+			check_prefetch (index);
+			printk("cmd640: drive%d timings/prefetch(%s) preserved",
+				index, drive->no_io_32bit ? "off" : "on");
+			display_clocks(index);
+		}
+#else
+		/*
+		 * Set the drive unmask flags to match the prefetch setting
+		 */
+		check_prefetch (index);
+		printk("cmd640: drive%d timings/prefetch(%s) preserved\n",
+			index, drive->no_io_32bit ? "off" : "on");
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+	}
+
+#ifdef CMD640_DUMP_REGS
+	CMD640_DUMP_REGS;
+#endif
+	return 1;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cmd640.h linux-2.4.21/drivers/ide/pci/cmd640.h
--- linux-2.4.20/drivers/ide/pci/cmd640.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/cmd640.h	2002-12-18 18:58:02.000000000 +0000
@@ -0,0 +1,32 @@
+#ifndef CMD640_H
+#define CMD640_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define IDE_IGNORE      ((void *)-1)
+
+static ide_pci_device_t cmd640_chipsets[] __initdata = {
+	{
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_CMD_640,
+		.name		= "CMD640",
+		.init_setup	= NULL,
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= IDE_IGNORE,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.bootable	= EOL,
+	}
+}
+
+#endif /* CMD640_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cmd64x.c linux-2.4.21/drivers/ide/pci/cmd64x.c
--- linux-2.4.20/drivers/ide/pci/cmd64x.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/cmd64x.c	2002-12-18 18:58:06.000000000 +0000
@@ -0,0 +1,798 @@
+/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
+ *
+ * linux/drivers/ide/cmd64x.c		Version 1.30	Sept 10, 2002
+ *
+ * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
+ *           Note, this driver is not used at all on other systems because
+ *           there the "BIOS" has done all of the following already.
+ *           Due to massive hardware bugs, UltraDMA is only supported
+ *           on the 646U2 and not on the 646U.
+ *
+ * Copyright (C) 1998		Eddie C. Dost  (ecd@skynet.be)
+ * Copyright (C) 1998		David S. Miller (davem@redhat.com)
+ *
+ * Copyright (C) 1999-2002	Andre Hedrick <andre@linux-ide.org>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "cmd64x.h"
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 cmd64x_proc = 0;
+
+#define CMD_MAX_DEVS		5
+
+static struct pci_dev *cmd_devs[CMD_MAX_DEVS];
+static int n_cmd_devs;
+
+#undef DEBUG_CMD_REGS
+
+static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index)
+{
+	char *p = buf;
+
+	u8 reg53 = 0, reg54 = 0, reg55 = 0, reg56 = 0;	/* primary */
+	u8 reg57 = 0, reg58 = 0, reg5b;			/* secondary */
+	u8 reg72 = 0, reg73 = 0;			/* primary */
+	u8 reg7a = 0, reg7b = 0;			/* secondary */
+	u8 reg50 = 0, reg71 = 0;			/* extra */
+#ifdef DEBUG_CMD_REGS
+	u8 hi_byte = 0, lo_byte = 0;
+#endif /* DEBUG_CMD_REGS */
+
+	p += sprintf(p, "\nController: %d\n", index);
+	p += sprintf(p, "CMD%x Chipset.\n", dev->device);
+	(void) pci_read_config_byte(dev, CFR,       &reg50);
+	(void) pci_read_config_byte(dev, ARTTIM0,   &reg53);
+	(void) pci_read_config_byte(dev, DRWTIM0,   &reg54);
+	(void) pci_read_config_byte(dev, ARTTIM1,   &reg55);
+	(void) pci_read_config_byte(dev, DRWTIM1,   &reg56);
+	(void) pci_read_config_byte(dev, ARTTIM2,   &reg57);
+	(void) pci_read_config_byte(dev, DRWTIM2,   &reg58);
+	(void) pci_read_config_byte(dev, DRWTIM3,   &reg5b);
+	(void) pci_read_config_byte(dev, MRDMODE,   &reg71);
+	(void) pci_read_config_byte(dev, BMIDESR0,  &reg72);
+	(void) pci_read_config_byte(dev, UDIDETCR0, &reg73);
+	(void) pci_read_config_byte(dev, BMIDESR1,  &reg7a);
+	(void) pci_read_config_byte(dev, UDIDETCR1, &reg7b);
+
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled           "
+			"              %sabled\n",
+		(reg72&0x80)?"dis":" en",
+		(reg7a&0x80)?"dis":" en");
+	p += sprintf(p, "--------------- drive0 "
+		"--------- drive1 -------- drive0 "
+		"---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s"
+			"             %s               %s\n",
+		(reg72&0x20)?"yes":"no ", (reg72&0x40)?"yes":"no ",
+		(reg7a&0x20)?"yes":"no ", (reg7a&0x40)?"yes":"no ");
+
+	p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)",
+		(reg72&0x20)?((reg73&0x01)?"UDMA":" DMA"):" PIO",
+		(reg72&0x20)?(
+			((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"):
+			((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"):
+			((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"):
+			((reg73&0x00)==0x00)?(((reg73&0x05)==0x05)?"5":"2"):
+			"X"):"?",
+		(reg72&0x40)?((reg73&0x02)?"UDMA":" DMA"):" PIO",
+		(reg72&0x40)?(
+			((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"):
+			((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"):
+			((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"):
+			((reg73&0x00)==0x00)?(((reg73&0x0A)==0x0A)?"5":"2"):
+			"X"):"?");
+	p += sprintf(p, "         %s(%s)           %s(%s)\n",
+		(reg7a&0x20)?((reg7b&0x01)?"UDMA":" DMA"):" PIO",
+		(reg7a&0x20)?(
+			((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"):
+			((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"):
+			((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"):
+			((reg7b&0x00)==0x00)?(((reg7b&0x05)==0x05)?"5":"2"):
+			"X"):"?",
+		(reg7a&0x40)?((reg7b&0x02)?"UDMA":" DMA"):" PIO",
+		(reg7a&0x40)?(
+			((reg7b&0xC0)==0xC0)?(((reg7b&0xC5)==0xC5)?"3":"0"):
+			((reg7b&0x80)==0x80)?(((reg7b&0x85)==0x85)?"3":"1"):
+			((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"):
+			((reg7b&0x00)==0x00)?(((reg7b&0x0A)==0x0A)?"5":"2"):
+			"X"):"?" );
+	p += sprintf(p, "PIO Mode:       %s                %s"
+			"               %s                 %s\n",
+			"?", "?", "?", "?");
+	p += sprintf(p, "                %s                     %s\n",
+		(reg50 & CFR_INTR_CH0) ? "interrupting" : "polling     ",
+		(reg57 & ARTTIM23_INTR_CH1) ? "interrupting" : "polling");
+	p += sprintf(p, "                %s                          %s\n",
+		(reg71 & MRDMODE_INTR_CH0) ? "pending" : "clear  ",
+		(reg71 & MRDMODE_INTR_CH1) ? "pending" : "clear");
+	p += sprintf(p, "                %s                          %s\n",
+		(reg71 & MRDMODE_BLK_CH0) ? "blocked" : "enabled",
+		(reg71 & MRDMODE_BLK_CH1) ? "blocked" : "enabled");
+
+#ifdef DEBUG_CMD_REGS
+	SPLIT_BYTE(reg50, hi_byte, lo_byte);
+	p += sprintf(p, "CFR       = 0x%02x, HI = 0x%02x, "
+			"LOW = 0x%02x\n", reg50, hi_byte, lo_byte);
+	SPLIT_BYTE(reg57, hi_byte, lo_byte);
+	p += sprintf(p, "ARTTIM23  = 0x%02x, HI = 0x%02x, "
+			"LOW = 0x%02x\n", reg57, hi_byte, lo_byte);
+	SPLIT_BYTE(reg71, hi_byte, lo_byte);
+	p += sprintf(p, "MRDMODE   = 0x%02x, HI = 0x%02x, "
+			"LOW = 0x%02x\n", reg71, hi_byte, lo_byte);
+#endif /* DEBUG_CMD_REGS */
+
+	return (char *)p;
+}
+
+static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	p += sprintf(p, "\n");
+	for (i = 0; i < n_cmd_devs; i++) {
+		struct pci_dev *dev	= cmd_devs[i];
+		p = print_cmd64x_get_info(p, dev, i);
+	}
+	return p-buffer;	/* => must be less than 4k! */
+}
+
+#endif	/* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/*
+ * Registers and masks for easy access by drive index:
+ */
+#if 0
+static u8 prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
+static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
+#endif
+
+/*
+ * This routine writes the prepared setup/active/recovery counts
+ * for a drive into the cmd646 chipset registers to active them.
+ */
+static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count)
+{
+	unsigned long flags;
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	ide_drive_t *drives = HWIF(drive)->drives;
+	u8 temp_b;
+	static const u8 setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
+	static const u8 recovery_counts[] =
+		{15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
+	static const u8 arttim_regs[2][2] = {
+			{ ARTTIM0, ARTTIM1 },
+			{ ARTTIM23, ARTTIM23 }
+		};
+	static const u8 drwtim_regs[2][2] = {
+			{ DRWTIM0, DRWTIM1 },
+			{ DRWTIM2, DRWTIM3 }
+		};
+	int channel = (int) HWIF(drive)->channel;
+	int slave = (drives != drive);  /* Is this really the best way to determine this?? */
+
+	cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n",
+		setup_count, active_count, recovery_count, drive->present);
+	/*
+	 * Set up address setup count registers.
+	 * Primary interface has individual count/timing registers for
+	 * each drive.  Secondary interface has one common set of registers,
+	 * for address setup so we merge these timings, using the slowest
+	 * value.
+	 */
+	if (channel) {
+		drive->drive_data = setup_count;
+		setup_count = IDE_MAX(drives[0].drive_data,
+					drives[1].drive_data);
+		cmdprintk("Secondary interface, setup_count = %d\n",
+					setup_count);
+	}
+
+	/*
+	 * Convert values to internal chipset representation
+	 */
+	setup_count = (setup_count > 5) ? 0xc0 : (int) setup_counts[setup_count];
+	active_count &= 0xf; /* Remember, max value is 16 */
+	recovery_count = (int) recovery_counts[recovery_count];
+
+	cmdprintk("Final values = %d,%d,%d\n",
+		setup_count, active_count, recovery_count);
+
+	/*
+	 * Now that everything is ready, program the new timings
+	 */
+	local_irq_save(flags);
+	/*
+	 * Program the address_setup clocks into ARTTIM reg,
+	 * and then the active/recovery counts into the DRWTIM reg
+	 */
+	(void) pci_read_config_byte(dev, arttim_regs[channel][slave], &temp_b);
+	(void) pci_write_config_byte(dev, arttim_regs[channel][slave],
+		((u8) setup_count) | (temp_b & 0x3f));
+	(void) pci_write_config_byte(dev, drwtim_regs[channel][slave],
+		(u8) ((active_count << 4) | recovery_count));
+	cmdprintk ("Write %x to %x\n",
+		((u8) setup_count) | (temp_b & 0x3f),
+		arttim_regs[channel][slave]);
+	cmdprintk ("Write %x to %x\n",
+		(u8) ((active_count << 4) | recovery_count),
+		drwtim_regs[channel][slave]);
+	local_irq_restore(flags);
+}
+
+/*
+ * Attempts to set the interface PIO mode.
+ * The preferred method of selecting PIO modes (e.g. mode 4) is 
+ * "echo 'piomode:4' > /proc/ide/hdx/settings".  Special cases are
+ * 8: prefetch off, 9: prefetch on, 255: auto-select best mode.
+ * Called with 255 at boot time.
+ */
+
+static void cmd64x_tuneproc (ide_drive_t *drive, u8 mode_wanted)
+{
+	int setup_time, active_time, recovery_time;
+	int clock_time, pio_mode, cycle_time;
+	u8 recovery_count2, cycle_count;
+	int setup_count, active_count, recovery_count;
+	int bus_speed = system_bus_clock();
+	/*byte b;*/
+	ide_pio_data_t  d;
+
+	switch (mode_wanted) {
+		case 8: /* set prefetch off */
+		case 9: /* set prefetch on */
+			mode_wanted &= 1;
+			/*set_prefetch_mode(index, mode_wanted);*/
+			cmdprintk("%s: %sabled cmd640 prefetch\n",
+				drive->name, mode_wanted ? "en" : "dis");
+			return;
+	}
+
+	mode_wanted = ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
+	pio_mode = d.pio_mode;
+	cycle_time = d.cycle_time;
+
+	/*
+	 * I copied all this complicated stuff from cmd640.c and made a few
+	 * minor changes.  For now I am just going to pray that it is correct.
+	 */
+	if (pio_mode > 5)
+		pio_mode = 5;
+	setup_time  = ide_pio_timings[pio_mode].setup_time;
+	active_time = ide_pio_timings[pio_mode].active_time;
+	recovery_time = cycle_time - (setup_time + active_time);
+	clock_time = 1000 / bus_speed;
+	cycle_count = (cycle_time + clock_time - 1) / clock_time;
+
+	setup_count = (setup_time + clock_time - 1) / clock_time;
+
+	active_count = (active_time + clock_time - 1) / clock_time;
+
+	recovery_count = (recovery_time + clock_time - 1) / clock_time;
+	recovery_count2 = cycle_count - (setup_count + active_count);
+	if (recovery_count2 > recovery_count)
+		recovery_count = recovery_count2;
+	if (recovery_count > 16) {
+		active_count += recovery_count - 16;
+		recovery_count = 16;
+	}
+	if (active_count > 16)
+		active_count = 16; /* maximum allowed by cmd646 */
+
+	/*
+	 * In a perfect world, we might set the drive pio mode here
+	 * (using WIN_SETFEATURE) before continuing.
+	 *
+	 * But we do not, because:
+	 *	1) this is the wrong place to do it
+	 *		(proper is do_special() in ide.c)
+	 * 	2) in practice this is rarely, if ever, necessary
+	 */
+	program_drive_counts (drive, setup_count, active_count, recovery_count);
+
+	cmdprintk("%s: selected cmd646 PIO mode%d : %d (%dns)%s, "
+		"clocks=%d/%d/%d\n",
+		drive->name, pio_mode, mode_wanted, cycle_time,
+		d.overridden ? " (overriding vendor mode)" : "",
+		setup_count, active_count, recovery_count);
+}
+
+static u8 cmd64x_ratemask (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 mode = 0;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_CMD_649:
+			mode = 3;
+			break;
+		case PCI_DEVICE_ID_CMD_648:
+			mode = 2;
+			break;
+		case PCI_DEVICE_ID_CMD_643:
+			return 0;
+
+		case PCI_DEVICE_ID_CMD_646:
+		{
+			unsigned int class_rev	= 0;
+			pci_read_config_dword(dev,
+				PCI_CLASS_REVISION, &class_rev);
+			class_rev &= 0xff;
+		/*
+		 * UltraDMA only supported on PCI646U and PCI646U2, which
+		 * correspond to revisions 0x03, 0x05 and 0x07 respectively.
+		 * Actually, although the CMD tech support people won't
+		 * tell me the details, the 0x03 revision cannot support
+		 * UDMA correctly without hardware modifications, and even
+		 * then it only works with Quantum disks due to some
+		 * hold time assumptions in the 646U part which are fixed
+		 * in the 646U2.
+		 *
+		 * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
+		 */
+			switch(class_rev) {
+				case 0x07:
+				case 0x05:
+					return 1;
+				case 0x03:
+				case 0x01:
+				default:
+					return 0;
+			}
+		}
+	}
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, u8 set_speed)
+{
+	u8 speed	= 0x00;
+	u8 set_pio	= ide_get_best_pio_mode(drive, 4, 5, NULL);
+
+	cmd64x_tuneproc(drive, set_pio);
+	speed = XFER_PIO_0 + set_pio;
+	if (set_speed)
+		(void) ide_config_drive_speed(drive, speed);
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive, u8 set_speed)
+{
+	config_cmd64x_chipset_for_pio(drive, set_speed);
+}
+
+static int cmd64x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 regU = 0, pciU	= (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
+	u8 regD = 0, pciD	= (hwif->channel) ? BMIDESR1 : BMIDESR0;
+
+	u8 speed	= ide_rate_filter(cmd64x_ratemask(drive), xferspeed);
+
+	if (speed > XFER_PIO_4) {
+		(void) pci_read_config_byte(dev, pciD, &regD);
+		(void) pci_read_config_byte(dev, pciU, &regU);
+		regD &= ~(unit ? 0x40 : 0x20);
+		regU &= ~(unit ? 0xCA : 0x35);
+		(void) pci_write_config_byte(dev, pciD, regD);
+		(void) pci_write_config_byte(dev, pciU, regU);
+		(void) pci_read_config_byte(dev, pciD, &regD);
+		(void) pci_read_config_byte(dev, pciU, &regU);
+	}
+
+	switch(speed) {
+		case XFER_UDMA_5:	regU |= (unit ? 0x0A : 0x05); break;
+		case XFER_UDMA_4:	regU |= (unit ? 0x4A : 0x15); break;
+		case XFER_UDMA_3:	regU |= (unit ? 0x8A : 0x25); break;
+		case XFER_UDMA_2:	regU |= (unit ? 0x42 : 0x11); break;
+		case XFER_UDMA_1:	regU |= (unit ? 0x82 : 0x21); break;
+		case XFER_UDMA_0:	regU |= (unit ? 0xC2 : 0x31); break;
+		case XFER_MW_DMA_2:	regD |= (unit ? 0x40 : 0x10); break;
+		case XFER_MW_DMA_1:	regD |= (unit ? 0x80 : 0x20); break;
+		case XFER_MW_DMA_0:	regD |= (unit ? 0xC0 : 0x30); break;
+		case XFER_SW_DMA_2:	regD |= (unit ? 0x40 : 0x10); break;
+		case XFER_SW_DMA_1:	regD |= (unit ? 0x80 : 0x20); break;
+		case XFER_SW_DMA_0:	regD |= (unit ? 0xC0 : 0x30); break;
+		case XFER_PIO_4:	cmd64x_tuneproc(drive, 4); break;
+		case XFER_PIO_3:	cmd64x_tuneproc(drive, 3); break;
+		case XFER_PIO_2:	cmd64x_tuneproc(drive, 2); break;
+		case XFER_PIO_1:	cmd64x_tuneproc(drive, 1); break;
+		case XFER_PIO_0:	cmd64x_tuneproc(drive, 0); break;
+
+		default:
+			return 1;
+	}
+
+	if (speed > XFER_PIO_4) {
+		(void) pci_write_config_byte(dev, pciU, regU);
+		regD |= (unit ? 0x40 : 0x20);
+		(void) pci_write_config_byte(dev, pciD, regD);
+	}
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed	= ide_dma_speed(drive, cmd64x_ratemask(drive));
+
+	config_chipset_for_pio(drive, !speed);
+
+	if (!speed)
+		return 0;
+
+	if(ide_set_xfer_rate(drive, speed))
+		return 0; 
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+
+	return ide_dma_enable(drive);
+}
+
+static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	if ((id != NULL) && ((id->capability & 1) != 0) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if ((id->field_valid & 4) && cmd64x_ratemask(drive)) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		config_chipset_for_pio(drive, 1);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static int cmd64x_alt_dma_status (struct pci_dev *dev)
+{
+	switch(dev->device) {
+		case PCI_DEVICE_ID_CMD_648:
+		case PCI_DEVICE_ID_CMD_649:
+			return 1;
+		default:
+			break;
+	}
+	return 0;
+}
+
+static int cmd64x_ide_dma_end (ide_drive_t *drive)
+{
+	u8 dma_stat = 0, dma_cmd = 0;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	drive->waiting_for_dma = 0;
+	/* read DMA command state */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop DMA */
+	hwif->OUTB((dma_cmd & ~1), hwif->dma_command);
+	/* get DMA status */
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* clear the INTR & ERROR bits */
+	hwif->OUTB(dma_stat|6, hwif->dma_status);
+	if (cmd64x_alt_dma_status(dev)) {
+		u8 dma_intr	= 0;
+		u8 dma_mask	= (hwif->channel) ? ARTTIM23_INTR_CH1 :
+						    CFR_INTR_CH0;
+		u8 dma_reg	= (hwif->channel) ? ARTTIM2 : CFR;
+		(void) pci_read_config_byte(dev, dma_reg, &dma_intr);
+		/* clear the INTR bit */
+		(void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask);
+	}
+	/* purge DMA mappings */
+	ide_destroy_dmatable(drive);
+	/* verify good DMA status */
+	return (dma_stat & 7) != 4;
+}
+
+static int cmd64x_ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif		= HWIF(drive);
+	struct pci_dev *dev		= hwif->pci_dev;
+        u8 dma_alt_stat = 0, mask	= (hwif->channel) ? MRDMODE_INTR_CH1 :
+							    MRDMODE_INTR_CH0;
+	u8 dma_stat = hwif->INB(hwif->dma_status);
+
+	(void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat);
+#ifdef DEBUG
+	printk("%s: dma_stat: 0x%02x dma_alt_stat: "
+		"0x%02x mask: 0x%02x\n", drive->name,
+		dma_stat, dma_alt_stat, mask);
+#endif
+	if (!(dma_alt_stat & mask))
+		return 0;
+
+	/* return 1 if INTR asserted */
+	if ((dma_stat & 4) == 4)
+		return 1;
+
+	return 0;
+}
+
+/*
+ * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old
+ * event order for DMA transfers.
+ */
+
+static int cmd646_1_ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 dma_stat = 0, dma_cmd = 0;
+
+	drive->waiting_for_dma = 0;
+	/* get DMA status */
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* read DMA command state */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop DMA */
+	hwif->OUTB((dma_cmd & ~1), hwif->dma_command);
+	/* clear the INTR & ERROR bits */
+	hwif->OUTB(dma_stat|6, hwif->dma_status);
+	/* and free any DMA resources */
+	ide_destroy_dmatable(drive);
+	/* verify good DMA status */
+	return (dma_stat & 7) != 4;
+}
+
+static unsigned int __init init_chipset_cmd64x (struct pci_dev *dev, const char *name)
+{
+	u32 class_rev = 0;
+	u8 mrdmode = 0;
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+#ifdef __i386__
+	if (dev->resource[PCI_ROM_RESOURCE].start) {
+		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
+	}
+#endif
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_CMD_643:
+			break;
+		case PCI_DEVICE_ID_CMD_646:
+			printk("%s: chipset revision 0x%02X, ", name, class_rev);
+			switch(class_rev) {
+				case 0x07:
+				case 0x05:
+					printk("UltraDMA Capable");
+					break;
+				case 0x03:
+					printk("MultiWord DMA Force Limited");
+					break;
+				case 0x01:
+				default:
+					printk("MultiWord DMA Limited, IRQ workaround enabled");
+					break;
+				}
+			printk("\n");
+                        break;
+		case PCI_DEVICE_ID_CMD_648:
+		case PCI_DEVICE_ID_CMD_649:
+			break;
+		default:
+			break;
+	}
+
+	/* Set a good latency timer and cache line size value. */
+	(void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+#ifdef __sparc_v9__
+	(void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10);
+#endif
+
+
+	/* Setup interrupts. */
+	(void) pci_read_config_byte(dev, MRDMODE, &mrdmode);
+	mrdmode &= ~(0x30);
+	(void) pci_write_config_byte(dev, MRDMODE, mrdmode);
+
+	/* Use MEMORY READ LINE for reads.
+	 * NOTE: Although not mentioned in the PCI0646U specs,
+	 *       these bits are write only and won't be read
+	 *       back as set or not.  The PCI0646U2 specs clarify
+	 *       this point.
+	 */
+	(void) pci_write_config_byte(dev, MRDMODE, mrdmode | 0x02);
+
+	/* Set reasonable active/recovery/address-setup values. */
+	(void) pci_write_config_byte(dev, ARTTIM0,  0x40);
+	(void) pci_write_config_byte(dev, DRWTIM0,  0x3f);
+	(void) pci_write_config_byte(dev, ARTTIM1,  0x40);
+	(void) pci_write_config_byte(dev, DRWTIM1,  0x3f);
+#ifdef __i386__
+	(void) pci_write_config_byte(dev, ARTTIM23, 0x1c);
+#else
+	(void) pci_write_config_byte(dev, ARTTIM23, 0x5c);
+#endif
+	(void) pci_write_config_byte(dev, DRWTIM23, 0x3f);
+	(void) pci_write_config_byte(dev, DRWTIM3,  0x3f);
+#ifdef CONFIG_PPC
+	(void) pci_write_config_byte(dev, UDIDETCR0, 0xf0);
+#endif /* CONFIG_PPC */
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+
+	cmd_devs[n_cmd_devs++] = dev;
+
+	if (!cmd64x_proc) {
+		cmd64x_proc = 1;
+		ide_pci_register_host_proc(&cmd64x_procs[0]);
+	}
+#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
+
+	return 0;
+}
+
+static unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
+{
+	u8 ata66 = 0, mask = (hwif->channel) ? 0x02 : 0x01;
+
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_CMD_643:
+		case PCI_DEVICE_ID_CMD_646:
+			return ata66;
+		default:
+			break;
+	}
+	pci_read_config_byte(hwif->pci_dev, BMIDECSR, &ata66);
+	return (ata66 & mask) ? 1 : 0;
+}
+
+static void __init init_hwif_cmd64x (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned int class_rev;
+
+	hwif->autodma = 0;
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+	hwif->tuneproc  = &cmd64x_tuneproc;
+	hwif->speedproc = &cmd64x_tune_chipset;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+
+	hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (dev->device == PCI_DEVICE_ID_CMD_643)
+		hwif->ultra_mask = 0x80;
+	if (dev->device == PCI_DEVICE_ID_CMD_646)
+		hwif->ultra_mask = (class_rev > 0x04) ? 0x07 : 0x80;
+	if (dev->device == PCI_DEVICE_ID_CMD_648)
+		hwif->ultra_mask = 0x1f;
+
+	hwif->ide_dma_check = &cmd64x_config_drive_for_dma;
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66_cmd64x(hwif);
+
+	if (dev->device == PCI_DEVICE_ID_CMD_646) {
+		hwif->chipset = ide_cmd646;
+		if (class_rev == 0x01) {
+			hwif->ide_dma_end = &cmd646_1_ide_dma_end;
+		} else {
+			hwif->ide_dma_end = &cmd64x_ide_dma_end;
+			hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq;
+		}
+	} else {
+		hwif->ide_dma_end = &cmd64x_ide_dma_end;
+		hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq;
+	}
+
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_cmd64x (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &cmd64x_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id cmd64x_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "CMD64x IDE",
+	.id_table	= cmd64x_pci_tbl,
+	.probe		= cmd64x_init_one,
+};
+
+static int cmd64x_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void cmd64x_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(cmd64x_ide_init);
+module_exit(cmd64x_ide_exit);
+
+MODULE_AUTHOR("Eddie Dost, David Miller, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for CMD64x IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cmd64x.h linux-2.4.21/drivers/ide/pci/cmd64x.h
--- linux-2.4.20/drivers/ide/pci/cmd64x.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/cmd64x.h	2002-12-18 18:58:06.000000000 +0000
@@ -0,0 +1,147 @@
+#ifndef CMD64X_H
+#define CMD64X_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_CMD64X_TIMINGS
+
+#define CMD_DEBUG 0
+
+#if CMD_DEBUG
+#define cmdprintk(x...)	printk(x)
+#else
+#define cmdprintk(x...)
+#endif
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+/*
+ * CMD64x specific registers definition.
+ */
+#define CFR		0x50
+#define   CFR_INTR_CH0		0x02
+#define CNTRL		0x51
+#define	  CNTRL_DIS_RA0		0x40
+#define   CNTRL_DIS_RA1		0x80
+#define	  CNTRL_ENA_2ND		0x08
+
+#define	CMDTIM		0x52
+#define	ARTTIM0		0x53
+#define	DRWTIM0		0x54
+#define ARTTIM1 	0x55
+#define DRWTIM1		0x56
+#define ARTTIM23	0x57
+#define   ARTTIM23_DIS_RA2	0x04
+#define   ARTTIM23_DIS_RA3	0x08
+#define   ARTTIM23_INTR_CH1	0x10
+#define ARTTIM2		0x57
+#define ARTTIM3		0x57
+#define DRWTIM23	0x58
+#define DRWTIM2		0x58
+#define BRST		0x59
+#define DRWTIM3		0x5b
+
+#define BMIDECR0	0x70
+#define MRDMODE		0x71
+#define   MRDMODE_INTR_CH0	0x04
+#define   MRDMODE_INTR_CH1	0x08
+#define   MRDMODE_BLK_CH0	0x10
+#define   MRDMODE_BLK_CH1	0x20
+#define BMIDESR0	0x72
+#define UDIDETCR0	0x73
+#define DTPR0		0x74
+#define BMIDECR1	0x78
+#define BMIDECSR	0x79
+#define BMIDESR1	0x7A
+#define UDIDETCR1	0x7B
+#define DTPR1		0x7C
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 cmd64x_proc;
+
+static char * print_cmd64x_get_info(char *, struct pci_dev *, int);
+static int cmd64x_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t cmd64x_procs[] __initdata = {
+	{
+		.name		= "cmd64x",
+		.set		= 1,
+		.get_info	= cmd64x_get_info,
+		.parent		= NULL,
+	},
+};
+#endif  /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static unsigned int init_chipset_cmd64x(struct pci_dev *, const char *);
+static void init_hwif_cmd64x(ide_hwif_t *);
+static void init_dma_cmd64x(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t cmd64x_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_CMD_643,
+		.name		= "CMD643",
+		.init_chipset	= init_chipset_cmd64x,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_cmd64x,
+		.init_dma	= init_dma_cmd64x,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_CMD_646,
+		.name		= "CMD646",
+		.init_chipset	= init_chipset_cmd64x,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_cmd64x,
+		.init_dma	= init_dma_cmd64x,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x51,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device	= PCI_DEVICE_ID_CMD_648,
+		.name		= "CMD648",
+		.init_chipset	= init_chipset_cmd64x,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_cmd64x,
+		.init_dma	= init_dma_cmd64x,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_CMD_649,
+		.name		= "CMD649",
+		.init_chipset	= init_chipset_cmd64x,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_cmd64x,
+		.init_dma	= init_dma_cmd64x,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 2,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* CMD64X_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cs5530.c linux-2.4.21/drivers/ide/pci/cs5530.c
--- linux-2.4.20/drivers/ide/pci/cs5530.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/cs5530.c	2002-12-18 18:58:10.000000000 +0000
@@ -0,0 +1,460 @@
+/*
+ * linux/drivers/ide/cs5530.c		Version 0.7	Sept 10, 2002
+ *
+ * Copyright (C) 2000			Andre Hedrick <andre@linux-ide.org>
+ * Ditto of GNU General Public License.
+ *
+ * Copyright (C) 2000			Mark Lord <mlord@pobox.com>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * Development of this chipset driver was funded
+ * by the nice folks at National Semiconductor.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "cs5530.h"
+
+#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 cs5530_proc = 0;
+
+static struct pci_dev *bmide_dev;
+
+static int cs5530_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	unsigned long bibma = pci_resource_start(bmide_dev, 4);
+	u8  c0 = 0, c1 = 0;
+
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte registers
+	 * to investigate:
+	 */
+
+	c0 = inb_p((u16)bibma + 0x02);
+	c1 = inb_p((u16)bibma + 0x0a);
+
+	p += sprintf(p, "\n                                "
+			"Cyrix 5530 Chipset.\n");
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled "
+			"                        %sabled\n",
+			(c0&0x80) ? "dis" : " en",
+			(c1&0x80) ? "dis" : " en");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	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 " );
+
+	p += sprintf(p, "UDMA\n");
+	p += sprintf(p, "DMA\n");
+	p += sprintf(p, "PIO\n");
+
+	return p-buffer;
+}
+#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
+
+/**
+ *	cs5530_xfer_set_mode	-	set a new transfer mode at the drive
+ *	@drive: drive to tune
+ *	@mode: new mode
+ *
+ *	Logging wrapper to the IDE driver speed configuration. This can
+ *	probably go away now.
+ */
+ 
+static int cs5530_set_xfer_mode (ide_drive_t *drive, u8 mode)
+{
+	printk(KERN_DEBUG "%s: cs5530_set_xfer_mode(%s)\n",
+		drive->name, ide_xfer_verbose(mode));
+	return (ide_config_drive_speed(drive, mode));
+}
+
+/*
+ * Here are the standard PIO mode 0-4 timings for each "format".
+ * Format-0 uses fast data reg timings, with slower command reg timings.
+ * Format-1 uses fast timings for all registers, but won't work with all drives.
+ */
+static unsigned int cs5530_pio_timings[2][5] = {
+	{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},
+	{0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}
+};
+
+/*
+ * After chip reset, the PIO timings are set to 0x0000e132, which is not valid.
+ */
+#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132)
+#define CS5530_BASEREG(hwif)	(((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20))
+
+/**
+ *	cs5530_tuneproc		-	select/set PIO modes
+ *
+ *	cs5530_tuneproc() handles selection/setting of PIO modes
+ *	for both the chipset and drive.
+ *
+ *	The ide_init_cs5530() routine guarantees that all drives
+ *	will have valid default PIO timings set up before we get here.
+ */
+
+static void cs5530_tuneproc (ide_drive_t *drive, u8 pio)	/* pio=255 means "autotune" */
+{
+	ide_hwif_t	*hwif = HWIF(drive);
+	unsigned int	format;
+	unsigned long basereg = CS5530_BASEREG(hwif);
+	static u8	modes[5] = { XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4};
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	if (!cs5530_set_xfer_mode(drive, modes[pio])) {
+		format = (hwif->INL(basereg+4) >> 31) & 1;
+		hwif->OUTL(cs5530_pio_timings[format][pio],
+			basereg+(drive->select.b.unit<<3));
+	}
+}
+
+/**
+ *	cs5530_config_dma	-	select/set DMA and UDMA modes
+ *	@drive: drive to tune
+ *
+ *	cs5530_config_dma() handles selection/setting of DMA/UDMA modes
+ *	for both the chipset and drive. The CS5530 has limitations about
+ *	mixing DMA/UDMA on the same cable.
+ */
+ 
+static int cs5530_config_dma (ide_drive_t *drive)
+{
+	int			udma_ok = 1, mode = 0;
+	ide_hwif_t		*hwif = HWIF(drive);
+	int			unit = drive->select.b.unit;
+	ide_drive_t		*mate = &hwif->drives[unit^1];
+	struct hd_driveid	*id = drive->id;
+	unsigned int		reg, timings;
+	unsigned long		basereg;
+
+	/*
+	 * Default to DMA-off in case we run into trouble here.
+	 */
+	hwif->ide_dma_off_quietly(drive);
+	/* turn off DMA while we fiddle */
+	hwif->ide_dma_host_off(drive);
+	/* clear DMA_capable bit */
+
+	/*
+	 * The CS5530 specifies that two drives sharing a cable cannot
+	 * mix UDMA/MDMA.  It has to be one or the other, for the pair,
+	 * though different timings can still be chosen for each drive.
+	 * We could set the appropriate timing bits on the fly,
+	 * but that might be a bit confusing.  So, for now we statically
+	 * handle this requirement by looking at our mate drive to see
+	 * what it is capable of, before choosing a mode for our own drive.
+	 *
+	 * Note: This relies on the fact we never fail from UDMA to MWDMA_2
+	 * but instead drop to PIO
+	 */
+	if (mate->present) {
+		struct hd_driveid *mateid = mate->id;
+		if (mateid && (mateid->capability & 1) &&
+		    !hwif->ide_dma_bad_drive(mate)) {
+			if ((mateid->field_valid & 4) &&
+			    (mateid->dma_ultra & 7))
+				udma_ok = 1;
+			else if ((mateid->field_valid & 2) &&
+				 (mateid->dma_mword & 7))
+				udma_ok = 0;
+			else
+				udma_ok = 1;
+		}
+	}
+
+	/*
+	 * Now see what the current drive is capable of,
+	 * selecting UDMA only if the mate said it was ok.
+	 */
+	if (id && (id->capability & 1) && drive->autodma &&
+	    !hwif->ide_dma_bad_drive(drive)) {
+		if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) {
+			if      (id->dma_ultra & 4)
+				mode = XFER_UDMA_2;
+			else if (id->dma_ultra & 2)
+				mode = XFER_UDMA_1;
+			else if (id->dma_ultra & 1)
+				mode = XFER_UDMA_0;
+		}
+		if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) {
+			if      (id->dma_mword & 4)
+				mode = XFER_MW_DMA_2;
+			else if (id->dma_mword & 2)
+				mode = XFER_MW_DMA_1;
+			else if (id->dma_mword & 1)
+				mode = XFER_MW_DMA_0;
+		}
+	}
+
+	/*
+	 * Tell the drive to switch to the new mode; abort on failure.
+	 */
+	if (!mode || cs5530_set_xfer_mode(drive, mode))
+		return 1;	/* failure */
+
+	/*
+	 * Now tune the chipset to match the drive:
+	 */
+	switch (mode) {
+		case XFER_UDMA_0:	timings = 0x00921250; break;
+		case XFER_UDMA_1:	timings = 0x00911140; break;
+		case XFER_UDMA_2:	timings = 0x00911030; break;
+		case XFER_MW_DMA_0:	timings = 0x00077771; break;
+		case XFER_MW_DMA_1:	timings = 0x00012121; break;
+		case XFER_MW_DMA_2:	timings = 0x00002020; break;
+		default:
+			printk(KERN_ERR "%s: cs5530_config_dma: huh? mode=%02x\n",
+				drive->name, mode);
+			return 1;	/* failure */
+	}
+	basereg = CS5530_BASEREG(hwif);
+	reg = hwif->INL(basereg+4);		/* get drive0 config register */
+	timings |= reg & 0x80000000;		/* preserve PIO format bit */
+	if (unit == 0) {			/* are we configuring drive0? */
+		hwif->OUTL(timings, basereg+4);	/* write drive0 config register */
+	} else {
+		if (timings & 0x00100000)
+			reg |=  0x00100000;	/* enable UDMA timings for both drives */
+		else
+			reg &= ~0x00100000;	/* disable UDMA timings for both drives */
+		hwif->OUTL(reg,     basereg+4);	/* write drive0 config register */
+		hwif->OUTL(timings, basereg+12);	/* write drive1 config register */
+	}
+	(void) hwif->ide_dma_host_on(drive);
+	/* set DMA_capable bit */
+
+	/*
+	 * Finally, turn DMA on in software, and exit.
+	 */
+	return hwif->ide_dma_on(drive);	/* success */
+}
+
+/**
+ *	init_chipset_5530	-	set up 5530 bridge
+ *	@dev: PCI device
+ *	@name: device name
+ *
+ *	Initialize the cs5530 bridge for reliable IDE DMA operation.
+ */
+
+static unsigned int __init init_chipset_cs5530 (struct pci_dev *dev, const char *name)
+{
+	struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
+	unsigned long flags;
+
+#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!cs5530_proc) {
+		cs5530_proc = 1;
+		bmide_dev = dev;
+		ide_pci_register_host_proc(&cs5530_procs[0]);
+	}
+#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
+
+	pci_for_each_dev (dev) {
+		if (dev->vendor == PCI_VENDOR_ID_CYRIX) {
+			switch (dev->device) {
+				case PCI_DEVICE_ID_CYRIX_PCI_MASTER:
+					master_0 = dev;
+					break;
+				case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
+					cs5530_0 = dev;
+					break;
+			}
+		}
+	}
+	if (!master_0) {
+		printk(KERN_ERR "%s: unable to locate PCI MASTER function\n", name);
+		return 0;
+	}
+	if (!cs5530_0) {
+		printk(KERN_ERR "%s: unable to locate CS5530 LEGACY function\n", name);
+		return 0;
+	}
+
+	spin_lock_irqsave(&ide_lock, flags);
+		/* all CPUs (there should only be one CPU with this chipset) */
+
+	/*
+	 * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530:
+	 * -->  OR 0x14 into 16-bit PCI COMMAND reg of function 0 of the cs5530
+	 */
+
+	pci_set_master(cs5530_0);
+	pci_set_mwi(cs5530_0);
+
+	/*
+	 * Set PCI CacheLineSize to 16-bytes:
+	 * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530
+	 */
+
+	pci_write_config_byte(cs5530_0, PCI_CACHE_LINE_SIZE, 0x04);
+
+	/*
+	 * Disable trapping of UDMA register accesses (Win98 hack):
+	 * --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530
+	 */
+
+	pci_write_config_word(cs5530_0, 0xd0, 0x5006);
+
+	/*
+	 * Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus:
+	 * The other settings are what is necessary to get the register
+	 * into a sane state for IDE DMA operation.
+	 */
+
+	pci_write_config_byte(master_0, 0x40, 0x1e);
+
+	/* 
+	 * Set max PCI burst size (16-bytes seems to work best):
+	 *	   16bytes: set bit-1 at 0x41 (reg value of 0x16)
+	 *	all others: clear bit-1 at 0x41, and do:
+	 *	  128bytes: OR 0x00 at 0x41
+	 *	  256bytes: OR 0x04 at 0x41
+	 *	  512bytes: OR 0x08 at 0x41
+	 *	 1024bytes: OR 0x0c at 0x41
+	 */
+
+	pci_write_config_byte(master_0, 0x41, 0x14);
+
+	/*
+	 * These settings are necessary to get the chip
+	 * into a sane state for IDE DMA operation.
+	 */
+
+	pci_write_config_byte(master_0, 0x42, 0x00);
+	pci_write_config_byte(master_0, 0x43, 0xc1);
+
+	spin_unlock_irqrestore(&ide_lock, flags);
+
+	return 0;
+}
+
+/**
+ *	init_hwif_cs5530	-	initialise an IDE channel
+ *	@hwif: IDE to initialize
+ *
+ *	This gets invoked by the IDE driver once for each channel. It
+ *	performs channel-specific pre-initialization before drive probing.
+ */
+
+static void __init init_hwif_cs5530 (ide_hwif_t *hwif)
+{
+	unsigned long basereg;
+	u32 d0_timings;
+	hwif->autodma = 0;
+
+	if (hwif->mate)
+		hwif->serialized = hwif->mate->serialized = 1;
+
+	hwif->tuneproc = &cs5530_tuneproc;
+	basereg = CS5530_BASEREG(hwif);
+	d0_timings = hwif->INL(basereg+0);
+	if (CS5530_BAD_PIO(d0_timings)) {
+		/* PIO timings not initialized? */
+		hwif->OUTL(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+0);
+		if (!hwif->drives[0].autotune)
+			hwif->drives[0].autotune = 1;
+			/* needs autotuning later */
+	}
+	if (CS5530_BAD_PIO(hwif->INL(basereg+8))) {
+	/* PIO timings not initialized? */
+		hwif->OUTL(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+8);
+		if (!hwif->drives[1].autotune)
+			hwif->drives[1].autotune = 1;
+			/* needs autotuning later */
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x07;
+	hwif->mwdma_mask = 0x07;
+
+	hwif->ide_dma_check = &cs5530_config_dma;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+/**
+ *	init_dma_cs5530		-	set up for DMA
+ *	@hwif: interface
+ *	@dmabase: DMA base address
+ *
+ *	FIXME: this can go away
+ */
+ 
+static void __init init_dma_cs5530 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+
+static int __devinit cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &cs5530_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id cs5530_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "CS5530 IDE",
+	.id_table	= cs5530_pci_tbl,
+	.probe		= cs5530_init_one,
+};
+
+static int cs5530_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void cs5530_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(cs5530_ide_init);
+module_exit(cs5530_ide_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for Cyrix/NS 5530 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cs5530.h linux-2.4.21/drivers/ide/pci/cs5530.h
--- linux-2.4.20/drivers/ide/pci/cs5530.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/cs5530.h	2002-12-18 18:58:02.000000000 +0000
@@ -0,0 +1,54 @@
+#ifndef CS5530_H
+#define CS5530_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_CS5530_TIMINGS
+
+#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 cs5530_proc;
+
+static int cs5530_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t cs5530_procs[] __initdata = {
+	{
+		.name		= "cs5530",
+		.set		= 1,
+		.get_info	= cs5530_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
+
+static unsigned int init_chipset_cs5530(struct pci_dev *, const char *);
+static void init_hwif_cs5530(ide_hwif_t *);
+static void init_dma_cs5530(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t cs5530_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_CYRIX,
+		.device		= PCI_DEVICE_ID_CYRIX_5530_IDE,
+		.name		= "CS5530",
+		.init_chipset	= init_chipset_cs5530,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_cs5530,
+		.init_dma	= init_dma_cs5530,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* CS5530_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cy82c693.c linux-2.4.21/drivers/ide/pci/cy82c693.c
--- linux-2.4.20/drivers/ide/pci/cy82c693.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/cy82c693.c	2002-12-18 18:58:05.000000000 +0000
@@ -0,0 +1,470 @@
+/*
+ * linux/drivers/ide/cy82c693.c		Version 0.40	Sep. 10, 2002
+ *
+ *  Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
+ *  Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrater
+ *
+ * CYPRESS CY82C693 chipset IDE controller
+ *
+ * The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards.
+ * Writting the driver was quite simple, since most of the job is
+ * done by the generic pci-ide support. 
+ * The hard part was finding the CY82C693's datasheet on Cypress's
+ * web page :-(. But Altavista solved this problem :-).
+ *
+ *
+ * Notes:
+ * - I recently got a 16.8G IBM DTTA, so I was able to test it with
+ *   a large and fast disk - the results look great, so I'd say the
+ *   driver is working fine :-)
+ *   hdparm -t reports 8.17 MB/sec at about 6% CPU usage for the DTTA 
+ * - this is my first linux driver, so there's probably a lot  of room 
+ *   for optimizations and bug fixing, so feel free to do it.
+ * - use idebus=xx parameter to set PCI bus speed - needed to calc
+ *   timings for PIO modes (default will be 40)
+ * - if using PIO mode it's a good idea to set the PIO mode and 
+ *   32-bit I/O support (if possible), e.g. hdparm -p2 -c1 /dev/hda
+ * - I had some problems with my IBM DHEA with PIO modes < 2
+ *   (lost interrupts) ?????
+ * - first tests with DMA look okay, they seem to work, but there is a
+ *   problem with sound - the BusMaster IDE TimeOut should fixed this
+ *
+ * Ancient History:
+ * AMH@1999-08-24: v0.34 init_cy82c693_chip moved to pci_init_cy82c693
+ * ASK@1999-01-23: v0.33 made a few minor code clean ups
+ *                       removed DMA clock speed setting by default
+ *                       added boot message
+ * ASK@1998-11-01: v0.32 added support to set BusMaster IDE TimeOut
+ *                       added support to set DMA Controller Clock Speed
+ * ASK@1998-10-31: v0.31 fixed problem with setting to high DMA modes
+ *                       on some drives.
+ * ASK@1998-10-29: v0.3 added support to set DMA modes
+ * ASK@1998-10-28: v0.2 added support to set PIO modes
+ * ASK@1998-10-27: v0.1 first version - chipset detection
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "cy82c693.h"
+
+/*
+ * calc clocks using bus_speed
+ * returns (rounded up) time in bus clocks for time in ns
+ */
+static int calc_clk (int time, int bus_speed)
+{
+	int clocks;
+
+	clocks = (time*bus_speed+999)/1000 -1;
+
+	if (clocks < 0)
+		clocks = 0;
+
+	if (clocks > 0x0F)
+		clocks = 0x0F;
+
+	return clocks;
+}
+
+/*
+ * compute the values for the clock registers for PIO
+ * mode and pci_clk [MHz] speed
+ *
+ * NOTE: for mode 0,1 and 2 drives 8-bit IDE command control registers are used
+ *       for mode 3 and 4 drives 8 and 16-bit timings are the same
+ *
+ */ 
+static void compute_clocks (u8 pio, pio_clocks_t *p_pclk)
+{
+	int clk1, clk2;
+	int bus_speed = system_bus_clock();	/* get speed of PCI bus */
+
+	/* we don't check against CY82C693's min and max speed,
+	 * so you can play with the idebus=xx parameter
+	 */
+
+	if (pio > CY82C693_MAX_PIO)
+		pio = CY82C693_MAX_PIO;
+
+	/* let's calc the address setup time clocks */
+	p_pclk->address_time = (u8)calc_clk(ide_pio_timings[pio].setup_time, bus_speed);
+
+	/* let's calc the active and recovery time clocks */
+	clk1 = calc_clk(ide_pio_timings[pio].active_time, bus_speed);
+
+	/* calc recovery timing */
+	clk2 =	ide_pio_timings[pio].cycle_time -
+		ide_pio_timings[pio].active_time -
+		ide_pio_timings[pio].setup_time;
+
+	clk2 = calc_clk(clk2, bus_speed);
+
+	clk1 = (clk1<<4)|clk2;	/* combine active and recovery clocks */
+
+	/* note: we use the same values for 16bit IOR and IOW
+         *	those are all the same, since I don't have other
+	 *	timings than those from ide_modes.h
+	 */
+
+	p_pclk->time_16r = (u8)clk1;
+	p_pclk->time_16w = (u8)clk1;
+
+	/* what are good values for 8bit ?? */
+	p_pclk->time_8 = (u8)clk1;
+}
+
+/*
+ * set DMA mode a specific channel for CY82C693
+ */
+
+static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
+{
+	u8 index = 0, data = 0;
+
+	if (mode>2)	/* make sure we set a valid mode */
+		mode = 2;
+			   
+	if (mode > drive->id->tDMA)  /* to be absolutly sure we have a valid mode */
+		mode = drive->id->tDMA;
+	
+	index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
+
+#if CY82C693_DEBUG_LOGS
+	/* for debug let's show the previous values */
+
+	HWIF(drive)->OUTB(index, CY82_INDEX_PORT);
+	data = HWIF(drive)->INB(CY82_DATA_PORT);
+
+	printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n",
+		drive->name, HWIF(drive)->channel, drive->select.b.unit,
+		(data&0x3), ((data>>2)&1));
+#endif /* CY82C693_DEBUG_LOGS */
+
+	data = (u8)mode|(u8)(single<<2);
+
+	HWIF(drive)->OUTB(index, CY82_INDEX_PORT);
+	HWIF(drive)->OUTB(data, CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO
+	printk(KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n",
+		drive->name, HWIF(drive)->channel, drive->select.b.unit,
+		mode, single);
+#endif /* CY82C693_DEBUG_INFO */
+
+	/* 
+	 * note: below we set the value for Bus Master IDE TimeOut Register
+	 * I'm not absolutly sure what this does, but it solved my problem
+	 * with IDE DMA and sound, so I now can play sound and work with
+	 * my IDE driver at the same time :-)
+	 *
+	 * If you know the correct (best) value for this register please
+	 * let me know - ASK
+	 */
+
+	data = BUSMASTER_TIMEOUT;
+	HWIF(drive)->OUTB(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT);
+	HWIF(drive)->OUTB(data, CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO	
+	printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n",
+		drive->name, data);
+#endif /* CY82C693_DEBUG_INFO */
+}
+
+/* 
+ * used to set DMA mode for CY82C693 (single and multi modes)
+ */
+int cy82c693_ide_dma_on (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+
+#if CY82C693_DEBUG_INFO
+	printk (KERN_INFO "dma_on: %s\n", drive->name);
+#endif /* CY82C693_DEBUG_INFO */
+
+	if (id != NULL) {		
+		/* Enable DMA on any drive that has DMA
+		 * (multi or single) enabled
+		 */
+		if (id->field_valid & 2) {	/* regular DMA */
+			int mmode, smode;
+
+			mmode = id->dma_mword & (id->dma_mword >> 8);
+			smode = id->dma_1word & (id->dma_1word >> 8);
+			       		      
+			if (mmode != 0) {
+				/* enable multi */
+				cy82c693_dma_enable(drive, (mmode >> 1), 0);
+			} else if (smode != 0) {
+				/* enable single */
+				cy82c693_dma_enable(drive, (smode >> 1), 1);
+			}
+		}
+	}
+        return __ide_dma_on(drive);
+}
+
+/*
+ * tune ide drive - set PIO mode
+ */
+static void cy82c693_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	pio_clocks_t pclk;
+	unsigned int addrCtrl;
+
+	/* select primary or secondary channel */
+	if (hwif->index > 0) {  /* drive is on the secondary channel */
+		dev = pci_find_slot(dev->bus->number, dev->devfn+1);
+		if (!dev) {
+			printk(KERN_ERR "%s: tune_drive: "
+				"Cannot find secondary interface!\n",
+				drive->name);
+			return;
+		}
+	}
+
+#if CY82C693_DEBUG_LOGS
+	/* for debug let's show the register values */
+	
+       	if (drive->select.b.unit == 0) {
+		/*
+		 * get master drive registers               	
+		 * address setup control register
+		 * is 32 bit !!!
+		 */ 
+	  	pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);                
+		addrCtrl &= 0x0F;
+
+		/* now let's get the remaining registers */
+		pci_read_config_byte(dev, CY82_IDE_MASTER_IOR, &pclk.time_16r);
+		pci_read_config_byte(dev, CY82_IDE_MASTER_IOW, &pclk.time_16w);
+		pci_read_config_byte(dev, CY82_IDE_MASTER_8BIT, &pclk.time_8);
+	} else {
+		/*
+		 * set slave drive registers
+		 * address setup control register
+		 * is 32 bit !!!
+		 */ 
+		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+
+		addrCtrl &= 0xF0;
+		addrCtrl >>= 4;
+
+		/* now let's get the remaining registers */
+		pci_read_config_byte(dev, CY82_IDE_SLAVE_IOR, &pclk.time_16r);
+		pci_read_config_byte(dev, CY82_IDE_SLAVE_IOW, &pclk.time_16w);
+		pci_read_config_byte(dev, CY82_IDE_SLAVE_8BIT, &pclk.time_8);
+	}
+
+	printk(KERN_INFO "%s (ch=%d, dev=%d): PIO timing is "
+		"(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n",
+		drive->name, hwif->channel, drive->select.b.unit,
+		addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+#endif /* CY82C693_DEBUG_LOGS */
+
+	/* first let's calc the pio modes */
+	pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO, NULL);
+
+#if CY82C693_DEBUG_INFO
+	printk (KERN_INFO "%s: Selected PIO mode %d\n", drive->name, pio);
+#endif /* CY82C693_DEBUG_INFO */
+
+	/* let's calc the values for this PIO mode */
+	compute_clocks(pio, &pclk);
+
+	/* now let's write  the clocks registers */
+	if (drive->select.b.unit == 0) {
+		/*
+		 * set master drive
+		 * address setup control register
+		 * is 32 bit !!!
+		 */ 
+		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+		
+		addrCtrl &= (~0xF);
+		addrCtrl |= (unsigned int)pclk.address_time;
+		pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
+
+		/* now let's set the remaining registers */
+		pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, pclk.time_16r);
+		pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, pclk.time_16w);
+		pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, pclk.time_8);
+		
+		addrCtrl &= 0xF;
+	} else {
+		/*
+		 * set slave drive
+		 * address setup control register
+		 * is 32 bit !!!
+		 */ 
+		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+
+		addrCtrl &= (~0xF0);
+		addrCtrl |= ((unsigned int)pclk.address_time<<4);
+		pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
+
+		/* now let's set the remaining registers */
+		pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, pclk.time_16r);
+		pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, pclk.time_16w);
+		pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, pclk.time_8);
+
+		addrCtrl >>= 4;
+		addrCtrl &= 0xF;
+	}	
+
+#if CY82C693_DEBUG_INFO
+	printk(KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to "
+		"(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n",
+		drive->name, hwif->channel, drive->select.b.unit,
+		addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+#endif /* CY82C693_DEBUG_INFO */
+}
+
+/*
+ * this function is called during init and is used to setup the cy82c693 chip
+ */
+unsigned int __init init_chipset_cy82c693(struct pci_dev *dev, const char *name)
+{
+	if (PCI_FUNC(dev->devfn) != 1)
+		return 0;
+
+#ifdef CY82C693_SETDMA_CLOCK
+	u8 data = 0;
+#endif /* CY82C693_SETDMA_CLOCK */ 
+
+	/* write info about this verion of the driver */
+	printk(KERN_INFO CY82_VERSION "\n");
+
+#ifdef CY82C693_SETDMA_CLOCK
+       /* okay let's set the DMA clock speed */
+        
+        outb(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
+        data = inb(CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO
+	printk(KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n",
+		name, data);
+#endif /* CY82C693_DEBUG_INFO */
+
+        /*
+	 * for some reason sometimes the DMA controller
+	 * speed is set to ATCLK/2 ???? - we fix this here
+	 * 
+	 * note: i don't know what causes this strange behaviour,
+	 *       but even changing the dma speed doesn't solve it :-(
+	 *       the ide performance is still only half the normal speed 
+	 * 
+	 *       if anybody knows what goes wrong with my machine, please
+	 *       let me know - ASK
+         */
+
+	data |= 0x03;
+
+        outb(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
+        outb(data, CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO
+	printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n",
+		name, data);
+#endif /* CY82C693_DEBUG_INFO */
+
+#endif /* CY82C693_SETDMA_CLOCK */
+	return 0;
+}
+
+/*
+ * the init function - called for each ide channel once
+ */
+void __init init_hwif_cy82c693(ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+
+	hwif->chipset = ide_cy82c693;
+	hwif->tuneproc = &cy82c693_tune_drive;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->mwdma_mask = 0x04;
+	hwif->swdma_mask = 0x04;
+
+	hwif->ide_dma_on = &cy82c693_ide_dma_on;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static __initdata ide_hwif_t *primary;
+
+void __init init_iops_cy82c693(ide_hwif_t *hwif)
+{
+	if (PCI_FUNC(hwif->pci_dev->devfn) == 1)
+		primary = hwif;
+	else {
+		hwif->mate = primary;
+		hwif->channel = 1;
+	}
+}
+
+static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &cy82c693_chipsets[id->driver_data];
+	struct pci_dev *dev2;
+
+	/* CY82C693 is more than only a IDE controller.
+	   Function 1 is primary IDE channel, function 2 - secondary. */
+        if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
+	    PCI_FUNC(dev->devfn) == 1) {
+		dev2 = pci_find_slot(dev->bus->number, dev->devfn + 1);
+		ide_setup_pci_devices(dev, dev2, d);
+	}
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id cy82c693_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "Cypress IDE",
+	.id_table	= cy82c693_pci_tbl,
+	.probe		= cy82c693_init_one,
+};
+
+static int cy82c693_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void cy82c693_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(cy82c693_ide_init);
+module_exit(cy82c693_ide_exit);
+
+MODULE_AUTHOR("Andreas Krebs, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for the Cypress CY82C693 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cy82c693.h linux-2.4.21/drivers/ide/pci/cy82c693.h
--- linux-2.4.20/drivers/ide/pci/cy82c693.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/cy82c693.h	2002-12-18 18:58:09.000000000 +0000
@@ -0,0 +1,93 @@
+#ifndef CY82C693_H
+#define CY82C693_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+/* the current version */
+#define CY82_VERSION	"CY82C693U driver v0.34 99-13-12 Andreas S. Krebs (akrebs@altavista.net)"
+
+/*
+ *	The following are used to debug the driver.
+ */
+#define	CY82C693_DEBUG_LOGS	0
+#define	CY82C693_DEBUG_INFO	0
+
+/* define CY82C693_SETDMA_CLOCK to set DMA Controller Clock Speed to ATCLK */
+#undef CY82C693_SETDMA_CLOCK
+
+/*
+ *	NOTE: the value for busmaster timeout is tricky and I got it by
+ *	 trial and error!  By using a to low value will cause DMA timeouts
+ *	 and drop IDE performance, and by using a to high value will cause
+ *	 audio playback to scatter.
+ *	 If you know a better value or how to calc it, please let me know.
+ */
+
+/* twice the value written in cy82c693ub datasheet */
+#define BUSMASTER_TIMEOUT	0x50
+/*
+ * the value above was tested on my machine and it seems to work okay
+ */
+
+/* here are the offset definitions for the registers */
+#define CY82_IDE_CMDREG		0x04
+#define CY82_IDE_ADDRSETUP	0x48
+#define CY82_IDE_MASTER_IOR	0x4C	
+#define CY82_IDE_MASTER_IOW	0x4D	
+#define CY82_IDE_SLAVE_IOR	0x4E	
+#define CY82_IDE_SLAVE_IOW	0x4F
+#define CY82_IDE_MASTER_8BIT	0x50	
+#define CY82_IDE_SLAVE_8BIT	0x51	
+
+#define CY82_INDEX_PORT		0x22
+#define CY82_DATA_PORT		0x23
+
+#define CY82_INDEX_CTRLREG1	0x01
+#define CY82_INDEX_CHANNEL0	0x30
+#define CY82_INDEX_CHANNEL1	0x31
+#define CY82_INDEX_TIMEOUT	0x32
+
+/* the max PIO mode - from datasheet */
+#define CY82C693_MAX_PIO	4
+
+/* the min and max PCI bus speed in MHz - from datasheet */
+#define CY82C963_MIN_BUS_SPEED	25
+#define CY82C963_MAX_BUS_SPEED	33
+
+/* the struct for the PIO mode timings */
+typedef struct pio_clocks_s {
+        u8	address_time;	/* Address setup (clocks) */
+	u8	time_16r;	/* clocks for 16bit IOR (0xF0=Active/data, 0x0F=Recovery) */
+	u8	time_16w;	/* clocks for 16bit IOW (0xF0=Active/data, 0x0F=Recovery) */
+	u8	time_8;		/* clocks for 8bit (0xF0=Active/data, 0x0F=Recovery) */
+} pio_clocks_t;
+
+extern unsigned int init_chipset_cy82c693(struct pci_dev *, const char *);
+extern void init_hwif_cy82c693(ide_hwif_t *);
+extern void init_iops_cy82c693(ide_hwif_t *);
+
+static ide_pci_device_t cy82c693_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_CONTAQ,
+		.device		= PCI_DEVICE_ID_CONTAQ_82C693,
+		.name		= "CY82C693",
+		.init_chipset	= init_chipset_cy82c693,
+		.init_iops	= init_iops_cy82c693,
+		.init_hwif	= init_hwif_cy82c693,
+		.init_dma	= NULL,
+		.channels	= 1,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* CY82C693_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/generic.c linux-2.4.21/drivers/ide/pci/generic.c
--- linux-2.4.20/drivers/ide/pci/generic.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/generic.c	2002-12-18 18:58:06.000000000 +0000
@@ -0,0 +1,146 @@
+/*
+ *  linux/drivers/ide/generic.c		Version 0.10	Sept 11, 2002
+ *
+ *  Copyright (C) 2001-2002	Andre Hedrick <andre@linux-ide.org>
+ */
+
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
+#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "generic.h"
+
+static unsigned int __init init_chipset_generic (struct pci_dev *dev, const char *name)
+{
+	return 0;
+}
+
+static void __init init_hwif_generic (ide_hwif_t *hwif)
+{
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_UMC_UM8673F:
+		case PCI_DEVICE_ID_UMC_UM8886A:
+		case PCI_DEVICE_ID_UMC_UM8886BF:
+			hwif->irq = hwif->channel ? 15 : 14;
+			break;
+		default:
+			break;
+	}
+
+	if (!(hwif->dma_base))
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void init_dma_generic (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+#if 0
+
+	/* Logic to add back later on */
+	
+	if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+		ide_pci_device_t *unknown = unknown_chipset;
+//		unknown->vendor = dev->vendor;
+//		unknown->device = dev->device;
+		init_setup_unknown(dev, unknown);
+		return 1;
+	}
+	return 0;
+#endif	
+
+/**
+ *	generic_init_one	-	called when a PIIX is found
+ *	@dev: the generic device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit generic_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &generic_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	if ((d->vendor == PCI_VENDOR_ID_UMC) &&
+	    (d->device == PCI_DEVICE_ID_UMC_UM8886A) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)))
+		return 1; /* UM8886A/BF pair */
+
+	if ((d->vendor == PCI_VENDOR_ID_OPTI) &&
+	    (d->device == PCI_DEVICE_ID_OPTI_82C558) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)))
+		return 1;
+
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id generic_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_NS,     PCI_DEVICE_ID_NS_87410,            PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8673F,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8886A,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8886BF,        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+	{ PCI_VENDOR_ID_HINT,   PCI_DEVICE_ID_HINT_VXPROII_IDE,    PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+	{ PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C561,          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
+	{ PCI_VENDOR_ID_OPTI,   PCI_DEVICE_ID_OPTI_82C558,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "PCI IDE",
+	.id_table	= generic_pci_tbl,
+	.probe		= generic_init_one,
+};
+
+static int generic_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void generic_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(generic_ide_init);
+module_exit(generic_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for generic PCI IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/generic.h linux-2.4.21/drivers/ide/pci/generic.h
--- linux-2.4.20/drivers/ide/pci/generic.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/generic.h	2002-12-18 18:58:04.000000000 +0000
@@ -0,0 +1,161 @@
+#ifndef IDE_GENERIC_H
+#define IDE_GENERIC_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static unsigned int init_chipset_generic(struct pci_dev *, const char *);
+static void init_hwif_generic(ide_hwif_t *);
+static void init_dma_generic(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t generic_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_NS,
+		.device		= PCI_DEVICE_ID_NS_87410,
+		.name		= "NS87410",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x43,0x08,0x08}, {0x47,0x08,0x08}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+        },{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_PCTECH,
+		.device		= PCI_DEVICE_ID_PCTECH_SAMURAI_IDE,
+		.name		= "SAMURAI",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_HOLTEK,
+		.device		= PCI_DEVICE_ID_HOLTEK_6565,
+		.name		= "HT6565",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_UMC,
+		.device		= PCI_DEVICE_ID_UMC_UM8673F,
+		.name		= "UM8673F",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 4 */
+		.vendor		= PCI_VENDOR_ID_UMC,
+		.device		= PCI_DEVICE_ID_UMC_UM8886A,
+		.name		= "UM8886A",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 5 */
+		.vendor		= PCI_VENDOR_ID_UMC,
+		.device		= PCI_DEVICE_ID_UMC_UM8886BF,
+		.name		= "UM8886BF",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 6 */
+		.vendor		= PCI_VENDOR_ID_HINT,
+		.device		= PCI_DEVICE_ID_HINT_VXPROII_IDE,
+		.name		= "HINT_IDE",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 7 */
+		.vendor		= PCI_VENDOR_ID_VIA,
+		.device		= PCI_DEVICE_ID_VIA_82C561,
+		.name		= "VIA_IDE",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 8 */
+		.vendor		= PCI_VENDOR_ID_OPTI,
+		.device		= PCI_DEVICE_ID_OPTI_82C558,
+		.name		= "OPTI621V",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+static ide_pci_device_t unknown_chipset[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= 0,
+		.device		= 0,
+		.name		= "PCI_IDE",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+
+};
+
+#endif /* IDE_GENERIC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/hpt34x.c linux-2.4.21/drivers/ide/pci/hpt34x.c
--- linux-2.4.20/drivers/ide/pci/hpt34x.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/hpt34x.c	2002-12-18 18:58:03.000000000 +0000
@@ -0,0 +1,366 @@
+/*
+ * linux/drivers/ide/hpt34x.c		Version 0.40	Sept 10, 2002
+ *
+ * Copyright (C) 1998-2000	Andre Hedrick <andre@linux-ide.org>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ *
+ * 00:12.0 Unknown mass storage controller:
+ * Triones Technologies, Inc.
+ * Unknown device 0003 (rev 01)
+ *
+ * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010)
+ * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030)
+ * hde: DMA 2  (0x0000 0x0002) (0x0000 0x0010)
+ * hdf: DMA 2  (0x0002 0x0012) (0x0010 0x0030)
+ * hdg: DMA 1  (0x0012 0x0052) (0x0030 0x0070)
+ * hdh: DMA 1  (0x0052 0x0252) (0x0070 0x00f0)
+ *
+ * ide-pci.c reference
+ *
+ * Since there are two cards that report almost identically,
+ * the only discernable difference is the values reported in pcicmd.
+ * Booting-BIOS card or HPT363 :: pcicmd == 0x07
+ * Non-bootable card or HPT343 :: pcicmd == 0x05
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "hpt34x.h"
+
+#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 hpt34x_proc = 0;
+
+#define HPT34X_MAX_DEVS		8
+static struct pci_dev *hpt34x_devs[HPT34X_MAX_DEVS];
+static int n_hpt34x_devs;
+
+static int hpt34x_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	p += sprintf(p, "\n                             "
+			"HPT34X Chipset.\n");
+	for (i = 0; i < n_hpt34x_devs; i++) {
+		struct pci_dev *dev = hpt34x_devs[i];
+		unsigned long bibma = pci_resource_start(dev, 4);
+		u8  c0 = 0, c1 = 0;
+
+		/*
+		 * at that point bibma+0x2 et bibma+0xa are byte registers
+		 * to investigate:
+		 */
+		c0 = inb_p((u16)bibma + 0x02);
+		c1 = inb_p((u16)bibma + 0x0a);
+		p += sprintf(p, "\nController: %d\n", i);
+		p += sprintf(p, "--------------- Primary Channel "
+				"---------------- Secondary Channel "
+				"-------------\n");
+		p += sprintf(p, "                %sabled "
+				"                        %sabled\n",
+				(c0&0x80) ? "dis" : " en",
+				(c1&0x80) ? "dis" : " en");
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"-------- drive0 ---------- drive1 ------\n");
+		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 " );
+
+		p += sprintf(p, "UDMA\n");
+		p += sprintf(p, "DMA\n");
+		p += sprintf(p, "PIO\n");
+	}
+	p += sprintf(p, "\n");
+
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u8 hpt34x_ratemask (ide_drive_t *drive)
+{
+	return 1;
+}
+
+static void hpt34x_clear_chipset (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u32 reg1 = 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
+
+	pci_read_config_dword(dev, 0x44, &reg1);
+	pci_read_config_dword(dev, 0x48, &reg2);
+	tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
+	tmp2 = (reg2 & ~(0x11 << drive->dn));
+	pci_write_config_dword(dev, 0x44, tmp1);
+	pci_write_config_dword(dev, 0x48, tmp2);
+}
+
+static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 speed	= ide_rate_filter(hpt34x_ratemask(drive), xferspeed);
+	u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
+	u8			hi_speed, lo_speed;
+
+	SPLIT_BYTE(speed, hi_speed, lo_speed);
+
+	if (hi_speed & 7) {
+		hi_speed = (hi_speed & 4) ? 0x01 : 0x10;
+	} else {
+		lo_speed <<= 5;
+		lo_speed >>= 5;
+	}
+
+	pci_read_config_dword(dev, 0x44, &reg1);
+	pci_read_config_dword(dev, 0x48, &reg2);
+	tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
+	tmp2 = ((hi_speed << drive->dn) | reg2);
+	pci_write_config_dword(dev, 0x44, tmp1);
+	pci_write_config_dword(dev, 0x48, tmp2);
+
+#if HPT343_DEBUG_DRIVE_INFO
+	printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
+		" (0x%02x 0x%02x)\n",
+		drive->name, ide_xfer_verbose(speed),
+		drive->dn, reg1, tmp1, reg2, tmp2,
+		hi_speed, lo_speed);
+#endif /* HPT343_DEBUG_DRIVE_INFO */
+
+	return(ide_config_drive_speed(drive, speed));
+}
+
+static void hpt34x_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	hpt34x_clear_chipset(drive);
+	(void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio));
+}
+
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.  Initally for designed for
+ * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc.
+ */
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, hpt34x_ratemask(drive));
+
+	if (!(speed))
+		return 0;
+
+	hpt34x_clear_chipset(drive);
+	(void) hpt34x_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int hpt34x_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hpt34x_tune_drive(drive, 255);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+
+#ifndef CONFIG_HPT34X_AUTODMA
+	return hwif->ide_dma_off_quietly(drive);
+#endif /* CONFIG_HPT34X_AUTODMA */
+	return hwif->ide_dma_on(drive);
+}
+
+/*
+ * If the BIOS does not set the IO base addaress to XX00, 343 will fail.
+ */
+#define	HPT34X_PCI_INIT_REG		0x80
+
+static unsigned int __init init_chipset_hpt34x (struct pci_dev *dev, const char *name)
+{
+	int i = 0;
+	unsigned long hpt34xIoBase = pci_resource_start(dev, 4);
+	unsigned long hpt_addr[4] = { 0x20, 0x34, 0x28, 0x3c };
+	unsigned long hpt_addr_len[4] = { 7, 3, 7, 3 };
+	u16 cmd;
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00);
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+
+	if (cmd & PCI_COMMAND_MEMORY) {
+		if (pci_resource_start(dev, PCI_ROM_RESOURCE)) {
+			pci_write_config_byte(dev, PCI_ROM_ADDRESS,
+				dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+			printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n",
+				dev->resource[PCI_ROM_RESOURCE].start);
+		}
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
+	} else {
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
+	}
+
+	/*
+	 * Since 20-23 can be assigned and are R/W, we correct them.
+	 */
+	pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
+	for(i=0; i<4; i++) {
+		dev->resource[i].start = (hpt34xIoBase + hpt_addr[i]);
+		dev->resource[i].end = dev->resource[i].start + hpt_addr_len[i];
+		dev->resource[i].flags = IORESOURCE_IO;
+		pci_write_config_dword(dev,
+				(PCI_BASE_ADDRESS_0 + (i * 4)),
+				dev->resource[i].start);
+	}
+	pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+	local_irq_restore(flags);
+
+#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
+	hpt34x_devs[n_hpt34x_devs++] = dev;
+
+	if (!hpt34x_proc) {
+		hpt34x_proc = 1;
+		ide_pci_register_host_proc(&hpt34x_procs[0]);
+	}
+#endif /* DISPLAY_HPT34X_TIMINGS && CONFIG_PROC_FS */
+
+	return dev->irq;
+}
+
+static void __init init_hwif_hpt34x (ide_hwif_t *hwif)
+{
+	u16 pcicmd = 0;
+
+	hwif->autodma = 0;
+
+	hwif->tuneproc = &hpt34x_tune_drive;
+	hwif->speedproc = &hpt34x_tune_chipset;
+	hwif->no_dsc = 1;
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].autotune = 1;
+
+	pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
+
+	if (!hwif->dma_base)
+		return;
+
+	hwif->ultra_mask = 0x07;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	hwif->ide_dma_check = &hpt34x_config_drive_xfer_rate;
+	if (!noautodma)
+		hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_hpt34x (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit hpt34x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &hpt34x_chipsets[id->driver_data];
+	static char *chipset_names[] = {"HPT343", "HPT345"};
+	u16 pcicmd = 0;
+
+	pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
+
+	d->name = chipset_names[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0];
+	d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD;
+
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id hpt34x_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "HPT34x IDE",
+	.id_table	= hpt34x_pci_tbl,
+	.probe		= hpt34x_init_one,
+};
+
+static int hpt34x_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void hpt34x_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(hpt34x_ide_init);
+module_exit(hpt34x_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for Highpoint 34x IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/hpt34x.h linux-2.4.21/drivers/ide/pci/hpt34x.h
--- linux-2.4.20/drivers/ide/pci/hpt34x.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/hpt34x.h	2002-12-18 18:58:01.000000000 +0000
@@ -0,0 +1,60 @@
+#ifndef HPT34X_H
+#define HPT34X_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define HPT343_DEBUG_DRIVE_INFO		0
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+#undef DISPLAY_HPT34X_TIMINGS
+
+#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 hpt34x_proc;
+
+static int hpt34x_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t hpt34x_procs[] __initdata = {
+	{
+		.name		= "hpt34x",
+		.set		= 1,
+		.get_info	= hpt34x_get_info,
+		.parent		= NULL,
+	},
+};
+#endif  /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static unsigned int init_chipset_hpt34x(struct pci_dev *, const char *);
+static void init_hwif_hpt34x(ide_hwif_t *);
+static void init_dma_hpt34x(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t hpt34x_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT343,
+		.name		= "HPT34X",
+		.init_chipset	= init_chipset_hpt34x,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt34x,
+		.init_dma	= init_dma_hpt34x,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= NEVER_BOARD,
+		.extra		= 16
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* HPT34X_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/hpt366.c linux-2.4.21/drivers/ide/pci/hpt366.c
--- linux-2.4.20/drivers/ide/pci/hpt366.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/hpt366.c	2002-12-18 18:58:03.000000000 +0000
@@ -0,0 +1,1219 @@
+/*
+ * linux/drivers/ide/hpt366.c		Version 0.34	Sept 17, 2002
+ *
+ * Copyright (C) 1999-2002		Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
+ *
+ * Thanks to HighPoint Technologies for their assistance, and hardware.
+ * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his
+ * donation of an ABit BP6 mainboard, processor, and memory acellerated
+ * development and support.
+ *
+ * Note that final HPT370 support was done by force extraction of GPL.
+ *
+ * - add function for getting/setting power status of drive
+ * - the HPT370's state machine can get confused. reset it before each dma 
+ *   xfer to prevent that from happening.
+ * - reset state engine whenever we get an error.
+ * - check for busmaster state at end of dma. 
+ * - use new highpoint timings.
+ * - detect bus speed using highpoint register.
+ * - use pll if we don't have a clock table. added a 66MHz table that's
+ *   just 2x the 33MHz table.
+ * - removed turnaround. NOTE: we never want to switch between pll and
+ *   pci clocks as the chip can glitch in those cases. the highpoint
+ *   approved workaround slows everything down too much to be useful. in
+ *   addition, we would have to serialize access to each chip.
+ * 	Adrian Sun <a.sun@sun.com>
+ *
+ * add drive timings for 66MHz PCI bus,
+ * fix ATA Cable signal detection, fix incorrect /proc info
+ * add /proc display for per-drive PIO/DMA/UDMA mode and
+ * per-channel ATA-33/66 Cable detect.
+ * 	Duncan Laurie <void@sun.com>
+ *
+ * fixup /proc output for multiple controllers
+ *	Tim Hockin <thockin@sun.com>
+ *
+ * On hpt366: 
+ * Reset the hpt366 on error, reset on dma
+ * Fix disabling Fast Interrupt hpt366.
+ * 	Mike Waychison <crlf@sun.com>
+ */
+
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "hpt366.h"
+
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static unsigned int hpt_revision(struct pci_dev *dev);
+static unsigned int hpt_minimum_revision(struct pci_dev *dev, int revision);
+
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+
+static u8 hpt366_proc = 0;
+static struct pci_dev *hpt_devs[HPT366_MAX_DEVS];
+static int n_hpt_devs;
+
+static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p	= buffer;
+	char *chipset_nums[] = {"366", "366",  "368",
+				"370", "370A", "372",
+				"302", "371",  "374" };
+	int i;
+
+	p += sprintf(p, "\n                             "
+		"HighPoint HPT366/368/370/372/374\n");
+	for (i = 0; i < n_hpt_devs; i++) {
+		struct pci_dev *dev = hpt_devs[i];
+		unsigned long iobase = dev->resource[4].start;
+		u32 class_rev = hpt_revision(dev);
+		u8 c0, c1;
+
+		p += sprintf(p, "\nController: %d\n", i);
+		p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]);
+		p += sprintf(p, "--------------- Primary Channel "
+				"--------------- Secondary Channel "
+				"--------------\n");
+
+		/* get the bus master status registers */
+		c0 = inb(iobase + 0x2);
+		c1 = inb(iobase + 0xa);
+		p += sprintf(p, "Enabled:        %s"
+				"                             %s\n",
+			(c0 & 0x80) ? "no" : "yes",
+			(c1 & 0x80) ? "no" : "yes");
+
+		if (hpt_minimum_revision(dev, 3)) {
+			u8 cbl;
+			cbl = inb(iobase + 0x7b);
+			outb(cbl | 1, iobase + 0x7b);
+			outb(cbl & ~1, iobase + 0x7b);
+			cbl = inb(iobase + 0x7a);
+			p += sprintf(p, "Cable:          ATA-%d"
+					"                          ATA-%d\n",
+				(cbl & 0x02) ? 33 : 66,
+				(cbl & 0x01) ? 33 : 66);
+			p += sprintf(p, "\n");
+		}
+
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"------- drive0 ---------- drive1 -------\n");
+		p += sprintf(p, "DMA capable:    %s              %s" 
+				"            %s               %s\n",
+			(c0 & 0x20) ? "yes" : "no ", 
+			(c0 & 0x40) ? "yes" : "no ",
+			(c1 & 0x20) ? "yes" : "no ", 
+			(c1 & 0x40) ? "yes" : "no ");
+
+		{
+			u8 c2, c3;
+			/* older revs don't have these registers mapped 
+			 * into io space */
+			pci_read_config_byte(dev, 0x43, &c0);
+			pci_read_config_byte(dev, 0x47, &c1);
+			pci_read_config_byte(dev, 0x4b, &c2);
+			pci_read_config_byte(dev, 0x4f, &c3);
+
+			p += sprintf(p, "Mode:           %s             %s"
+					"           %s              %s\n",
+				(c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " : 
+					(c0 & 0x80) ? "PIO " : "off ",
+				(c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
+					(c1 & 0x80) ? "PIO " : "off ",
+				(c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " :
+					(c2 & 0x80) ? "PIO " : "off ",
+				(c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " :
+					(c3 & 0x80) ? "PIO " : "off ");
+		}
+	}
+	p += sprintf(p, "\n");
+	
+	return p-buffer;/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u32 hpt_revision (struct pci_dev *dev)
+{
+	u32 class_rev;
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_TTI_HPT374:
+			class_rev = PCI_DEVICE_ID_TTI_HPT374; break;
+		case PCI_DEVICE_ID_TTI_HPT371:
+			class_rev = PCI_DEVICE_ID_TTI_HPT371; break;
+		case PCI_DEVICE_ID_TTI_HPT302:
+			class_rev = PCI_DEVICE_ID_TTI_HPT302; break;
+		case PCI_DEVICE_ID_TTI_HPT372:
+			class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
+		default:
+			break;
+	}
+	return class_rev;
+}
+
+static u32 hpt_minimum_revision (struct pci_dev *dev, int revision)
+{
+	unsigned int class_rev = hpt_revision(dev);
+	revision--;
+	return ((int) (class_rev > revision) ? 1 : 0);
+}
+
+static int check_in_drive_lists(ide_drive_t *drive, const char **list);
+
+static u8 hpt3xx_ratemask (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 mode			= 0;
+
+	if (hpt_minimum_revision(dev, 8)) {		/* HPT374 */
+		mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3;
+	} else if (hpt_minimum_revision(dev, 7)) {	/* HPT371 */
+		mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3;
+	} else if (hpt_minimum_revision(dev, 6)) {	/* HPT302 */
+		mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3;
+	} else if (hpt_minimum_revision(dev, 5)) {	/* HPT372 */
+		mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3;
+	} else if (hpt_minimum_revision(dev, 4)) {	/* HPT370A */
+		mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
+	} else if (hpt_minimum_revision(dev, 3)) {	/* HPT370 */
+		mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
+		mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode;
+	} else {				/* HPT366 and HPT368 */
+		mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2;
+	}
+	if (!eighty_ninty_three(drive) && (mode))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 mode			= hpt3xx_ratemask(drive);
+
+	if (drive->media != ide_disk)
+		return min(speed, (u8)XFER_PIO_4);
+
+	switch(mode) {
+		case 0x04:
+			speed = min(speed, (u8)XFER_UDMA_6);
+			break;
+		case 0x03:
+			speed = min(speed, (u8)XFER_UDMA_5);
+			if (hpt_minimum_revision(dev, 5))
+				break;
+			if (check_in_drive_lists(drive, bad_ata100_5))
+				speed = min(speed, (u8)XFER_UDMA_4);
+			break;
+		case 0x02:
+			speed = min(speed, (u8)XFER_UDMA_4);
+	/*
+	 * CHECK ME, Does this need to be set to 5 ??
+	 */
+			if (hpt_minimum_revision(dev, 3))
+				break;
+			if ((check_in_drive_lists(drive, bad_ata66_4)) ||
+			    (!(HPT366_ALLOW_ATA66_4)))
+				speed = min(speed, (u8)XFER_UDMA_3);
+			if ((check_in_drive_lists(drive, bad_ata66_3)) ||
+			    (!(HPT366_ALLOW_ATA66_3)))
+				speed = min(speed, (u8)XFER_UDMA_2);
+			break;
+		case 0x01:
+			speed = min(speed, (u8)XFER_UDMA_2);
+	/*
+	 * CHECK ME, Does this need to be set to 5 ??
+	 */
+			if (hpt_minimum_revision(dev, 3))
+				break;
+			if (check_in_drive_lists(drive, bad_ata33))
+				speed = min(speed, (u8)XFER_MW_DMA_2);
+			break;
+		case 0x00:
+		default:
+			speed = min(speed, (u8)XFER_MW_DMA_2);
+			break;
+	}
+	return speed;
+}
+
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+	struct hd_driveid *id = drive->id;
+
+	if (quirk_drives == list) {
+		while (*list)
+			if (strstr(id->model, *list++))
+				return 1;
+	} else {
+		while (*list)
+			if (!strcmp(*list++,id->model))
+				return 1;
+	}
+	return 0;
+}
+
+static unsigned int pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+	for ( ; chipset_table->xfer_speed ; chipset_table++)
+		if (chipset_table->xfer_speed == speed)
+			return chipset_table->chipset_settings;
+	return chipset_table->chipset_settings;
+}
+
+static void hpt366_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 speed		= hpt3xx_ratefilter(drive, xferspeed);
+//	u8 speed		= ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
+	u8 regtime		= (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
+	u8 regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
+	u8 drive_fast		= 0;
+	u32 reg1 = 0, reg2	= 0;
+
+	/*
+	 * Disable the "fast interrupt" prediction.
+	 */
+	pci_read_config_byte(dev, regfast, &drive_fast);
+#if 0
+	if (drive_fast & 0x02)
+		pci_write_config_byte(dev, regfast, drive_fast & ~0x20);
+#else
+	if (drive_fast & 0x80)
+		pci_write_config_byte(dev, regfast, drive_fast & ~0x80);
+#endif
+
+	reg2 = pci_bus_clock_list(speed,
+		(struct chipset_bus_clock_list_entry *) pci_get_drvdata(dev));
+	/*
+	 * Disable on-chip PIO FIFO/buffer
+	 *  (to avoid problems handling I/O errors later)
+	 */
+	pci_read_config_dword(dev, regtime, &reg1);
+	if (speed >= XFER_MW_DMA_0) {
+		reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
+	} else {
+		reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000);
+	}	
+	reg2 &= ~0x80000000;
+
+	pci_write_config_dword(dev, regtime, reg2);
+}
+
+static void hpt368_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	hpt366_tune_chipset(drive, speed);
+}
+
+static void hpt370_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	u8 speed	= hpt3xx_ratefilter(drive, xferspeed);
+//	u8 speed	= ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
+	u8 regfast	= (HWIF(drive)->channel) ? 0x55 : 0x51;
+	u8 drive_pci	= 0x40 + (drive->dn * 4);
+	u8 new_fast	= 0, drive_fast = 0;
+	u32 list_conf	= 0, drive_conf = 0;
+	u32 conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
+
+	/*
+	 * Disable the "fast interrupt" prediction.
+	 * don't holdoff on interrupts. (== 0x01 despite what the docs say) 
+	 */
+	pci_read_config_byte(dev, regfast, &drive_fast);
+	new_fast = drive_fast;
+	if (new_fast & 0x02)
+		new_fast &= ~0x02;
+
+#ifdef HPT_DELAY_INTERRUPT
+	if (new_fast & 0x01)
+		new_fast &= ~0x01;
+#else
+	if ((new_fast & 0x01) == 0)
+		new_fast |= 0x01;
+#endif
+	if (new_fast != drive_fast)
+		pci_write_config_byte(dev, regfast, new_fast);
+
+	list_conf = pci_bus_clock_list(speed, 
+				       (struct chipset_bus_clock_list_entry *)
+				       pci_get_drvdata(dev));
+
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
+	
+	if (speed < XFER_MW_DMA_0) {
+		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+	}
+
+	pci_write_config_dword(dev, drive_pci, list_conf);
+}
+
+static void hpt372_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 speed	= hpt3xx_ratefilter(drive, xferspeed);
+//	u8 speed	= ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
+	u8 regfast	= (HWIF(drive)->channel) ? 0x55 : 0x51;
+	u8 drive_fast	= 0, drive_pci = 0x40 + (drive->dn * 4);
+	u32 list_conf	= 0, drive_conf = 0;
+	u32 conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
+
+	/*
+	 * Disable the "fast interrupt" prediction.
+	 * don't holdoff on interrupts. (== 0x01 despite what the docs say)
+	 */
+	pci_read_config_byte(dev, regfast, &drive_fast);
+	drive_fast &= ~0x07;
+	pci_write_config_byte(dev, regfast, drive_fast);
+					
+	list_conf = pci_bus_clock_list(speed,
+			(struct chipset_bus_clock_list_entry *)
+					pci_get_drvdata(dev));
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
+	if (speed < XFER_MW_DMA_0)
+		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+	pci_write_config_dword(dev, drive_pci, list_conf);
+}
+
+static void hpt374_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	hpt372_tune_chipset(drive, speed);
+}
+
+static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+
+	if (hpt_minimum_revision(dev, 8))
+		hpt374_tune_chipset(drive, speed);
+#if 0
+	else if (hpt_minimum_revision(dev, 7))
+		hpt371_tune_chipset(drive, speed);
+	else if (hpt_minimum_revision(dev, 6))
+		hpt302_tune_chipset(drive, speed);
+#endif
+	else if (hpt_minimum_revision(dev, 5))
+		hpt372_tune_chipset(drive, speed);
+	else if (hpt_minimum_revision(dev, 3))
+		hpt370_tune_chipset(drive, speed);
+	else if (hpt_minimum_revision(dev, 2))
+		hpt368_tune_chipset(drive, speed);
+	else
+                hpt366_tune_chipset(drive, speed);
+
+	return ((int) ide_config_drive_speed(drive, speed));
+}
+
+static void hpt3xx_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	(void) hpt3xx_tune_chipset(drive, (XFER_PIO_0 + pio));
+}
+
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.  Initally for designed for
+ * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
+ *
+ * check_in_drive_lists(drive, bad_ata66_4)
+ * check_in_drive_lists(drive, bad_ata66_3)
+ * check_in_drive_lists(drive, bad_ata33)
+ *
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive));
+
+	if (!(speed))
+		return 0;
+
+	(void) hpt3xx_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int hpt3xx_quirkproc (ide_drive_t *drive)
+{
+	return ((int) check_in_drive_lists(drive, quirk_drives));
+}
+
+static void hpt3xx_intrproc (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	if (drive->quirk_list)
+		return;
+	/* drives in the quirk_list may not like intr setups/cleanups */
+	hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+}
+
+static void hpt3xx_maskproc (ide_drive_t *drive, int mask)
+{
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+
+	if (drive->quirk_list) {
+		if (hpt_minimum_revision(dev,3)) {
+			u8 reg5a = 0;
+			pci_read_config_byte(dev, 0x5a, &reg5a);
+			if (((reg5a & 0x10) >> 4) != mask)
+				pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
+		} else {
+			if (mask) {
+				disable_irq(HWIF(drive)->irq);
+			} else {
+				enable_irq(HWIF(drive)->irq);
+			}
+		}
+	} else {
+		if (IDE_CONTROL_REG)
+			HWIF(drive)->OUTB(mask ? (drive->ctl | 2) :
+						 (drive->ctl & ~2),
+						 IDE_CONTROL_REG);
+	}
+}
+
+static int hpt366_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if (id->dma_mword & hwif->mwdma_mask) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hpt3xx_tune_drive(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+/*
+ * This is specific to the HPT366 UDMA bios chipset
+ * by HighPoint|Triones Technologies, Inc.
+ */
+static int hpt366_ide_dma_lostirq (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 reg50h = 0, reg52h = 0, reg5ah = 0;
+
+	pci_read_config_byte(dev, 0x50, &reg50h);
+	pci_read_config_byte(dev, 0x52, &reg52h);
+	pci_read_config_byte(dev, 0x5a, &reg5ah);
+	printk("%s: (%s)  reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
+		drive->name, __FUNCTION__, reg50h, reg52h, reg5ah);
+	if (reg5ah & 0x10)
+		pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
+#if 0
+	/* how about we flush and reset, mmmkay? */
+	pci_write_config_byte(dev, 0x51, 0x1F);
+	/* fall through to a reset */
+	case ide_dma_begin:
+	case ide_dma_end:
+	/* reset the chips state over and over.. */
+	pci_write_config_byte(dev, 0x51, 0x13);
+#endif
+	return __ide_dma_lostirq(drive);
+}
+
+static void hpt370_clear_engine (ide_drive_t *drive)
+{
+	u8 regstate = HWIF(drive)->channel ? 0x54 : 0x50;
+	pci_write_config_byte(HWIF(drive)->pci_dev, regstate, 0x37);
+	udelay(10);
+}
+
+static int hpt370_ide_dma_begin (ide_drive_t *drive)
+{
+#ifdef HPT_RESET_STATE_ENGINE
+	hpt370_clear_engine(drive);
+#endif
+	return __ide_dma_begin(drive);
+}
+
+static int hpt370_ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
+
+	if (dma_stat & 0x01) {
+		/* wait a little */
+		udelay(20);
+		dma_stat = hwif->INB(hwif->dma_status);
+	}
+	if ((dma_stat & 0x01) != 0) 
+		/* fallthrough */
+		(void) HWIF(drive)->ide_dma_timeout(drive);
+
+	return __ide_dma_end(drive);
+}
+
+static void hpt370_lostirq_timeout (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 bfifo = 0, reginfo	= hwif->channel ? 0x56 : 0x52;
+	u8 dma_stat = 0, dma_cmd = 0;
+
+	pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo);
+	printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
+	hpt370_clear_engine(drive);
+	/* get dma command mode */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop dma */
+	hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* clear errors */
+	hwif->OUTB(dma_stat | 0x6, hwif->dma_status);
+}
+
+static int hpt370_ide_dma_timeout (ide_drive_t *drive)
+{
+	hpt370_lostirq_timeout(drive);
+	hpt370_clear_engine(drive);
+	return __ide_dma_timeout(drive);
+}
+
+static int hpt370_ide_dma_lostirq (ide_drive_t *drive)
+{
+	hpt370_lostirq_timeout(drive);
+	hpt370_clear_engine(drive);
+	return __ide_dma_lostirq(drive);
+}
+
+static int hpt374_ide_dma_end (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 msc_stat = 0, mscreg	= hwif->channel ? 0x54 : 0x50;
+	u8 bwsr_stat = 0, bwsr_mask = hwif->channel ? 0x02 : 0x01;
+
+	pci_read_config_byte(dev, 0x6a, &bwsr_stat);
+	pci_read_config_byte(dev, mscreg, &msc_stat);
+	if ((bwsr_stat & bwsr_mask) == bwsr_mask)
+		pci_write_config_byte(dev, mscreg, msc_stat|0x30);
+	return __ide_dma_end(drive);
+}
+
+/*
+ * Since SUN Cobalt is attempting to do this operation, I should disclose
+ * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
+ * HOTSWAP ATA Infrastructure.
+ */
+
+static void hpt3xx_reset (ide_drive_t *drive)
+{
+#if 0
+	unsigned long high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
+	u8 reset	= (HWIF(drive)->channel) ? 0x80 : 0x40;
+	u8 reg59h	= 0;
+
+	pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, &reg59h);
+	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset);
+	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h);
+#endif
+}
+
+static int hpt3xx_tristate (ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 reg59h = 0, reset	= (hwif->channel) ? 0x80 : 0x40;
+	u8 regXXh = 0, state_reg= (hwif->channel) ? 0x57 : 0x53;
+
+	if (!hwif)
+		return -EINVAL;
+
+//	hwif->bus_state = state;
+
+	pci_read_config_byte(dev, 0x59, &reg59h);
+	pci_read_config_byte(dev, state_reg, &regXXh);
+
+	if (state) {
+		(void) ide_do_reset(drive);
+		pci_write_config_byte(dev, state_reg, regXXh|0x80);
+		pci_write_config_byte(dev, 0x59, reg59h|reset);
+	} else {
+		pci_write_config_byte(dev, 0x59, reg59h & ~(reset));
+		pci_write_config_byte(dev, state_reg, regXXh & ~(0x80));
+		(void) ide_do_reset(drive);
+	}
+	return 0;
+}
+
+/* 
+ * set/get power state for a drive.
+ * turning the power off does the following things:
+ *   1) soft-reset the drive
+ *   2) tri-states the ide bus
+ *
+ * when we turn things back on, we need to re-initialize things.
+ */
+#define TRISTATE_BIT  0x8000
+static int hpt370_busproc(ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 tristate = 0, resetmask = 0, bus_reg = 0;
+	u16 tri_reg;
+
+	if (!hwif)
+		return -EINVAL;
+
+	hwif->bus_state = state;
+
+	if (hwif->channel) { 
+		/* secondary channel */
+		tristate = 0x56;
+		resetmask = 0x80; 
+	} else { 
+		/* primary channel */
+		tristate = 0x52;
+		resetmask = 0x40;
+	}
+
+	/* grab status */
+	pci_read_config_word(dev, tristate, &tri_reg);
+	pci_read_config_byte(dev, 0x59, &bus_reg);
+
+	/* set the state. we don't set it if we don't need to do so.
+	 * make sure that the drive knows that it has failed if it's off */
+	switch (state) {
+	case BUSSTATE_ON:
+		hwif->drives[0].failures = 0;
+		hwif->drives[1].failures = 0;
+		if ((bus_reg & resetmask) == 0)
+			return 0;
+		tri_reg &= ~TRISTATE_BIT;
+		bus_reg &= ~resetmask;
+		break;
+	case BUSSTATE_OFF:
+		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+		if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask))
+			return 0;
+		tri_reg &= ~TRISTATE_BIT;
+		bus_reg |= resetmask;
+		break;
+	case BUSSTATE_TRISTATE:
+		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+		if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask))
+			return 0;
+		tri_reg |= TRISTATE_BIT;
+		bus_reg |= resetmask;
+		break;
+	}
+	pci_write_config_byte(dev, 0x59, bus_reg);
+	pci_write_config_word(dev, tristate, tri_reg);
+
+	return 0;
+}
+
+static int __init init_hpt37x(struct pci_dev *dev)
+{
+	int adjust, i;
+	u16 freq;
+	u32 pll;
+	u8 reg5bh;
+
+#if 1
+	u8 reg5ah = 0;
+	pci_read_config_byte(dev, 0x5a, &reg5ah);
+	/* interrupt force enable */
+	pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
+#endif
+
+	/*
+	 * default to pci clock. make sure MA15/16 are set to output
+	 * to prevent drives having problems with 40-pin cables.
+	 */
+	pci_write_config_byte(dev, 0x5b, 0x23);
+
+	/*
+	 * set up the PLL. we need to adjust it so that it's stable. 
+	 * freq = Tpll * 192 / Tpci
+	 */
+	pci_read_config_word(dev, 0x78, &freq);
+	freq &= 0x1FF;
+	if (freq < 0x9c) {
+		pll = F_LOW_PCI_33;
+		if (hpt_minimum_revision(dev,8))
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt374);
+		else if (hpt_minimum_revision(dev,5))
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt372);
+		else if (hpt_minimum_revision(dev,4))
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt370a);
+		else
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt370);
+		printk("HPT37X: using 33MHz PCI clock\n");
+	} else if (freq < 0xb0) {
+		pll = F_LOW_PCI_40;
+	} else if (freq < 0xc8) {
+		pll = F_LOW_PCI_50;
+		if (hpt_minimum_revision(dev,8))
+			return -EOPNOTSUPP;
+		else if (hpt_minimum_revision(dev,5))
+			pci_set_drvdata(dev, (void *) fifty_base_hpt372);
+		else if (hpt_minimum_revision(dev,4))
+			pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+		else
+			pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+		printk("HPT37X: using 50MHz PCI clock\n");
+	} else {
+		pll = F_LOW_PCI_66;
+		if (hpt_minimum_revision(dev,8))
+		{
+			printk(KERN_ERR "HPT37x: 66MHz timings are not supported.\n");
+			return -EOPNOTSUPP;
+		}
+		else if (hpt_minimum_revision(dev,5))
+			pci_set_drvdata(dev, (void *) sixty_six_base_hpt372);
+		else if (hpt_minimum_revision(dev,4))
+			pci_set_drvdata(dev, (void *) sixty_six_base_hpt370a);
+		else
+			pci_set_drvdata(dev, (void *) sixty_six_base_hpt370);
+		printk("HPT37X: using 66MHz PCI clock\n");
+	}
+	
+	/*
+	 * only try the pll if we don't have a table for the clock
+	 * speed that we're running at. NOTE: the internal PLL will
+	 * result in slow reads when using a 33MHz PCI clock. we also
+	 * don't like to use the PLL because it will cause glitches
+	 * on PRST/SRST when the HPT state engine gets reset.
+	 */
+	if (pci_get_drvdata(dev)) 
+		goto init_hpt37X_done;
+	
+	/*
+	 * adjust PLL based upon PCI clock, enable it, and wait for
+	 * stabilization.
+	 */
+	adjust = 0;
+	freq = (pll < F_LOW_PCI_50) ? 2 : 4;
+	while (adjust++ < 6) {
+		pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
+				       pll | 0x100);
+
+		/* wait for clock stabilization */
+		for (i = 0; i < 0x50000; i++) {
+			pci_read_config_byte(dev, 0x5b, &reg5bh);
+			if (reg5bh & 0x80) {
+				/* spin looking for the clock to destabilize */
+				for (i = 0; i < 0x1000; ++i) {
+					pci_read_config_byte(dev, 0x5b, 
+							     &reg5bh);
+					if ((reg5bh & 0x80) == 0)
+						goto pll_recal;
+				}
+				pci_read_config_dword(dev, 0x5c, &pll);
+				pci_write_config_dword(dev, 0x5c, 
+						       pll & ~0x100);
+				pci_write_config_byte(dev, 0x5b, 0x21);
+				if (hpt_minimum_revision(dev,8))
+					return -EOPNOTSUPP;
+				else if (hpt_minimum_revision(dev,5))
+					pci_set_drvdata(dev, (void *) fifty_base_hpt372);
+				else if (hpt_minimum_revision(dev,4))
+					pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+				else
+					pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+				printk("HPT37X: using 50MHz internal PLL\n");
+				goto init_hpt37X_done;
+			}
+		}
+pll_recal:
+		if (adjust & 1)
+			pll -= (adjust >> 1);
+		else
+			pll += (adjust >> 1);
+	} 
+
+init_hpt37X_done:
+	/* reset state engine */
+	pci_write_config_byte(dev, 0x50, 0x37); 
+	pci_write_config_byte(dev, 0x54, 0x37); 
+	udelay(100);
+	return 0;
+}
+
+static int __init init_hpt366 (struct pci_dev *dev)
+{
+	u32 reg1	= 0;
+	u8 drive_fast	= 0;
+
+	/*
+	 * Disable the "fast interrupt" prediction.
+	 */
+	pci_read_config_byte(dev, 0x51, &drive_fast);
+	if (drive_fast & 0x80)
+		pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
+	pci_read_config_dword(dev, 0x40, &reg1);
+									
+	/* detect bus speed by looking at control reg timing: */
+	switch((reg1 >> 8) & 7) {
+		case 5:
+			pci_set_drvdata(dev, (void *) forty_base_hpt366);
+			break;
+		case 9:
+			pci_set_drvdata(dev, (void *) twenty_five_base_hpt366);
+			break;
+		case 7:
+		default:
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt366);
+			break;
+	}
+
+	if (!pci_get_drvdata(dev))
+	{
+		printk(KERN_ERR "hpt366: unknown bus timing.\n");
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+static unsigned int __init init_chipset_hpt366 (struct pci_dev *dev, const char *name)
+{
+	int ret = 0;
+	u8 test = 0;
+
+	if (dev->resource[PCI_ROM_RESOURCE].start)
+		pci_write_config_byte(dev, PCI_ROM_ADDRESS,
+			dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+
+	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
+	if (test != (L1_CACHE_BYTES / 4))
+		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+			(L1_CACHE_BYTES / 4));
+
+	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
+	if (test != 0x78)
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+
+	pci_read_config_byte(dev, PCI_MIN_GNT, &test);
+	if (test != 0x08)
+		pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+
+	pci_read_config_byte(dev, PCI_MAX_LAT, &test);
+	if (test != 0x08)
+		pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+
+	if (hpt_minimum_revision(dev, 3)) {
+		ret = init_hpt37x(dev);
+	} else {
+		ret =init_hpt366(dev);
+	}
+	if (ret)
+		return ret;
+	
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+	hpt_devs[n_hpt_devs++] = dev;
+
+	if (!hpt366_proc) {
+		hpt366_proc = 1;
+		ide_pci_register_host_proc(&hpt366_procs[0]);
+	}
+#endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */
+
+	return dev->irq;
+}
+
+static void __init init_hwif_hpt366 (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev		= hwif->pci_dev;
+	u8 ata66 = 0, regmask		= (hwif->channel) ? 0x01 : 0x02;
+
+	hwif->tuneproc			= &hpt3xx_tune_drive;
+	hwif->speedproc			= &hpt3xx_tune_chipset;
+	hwif->quirkproc			= &hpt3xx_quirkproc;
+	hwif->intrproc			= &hpt3xx_intrproc;
+	hwif->maskproc			= &hpt3xx_maskproc;
+
+	pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
+
+#ifdef DEBUG
+	printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
+		ata66, (ata66 & regmask) ? "33" : "66",
+		PCI_FUNC(hwif->pci_dev->devfn));
+#endif /* DEBUG */
+
+#ifdef HPT_SERIALIZE_IO
+	/* serialize access to this device */
+	if (hwif->mate)
+		hwif->serialized = hwif->mate->serialized = 1;
+#endif
+
+	if (hpt_minimum_revision(dev,3)) {
+		u8 reg5ah = 0;
+			pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
+		/*
+		 * set up ioctl for power status.
+		 * note: power affects both
+		 * drives on each channel
+		 */
+		hwif->resetproc	= &hpt3xx_reset;
+		hwif->busproc	= &hpt370_busproc;
+//		hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+	} else if (hpt_minimum_revision(dev,2)) {
+		hwif->resetproc	= &hpt3xx_reset;
+		hwif->busproc	= &hpt3xx_tristate;
+	} else {
+		hwif->resetproc = &hpt3xx_reset;
+		hwif->busproc   = &hpt3xx_tristate;
+	}
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+
+	if (!(hwif->udma_four))
+		hwif->udma_four = ((ata66 & regmask) ? 0 : 1);
+	hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
+
+	if (hpt_minimum_revision(dev,8))
+		hwif->ide_dma_end = &hpt374_ide_dma_end;
+	else if (hpt_minimum_revision(dev,5))
+		hwif->ide_dma_end = &hpt374_ide_dma_end;
+	else if (hpt_minimum_revision(dev,3)) {
+		hwif->ide_dma_begin = &hpt370_ide_dma_begin;
+		hwif->ide_dma_end = &hpt370_ide_dma_end;
+		hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
+		hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq;
+	} else if (hpt_minimum_revision(dev,2))
+		hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
+	else
+		hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_hpt366 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	u8 masterdma	= 0, slavedma = 0;
+	u8 dma_new	= 0, dma_old = 0;
+	u8 primary	= hwif->channel ? 0x4b : 0x43;
+	u8 secondary	= hwif->channel ? 0x4f : 0x47;
+	unsigned long flags;
+
+	if (!dmabase)
+		return;
+
+	dma_old = hwif->INB(dmabase+2);
+
+	local_irq_save(flags);
+
+	dma_new = dma_old;
+	pci_read_config_byte(hwif->pci_dev, primary, &masterdma);
+	pci_read_config_byte(hwif->pci_dev, secondary, &slavedma);
+
+	if (masterdma & 0x30)	dma_new |= 0x20;
+	if (slavedma & 0x30)	dma_new |= 0x40;
+	if (dma_new != dma_old)
+		hwif->OUTB(dma_new, dmabase+2);
+
+	local_irq_restore(flags);
+
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+extern void ide_setup_pci_devices(struct pci_dev *, struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_hpt374 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct pci_dev *findev = NULL;
+
+	if (PCI_FUNC(dev->devfn) & 1)
+		return;
+
+	pci_for_each_dev(findev) {
+		if ((findev->vendor == dev->vendor) &&
+		    (findev->device == dev->device) &&
+		    ((findev->devfn - dev->devfn) == 1) &&
+		    (PCI_FUNC(findev->devfn) & 1)) {
+			u8 irq = 0, irq2 = 0;
+			pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+			pci_read_config_byte(findev, PCI_INTERRUPT_LINE, &irq2);
+			if (irq != irq2) {
+				pci_write_config_byte(findev,
+						PCI_INTERRUPT_LINE, irq);
+				findev->irq = dev->irq;
+				printk("%s: pci-config space interrupt "
+					"fixed.\n", d->name);
+			}
+			ide_setup_pci_devices(dev, findev, d);
+			return;
+		}
+	}
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_hpt37x (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_hpt366 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct pci_dev *findev = NULL;
+	u8 pin1 = 0, pin2 = 0;
+	unsigned int class_rev;
+	char *chipset_names[] = {"HPT366", "HPT366",  "HPT368",
+				 "HPT370", "HPT370A", "HPT372"};
+
+	if (PCI_FUNC(dev->devfn) & 1)
+		return;
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+	strcpy(d->name, chipset_names[class_rev]);
+
+	switch(class_rev) {
+		case 5:
+		case 4:
+		case 3: ide_setup_pci_device(dev, d);
+			return;
+		default:	break;
+	}
+
+	d->channels = 1;
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
+	pci_for_each_dev(findev) {
+		if ((findev->vendor == dev->vendor) &&
+		    (findev->device == dev->device) &&
+		    ((findev->devfn - dev->devfn) == 1) &&
+		    (PCI_FUNC(findev->devfn) & 1)) {
+			pci_read_config_byte(findev, PCI_INTERRUPT_PIN, &pin2);
+			if ((pin1 != pin2) && (dev->irq == findev->irq)) {
+				d->bootable = ON_BOARD;
+				printk("%s: onboard version of chipset, "
+					"pin1=%d pin2=%d\n", d->name,
+					pin1, pin2);
+			}
+			ide_setup_pci_devices(dev, findev, d);
+			return;
+		}
+	}
+	ide_setup_pci_device(dev, d);
+}
+
+
+/**
+ *	hpt366_init_one	-	called when an HPT366 is found
+ *	@dev: the hpt366 device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit hpt366_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &hpt366_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id hpt366_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT374, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "HPT366 IDE",
+	.id_table	= hpt366_pci_tbl,
+	.probe		= hpt366_init_one,
+};
+
+static int hpt366_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void hpt366_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(hpt366_ide_init);
+module_exit(hpt366_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for Highpoint HPT366 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/hpt366.h linux-2.4.21/drivers/ide/pci/hpt366.h
--- linux-2.4.20/drivers/ide/pci/hpt366.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/hpt366.h	2002-12-18 18:58:11.000000000 +0000
@@ -0,0 +1,523 @@
+#ifndef HPT366_H
+#define HPT366_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_HPT366_TIMINGS
+
+/* various tuning parameters */
+#define HPT_RESET_STATE_ENGINE
+#undef HPT_DELAY_INTERRUPT
+#undef HPT_SERIALIZE_IO
+
+const char *quirk_drives[] = {
+	"QUANTUM FIREBALLlct08 08",
+	"QUANTUM FIREBALLP KA6.4",
+	"QUANTUM FIREBALLP LM20.4",
+	"QUANTUM FIREBALLP LM20.5",
+        NULL
+};
+
+const char *bad_ata100_5[] = {
+	"IBM-DTLA-307075",
+	"IBM-DTLA-307060",
+	"IBM-DTLA-307045",
+	"IBM-DTLA-307030",
+	"IBM-DTLA-307020",
+	"IBM-DTLA-307015",
+	"IBM-DTLA-305040",
+	"IBM-DTLA-305030",
+	"IBM-DTLA-305020",
+	"IC35L010AVER07-0",
+	"IC35L020AVER07-0",
+	"IC35L030AVER07-0",
+	"IC35L040AVER07-0",
+	"IC35L060AVER07-0",
+	"WDC AC310200R",
+	NULL
+};
+
+const char *bad_ata66_4[] = {
+	"IBM-DTLA-307075",
+	"IBM-DTLA-307060",
+	"IBM-DTLA-307045",
+	"IBM-DTLA-307030",
+	"IBM-DTLA-307020",
+	"IBM-DTLA-307015",
+	"IBM-DTLA-305040",
+	"IBM-DTLA-305030",
+	"IBM-DTLA-305020",
+	"IC35L010AVER07-0",
+	"IC35L020AVER07-0",
+	"IC35L030AVER07-0",
+	"IC35L040AVER07-0",
+	"IC35L060AVER07-0",
+	"WDC AC310200R",
+	NULL
+};
+
+const char *bad_ata66_3[] = {
+	"WDC AC310200R",
+	NULL
+};
+
+const char *bad_ata33[] = {
+	"Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
+	"Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
+	"Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
+	"Maxtor 90510D4",
+	"Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
+	"Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
+	"Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
+	NULL
+};
+
+struct chipset_bus_clock_list_entry {
+	byte		xfer_speed;
+	unsigned int	chipset_settings;
+};
+
+/* key for bus clock timings
+ * bit
+ * 0:3    data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
+ *        DMA. cycles = value + 1
+ * 4:8    data_low_time. active time of DIOW_/DIOR_ for PIO and MW
+ *        DMA. cycles = value + 1
+ * 9:12   cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ *        register access.
+ * 13:17  cmd_low_time. active time of DIOW_/DIOR_ during task file
+ *        register access.
+ * 18:21  udma_cycle_time. clock freq and clock cycles for UDMA xfer.
+ *        during task file register access.
+ * 22:24  pre_high_time. time to initialize 1st cycle for PIO and MW DMA
+ *        xfer.
+ * 25:27  cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ *        register access.
+ * 28     UDMA enable
+ * 29     DMA enable
+ * 30     PIO_MST enable. if set, the chip is in bus master mode during
+ *        PIO.
+ * 31     FIFO enable.
+ */
+struct chipset_bus_clock_list_entry forty_base_hpt366[] = {
+	{	XFER_UDMA_4,	0x900fd943	},
+	{	XFER_UDMA_3,	0x900ad943	},
+	{	XFER_UDMA_2,	0x900bd943	},
+	{	XFER_UDMA_1,	0x9008d943	},
+	{	XFER_UDMA_0,	0x9008d943	},
+
+	{	XFER_MW_DMA_2,	0xa008d943	},
+	{	XFER_MW_DMA_1,	0xa010d955	},
+	{	XFER_MW_DMA_0,	0xa010d9fc	},
+
+	{	XFER_PIO_4,	0xc008d963	},
+	{	XFER_PIO_3,	0xc010d974	},
+	{	XFER_PIO_2,	0xc010d997	},
+	{	XFER_PIO_1,	0xc010d9c7	},
+	{	XFER_PIO_0,	0xc018d9d9	},
+	{	0,		0x0120d9d9	}
+};
+
+struct chipset_bus_clock_list_entry thirty_three_base_hpt366[] = {
+	{	XFER_UDMA_4,	0x90c9a731	},
+	{	XFER_UDMA_3,	0x90cfa731	},
+	{	XFER_UDMA_2,	0x90caa731	},
+	{	XFER_UDMA_1,	0x90cba731	},
+	{	XFER_UDMA_0,	0x90c8a731	},
+
+	{	XFER_MW_DMA_2,	0xa0c8a731	},
+	{	XFER_MW_DMA_1,	0xa0c8a732	},	/* 0xa0c8a733 */
+	{	XFER_MW_DMA_0,	0xa0c8a797	},
+
+	{	XFER_PIO_4,	0xc0c8a731	},
+	{	XFER_PIO_3,	0xc0c8a742	},
+	{	XFER_PIO_2,	0xc0d0a753	},
+	{	XFER_PIO_1,	0xc0d0a7a3	},	/* 0xc0d0a793 */
+	{	XFER_PIO_0,	0xc0d0a7aa	},	/* 0xc0d0a7a7 */
+	{	0,		0x0120a7a7	}
+};
+
+struct chipset_bus_clock_list_entry twenty_five_base_hpt366[] = {
+
+	{	XFER_UDMA_4,	0x90c98521	},
+	{	XFER_UDMA_3,	0x90cf8521	},
+	{	XFER_UDMA_2,	0x90cf8521	},
+	{	XFER_UDMA_1,	0x90cb8521	},
+	{	XFER_UDMA_0,	0x90cb8521	},
+
+	{	XFER_MW_DMA_2,	0xa0ca8521	},
+	{	XFER_MW_DMA_1,	0xa0ca8532	},
+	{	XFER_MW_DMA_0,	0xa0ca8575	},
+
+	{	XFER_PIO_4,	0xc0ca8521	},
+	{	XFER_PIO_3,	0xc0ca8532	},
+	{	XFER_PIO_2,	0xc0ca8542	},
+	{	XFER_PIO_1,	0xc0d08572	},
+	{	XFER_PIO_0,	0xc0d08585	},
+	{	0,		0x01208585	}
+};
+
+/* from highpoint documentation. these are old values */
+struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
+/*	{	XFER_UDMA_5,	0x1A85F442,	0x16454e31	}, */
+	{	XFER_UDMA_5,	0x16454e31	},
+	{	XFER_UDMA_4,	0x16454e31	},
+	{	XFER_UDMA_3,	0x166d4e31	},
+	{	XFER_UDMA_2,	0x16494e31	},
+	{	XFER_UDMA_1,	0x164d4e31	},
+	{	XFER_UDMA_0,	0x16514e31	},
+
+	{	XFER_MW_DMA_2,	0x26514e21	},
+	{	XFER_MW_DMA_1,	0x26514e33	},
+	{	XFER_MW_DMA_0,	0x26514e97	},
+
+	{	XFER_PIO_4,	0x06514e21	},
+	{	XFER_PIO_3,	0x06514e22	},
+	{	XFER_PIO_2,	0x06514e33	},
+	{	XFER_PIO_1,	0x06914e43	},
+	{	XFER_PIO_0,	0x06914e57	},
+	{	0,		0x06514e57	}
+};
+
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+	{       XFER_UDMA_5,    0x14846231      },
+	{       XFER_UDMA_4,    0x14886231      },
+	{       XFER_UDMA_3,    0x148c6231      },
+	{       XFER_UDMA_2,    0x148c6231      },
+	{       XFER_UDMA_1,    0x14906231      },
+	{       XFER_UDMA_0,    0x14986231      },
+	
+	{       XFER_MW_DMA_2,  0x26514e21      },
+	{       XFER_MW_DMA_1,  0x26514e33      },
+	{       XFER_MW_DMA_0,  0x26514e97      },
+	
+	{       XFER_PIO_4,     0x06514e21      },
+	{       XFER_PIO_3,     0x06514e22      },
+	{       XFER_PIO_2,     0x06514e33      },
+	{       XFER_PIO_1,     0x06914e43      },
+	{       XFER_PIO_0,     0x06914e57      },
+	{       0,              0x06514e57      }
+};
+
+/* these are the current (4 sep 2001) timings from highpoint */
+struct chipset_bus_clock_list_entry thirty_three_base_hpt370a[] = {
+        {       XFER_UDMA_5,    0x12446231      },
+        {       XFER_UDMA_4,    0x12446231      },
+        {       XFER_UDMA_3,    0x126c6231      },
+        {       XFER_UDMA_2,    0x12486231      },
+        {       XFER_UDMA_1,    0x124c6233      },
+        {       XFER_UDMA_0,    0x12506297      },
+
+        {       XFER_MW_DMA_2,  0x22406c31      },
+        {       XFER_MW_DMA_1,  0x22406c33      },
+        {       XFER_MW_DMA_0,  0x22406c97      },
+
+        {       XFER_PIO_4,     0x06414e31      },
+        {       XFER_PIO_3,     0x06414e42      },
+        {       XFER_PIO_2,     0x06414e53      },
+        {       XFER_PIO_1,     0x06814e93      },
+        {       XFER_PIO_0,     0x06814ea7      },
+        {       0,              0x06814ea7      }
+};
+
+/* 2x 33MHz timings */
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370a[] = {
+	{       XFER_UDMA_5,    0x1488e673       },
+	{       XFER_UDMA_4,    0x1488e673       },
+	{       XFER_UDMA_3,    0x1498e673       },
+	{       XFER_UDMA_2,    0x1490e673       },
+	{       XFER_UDMA_1,    0x1498e677       },
+	{       XFER_UDMA_0,    0x14a0e73f       },
+
+	{       XFER_MW_DMA_2,  0x2480fa73       },
+	{       XFER_MW_DMA_1,  0x2480fa77       }, 
+	{       XFER_MW_DMA_0,  0x2480fb3f       },
+
+	{       XFER_PIO_4,     0x0c82be73       },
+	{       XFER_PIO_3,     0x0c82be95       },
+	{       XFER_PIO_2,     0x0c82beb7       },
+	{       XFER_PIO_1,     0x0d02bf37       },
+	{       XFER_PIO_0,     0x0d02bf5f       },
+	{       0,              0x0d02bf5f       }
+};
+
+struct chipset_bus_clock_list_entry fifty_base_hpt370a[] = {
+	{       XFER_UDMA_5,    0x12848242      },
+	{       XFER_UDMA_4,    0x12ac8242      },
+	{       XFER_UDMA_3,    0x128c8242      },
+	{       XFER_UDMA_2,    0x120c8242      },
+	{       XFER_UDMA_1,    0x12148254      },
+	{       XFER_UDMA_0,    0x121882ea      },
+
+	{       XFER_MW_DMA_2,  0x22808242      },
+	{       XFER_MW_DMA_1,  0x22808254      },
+	{       XFER_MW_DMA_0,  0x228082ea      },
+
+	{       XFER_PIO_4,     0x0a81f442      },
+	{       XFER_PIO_3,     0x0a81f443      },
+	{       XFER_PIO_2,     0x0a81f454      },
+	{       XFER_PIO_1,     0x0ac1f465      },
+	{       XFER_PIO_0,     0x0ac1f48a      },
+	{       0,              0x0ac1f48a      }
+};
+
+struct chipset_bus_clock_list_entry thirty_three_base_hpt372[] = {
+	{	XFER_UDMA_6,	0x1c81dc62	},
+	{	XFER_UDMA_5,	0x1c6ddc62	},
+	{	XFER_UDMA_4,	0x1c8ddc62	},
+	{	XFER_UDMA_3,	0x1c8edc62	},	/* checkme */
+	{	XFER_UDMA_2,	0x1c91dc62	},
+	{	XFER_UDMA_1,	0x1c9adc62	},	/* checkme */
+	{	XFER_UDMA_0,	0x1c82dc62	},	/* checkme */
+
+	{	XFER_MW_DMA_2,	0x2c829262	},
+	{	XFER_MW_DMA_1,	0x2c829266	},	/* checkme */
+	{	XFER_MW_DMA_0,	0x2c82922e	},	/* checkme */
+
+	{	XFER_PIO_4,	0x0c829c62	},
+	{	XFER_PIO_3,	0x0c829c84	},
+	{	XFER_PIO_2,	0x0c829ca6	},
+	{	XFER_PIO_1,	0x0d029d26	},
+	{	XFER_PIO_0,	0x0d029d5e	},
+	{	0,		0x0d029d5e	}
+};
+
+struct chipset_bus_clock_list_entry fifty_base_hpt372[] = {
+	{	XFER_UDMA_5,	0x12848242	},
+	{	XFER_UDMA_4,	0x12ac8242	},
+	{	XFER_UDMA_3,	0x128c8242	},
+	{	XFER_UDMA_2,	0x120c8242	},
+	{	XFER_UDMA_1,	0x12148254	},
+	{	XFER_UDMA_0,	0x121882ea	},
+
+	{	XFER_MW_DMA_2,	0x22808242	},
+	{	XFER_MW_DMA_1,	0x22808254	},
+	{	XFER_MW_DMA_0,	0x228082ea	},
+
+	{	XFER_PIO_4,	0x0a81f442	},
+	{	XFER_PIO_3,	0x0a81f443	},
+	{	XFER_PIO_2,	0x0a81f454	},
+	{	XFER_PIO_1,	0x0ac1f465	},
+	{	XFER_PIO_0,	0x0ac1f48a	},
+	{	0,		0x0a81f443	}
+};
+
+struct chipset_bus_clock_list_entry sixty_six_base_hpt372[] = {
+	{	XFER_UDMA_6,	0x1c869c62	},
+	{	XFER_UDMA_5,	0x1cae9c62	},
+	{	XFER_UDMA_4,	0x1c8a9c62	},
+	{	XFER_UDMA_3,	0x1c8e9c62	},
+	{	XFER_UDMA_2,	0x1c929c62	},
+	{	XFER_UDMA_1,	0x1c9a9c62	},
+	{	XFER_UDMA_0,	0x1c829c62	},
+
+	{	XFER_MW_DMA_2,	0x2c829c62	},
+	{	XFER_MW_DMA_1,	0x2c829c66	},
+	{	XFER_MW_DMA_0,	0x2c829d2e	},
+
+	{	XFER_PIO_4,	0x0c829c62	},
+	{	XFER_PIO_3,	0x0c829c84	},
+	{	XFER_PIO_2,	0x0c829ca6	},
+	{	XFER_PIO_1,	0x0d029d26	},
+	{	XFER_PIO_0,	0x0d029d5e	},
+	{	0,		0x0d029d26	}
+};
+
+struct chipset_bus_clock_list_entry thirty_three_base_hpt374[] = {
+	{	XFER_UDMA_6,	0x12808242	},
+	{	XFER_UDMA_5,	0x12848242	},
+	{	XFER_UDMA_4,	0x12ac8242	},
+	{	XFER_UDMA_3,	0x128c8242	},
+	{	XFER_UDMA_2,	0x120c8242	},
+	{	XFER_UDMA_1,	0x12148254	},
+	{	XFER_UDMA_0,	0x121882ea	},
+
+	{	XFER_MW_DMA_2,	0x22808242	},
+	{	XFER_MW_DMA_1,	0x22808254	},
+	{	XFER_MW_DMA_0,	0x228082ea	},
+
+	{	XFER_PIO_4,	0x0a81f442	},
+	{	XFER_PIO_3,	0x0a81f443	},
+	{	XFER_PIO_2,	0x0a81f454	},
+	{	XFER_PIO_1,	0x0ac1f465	},
+	{	XFER_PIO_0,	0x0ac1f48a	},
+	{	0,		0x06814e93	}
+};
+
+#if 0
+struct chipset_bus_clock_list_entry fifty_base_hpt374[] = {
+	{	XFER_UDMA_6,	},
+	{	XFER_UDMA_5,	},
+	{	XFER_UDMA_4,	},
+	{	XFER_UDMA_3,	},
+	{	XFER_UDMA_2,	},
+	{	XFER_UDMA_1,	},
+	{	XFER_UDMA_0,	},
+	{	XFER_MW_DMA_2,	},
+	{	XFER_MW_DMA_1,	},
+	{	XFER_MW_DMA_0,	},
+	{	XFER_PIO_4,	},
+	{	XFER_PIO_3,	},
+	{	XFER_PIO_2,	},
+	{	XFER_PIO_1,	},
+	{	XFER_PIO_0,	},
+	{	0,	}
+};
+#endif
+#if 0
+struct chipset_bus_clock_list_entry sixty_six_base_hpt374[] = {
+	{	XFER_UDMA_6,	0x12406231	},	/* checkme */
+	{	XFER_UDMA_5,	0x12446231	},
+				0x14846231
+	{	XFER_UDMA_4,		0x16814ea7	},
+				0x14886231
+	{	XFER_UDMA_3,		0x16814ea7	},
+				0x148c6231
+	{	XFER_UDMA_2,		0x16814ea7	},
+				0x148c6231
+	{	XFER_UDMA_1,		0x16814ea7	},
+				0x14906231
+	{	XFER_UDMA_0,		0x16814ea7	},
+				0x14986231
+	{	XFER_MW_DMA_2,		0x16814ea7	},
+				0x26514e21
+	{	XFER_MW_DMA_1,		0x16814ea7	},
+				0x26514e97
+	{	XFER_MW_DMA_0,		0x16814ea7	},
+				0x26514e97
+	{	XFER_PIO_4,		0x06814ea7	},
+				0x06514e21
+	{	XFER_PIO_3,		0x06814ea7	},
+				0x06514e22
+	{	XFER_PIO_2,		0x06814ea7	},
+				0x06514e33
+	{	XFER_PIO_1,		0x06814ea7	},
+				0x06914e43
+	{	XFER_PIO_0,		0x06814ea7	},
+				0x06914e57
+	{	0,		0x06814ea7	}
+};
+#endif
+
+#define HPT366_DEBUG_DRIVE_INFO		0
+#define HPT374_ALLOW_ATA133_6		0
+#define HPT371_ALLOW_ATA133_6		0
+#define HPT302_ALLOW_ATA133_6		0
+#define HPT372_ALLOW_ATA133_6		1
+#define HPT370_ALLOW_ATA100_5		1
+#define HPT366_ALLOW_ATA66_4		1
+#define HPT366_ALLOW_ATA66_3		1
+#define HPT366_MAX_DEVS			8
+
+#define F_LOW_PCI_33      0x23
+#define F_LOW_PCI_40      0x29
+#define F_LOW_PCI_50      0x2d
+#define F_LOW_PCI_66      0x42
+
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 hpt366_proc;
+
+static int hpt366_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t hpt366_procs[] __initdata = {
+	{
+		.name		= "hpt366",
+		.set		= 1,
+		.get_info	= hpt366_get_info,
+		.parent		= NULL,
+	},
+};
+#endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_hpt366(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_hpt37x(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_hpt374(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_hpt366(struct pci_dev *, const char *);
+static void init_hwif_hpt366(ide_hwif_t *);
+static void init_dma_hpt366(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT366,
+		.name		= "HPT366",
+		.init_setup	= init_setup_hpt366,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 240
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT372,
+		.name		= "HPT372A",
+		.init_setup	= init_setup_hpt37x,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT302,
+		.name		= "HPT302",
+		.init_setup	= init_setup_hpt37x,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT371,
+		.name		= "HPT371",
+		.init_setup	= init_setup_hpt37x,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
+	},{	/* 4 */
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT374,
+		.name		= "HPT374",
+		.init_setup	= init_setup_hpt374,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,	/* 4 */
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* HPT366_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/it8172.c linux-2.4.21/drivers/ide/pci/it8172.c
--- linux-2.4.20/drivers/ide/pci/it8172.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/it8172.c	2002-12-18 18:58:02.000000000 +0000
@@ -0,0 +1,334 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *      IT8172 IDE controller support
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *              stevel@mvista.com or source@mvista.com
+ *
+ *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/it8172/it8172_int.h>
+
+#include "ide_modes.h"
+#include "it8172.h"
+
+/*
+ * Prototypes
+ */
+static u8 it8172_ratemask (ide_drive_t *drive)
+{
+	return 1;
+}
+
+static void it8172_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	int is_slave		= (hwif->drives[1] == drive);
+	unsigned long flags;
+	u16 drive_enables;
+	u32 drive_timing;
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	spin_lock_irqsave(&ide_lock, flags);
+	pci_read_config_word(dev, 0x40, &drive_enables);
+	pci_read_config_dword(dev, 0x44, &drive_timing);
+
+	/*
+	 * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44
+	 * are being left at the default values of 8 PCI clocks (242 nsec
+	 * for a 33 MHz clock). These can be safely shortened at higher
+	 * PIO modes. The DIOR/DIOW pulse width and recovery times only
+	 * apply to PIO modes, not to the DMA modes.
+	 */
+
+	/*
+	 * Enable port 0x44. The IT8172G spec is confused; it calls
+	 * this register the "Slave IDE Timing Register", but in fact,
+	 * it controls timing for both master and slave drives.
+	 */
+	drive_enables |= 0x4000;
+
+	if (is_slave) {
+		drive_enables &= 0xc006;
+		if (pio > 1)
+			/* enable prefetch and IORDY sample-point */
+			drive_enables |= 0x0060;
+	} else {
+		drive_enables &= 0xc060;
+		if (pio > 1)
+			/* enable prefetch and IORDY sample-point */
+			drive_enables |= 0x0006;
+	}
+
+	pci_write_config_word(dev, 0x40, drive_enables);
+	spin_unlock_irqrestore(&ide_lock, flags)
+}
+
+static u8 it8172_dma_2_pio (u8 xfer_rate)
+{
+	switch(xfer_rate) {
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:
+		case XFER_PIO_4:
+			return 4;
+		case XFER_MW_DMA_1:
+		case XFER_PIO_3:
+			return 3;
+		case XFER_SW_DMA_2:
+		case XFER_PIO_2:
+			return 2;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+		case XFER_PIO_SLOW:
+		default:
+			return 0;
+	}
+}
+
+static int it8172_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed	= ide_rate_filter(it8172_ratemask(drive), xferspeed);
+	int a_speed		= 3 << (drive->dn * 4);
+	int u_flag		= 1 << drive->dn;
+	int u_speed		= 0;
+	u8 reg48, reg4a;
+
+	pci_read_config_byte(dev, 0x48, &reg48);
+	pci_read_config_byte(dev, 0x4a, &reg4a);
+
+    /*
+     * Setting the DMA cycle time to 2 or 3 PCI clocks (60 and 91 nsec
+     * at 33 MHz PCI clock) seems to cause BadCRC errors during DMA
+     * transfers on some drives, even though both numbers meet the minimum
+     * ATAPI-4 spec of 73 and 54 nsec for UDMA 1 and 2 respectively.
+     * So the faster times are just commented out here. The good news is
+     * that the slower cycle time has very little affect on transfer
+     * performance.
+     */
+    
+	switch(speed) {
+		case XFER_UDMA_4:
+		case XFER_UDMA_2:	//u_speed = 2 << (drive->dn * 4); break;
+		case XFER_UDMA_5:
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	//u_speed = 1 << (drive->dn * 4); break;
+		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_2:	break;
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_0:	break;
+		default:		return -1;
+	}
+
+	if (speed >= XFER_UDMA_0) {
+		pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+		reg4a &= ~a_speed;
+		pci_write_config_byte(dev, 0x4a, reg4a | u_speed);
+	} else {
+		pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
+		pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed);
+	}
+
+	it8172_tune_drive(drive, it8172_dma_2_pio(speed));
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static int it8172_config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, it8172_ratemask(drive));
+
+	if (!(speed)) {
+		u8 tspeed = ide_get_best_pio_mode(drive, 255, 4, NULL);
+		speed = it8172_dma_2_pio(XFER_PIO_0 + tspeed);
+	}
+
+	(void) it8172_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int it8172_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = it8172_config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!it8172_config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!it8172_config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		it8172_tune_drive(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static unsigned int __init init_chipset_it8172 (struct pci_dev *dev, const char *name)
+{
+	unsigned char progif;
+    
+	/*
+	 * Place both IDE interfaces into PCI "native" mode
+	 */
+	pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
+	pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05);    
+
+	return IT8172_IDE_IRQ;
+}
+
+
+static void __init init_hwif_it8172 (ide_hwif_t *hwif)
+{
+	struct pci_dev* dev = hwif->pci_dev;
+	unsigned long cmdBase, ctrlBase;
+    
+	hwif->autodma = 0;
+	hwif->tuneproc = &it8172_tune_drive;
+	hwif->speedproc = &it8172_tune_chipset;
+
+	cmdBase = dev->resource[0].start;
+	ctrlBase = dev->resource[1].start;
+    
+	ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL);
+	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+	hwif->noprobe = 0;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x07;
+	hwif->mwdma_mask = 0x06;
+	hwif->swdma_mask = 0x04;
+
+	hwif->ide_dma_check = &it8172_config_drive_xfer_rate;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_it8172 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit it8172_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &it8172_chipsets[id->driver_data];
+        if ((!(PCI_FUNC(dev->devfn) & 1) ||
+            (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))))
+                return 1; /* IT8172 is more than only a IDE controller */
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id it8172_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "IT8172IDE",
+	.id_table	= it8172_pci_tbl,
+	.probe		= it8172_init_one,
+};
+
+static int it8172_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void it8172_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(it8172_ide_init);
+module_exit(it8172_ide_exit);
+
+MODULE_AUTHOR("SteveL@mvista.com");
+MODULE_DESCRIPTION("PCI driver module for ITE 8172 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/it8172.h linux-2.4.21/drivers/ide/pci/it8172.h
--- linux-2.4.20/drivers/ide/pci/it8172.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/it8172.h	2002-12-18 18:58:04.000000000 +0000
@@ -0,0 +1,45 @@
+#ifndef ITE8172G_H
+#define ITE8172G_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static u8 it8172_ratemask(ide_drive_t *drive);
+static u8 it8172_ratefilter(ide_drive_t *drive, u8 speed);
+static void it8172_tune_drive(ide_drive_t *drive, u8 pio);
+static u8 it8172_dma_2_pio(u8 xfer_rate);
+static int it8172_tune_chipset(ide_drive_t *drive, u8 xferspeed);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int it8172_config_chipset_for_dma(ide_drive_t *drive);
+#endif
+
+static void init_setup_it8172(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_it8172(struct pci_dev *, const char *);
+static void init_hwif_it8172(ide_hwif_t *);
+static void init_dma_it8172(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t it8172_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_ITE,
+		.device		= PCI_DEVICE_ID_ITE_IT8172G,
+		.name		= "IT8172G",
+		.init_setup	= init_setup_it8172,
+		.init_chipset	= init_chipset_it8172,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_it8172,
+                .init_dma	= init_dma_it8172,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x40,0x00,0x01}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* ITE8172G_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/ns87415.c linux-2.4.21/drivers/ide/pci/ns87415.c
--- linux-2.4.20/drivers/ide/pci/ns87415.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/ns87415.c	2002-12-18 18:58:06.000000000 +0000
@@ -0,0 +1,267 @@
+/*
+ * linux/drivers/ide/ns87415.c		Version 2.00  Sep. 10, 2002
+ *
+ * Copyright (C) 1997-1998	Mark Lord <mlord@pobox.com>
+ * Copyright (C) 1998		Eddie C. Dost <ecd@skynet.be>
+ * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
+ *
+ * Inspired by an earlier effort from David S. Miller <davem@redhat.com>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ns87415.h"
+
+static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
+
+/*
+ * This routine either enables/disables (according to drive->present)
+ * the IRQ associated with the port (HWIF(drive)),
+ * and selects either PIO or DMA handshaking for the next I/O operation.
+ */
+static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data;
+	struct pci_dev *dev = hwif->pci_dev;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	new = *old;
+
+	/* Adjust IRQ enable bit */
+	bit = 1 << (8 + hwif->channel);
+	new = drive->present ? (new & ~bit) : (new | bit);
+
+	/* Select PIO or DMA, DMA may only be selected for one drive/channel. */
+	bit   = 1 << (20 + drive->select.b.unit       + (hwif->channel << 1));
+	other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->channel << 1));
+	new = use_dma ? ((new & ~other) | bit) : (new & ~bit);
+
+	if (new != *old) {
+		unsigned char stat;
+
+		/*
+		 * Don't change DMA engine settings while Write Buffers
+		 * are busy.
+		 */
+		(void) pci_read_config_byte(dev, 0x43, &stat);
+		while (stat & 0x03) {
+			udelay(1);
+			(void) pci_read_config_byte(dev, 0x43, &stat);
+		}
+
+		*old = new;
+		(void) pci_write_config_dword(dev, 0x40, new);
+
+		/*
+		 * And let things settle...
+		 */
+		udelay(10);
+	}
+
+	local_irq_restore(flags);
+}
+
+static void ns87415_selectproc (ide_drive_t *drive)
+{
+	ns87415_prepare_drive (drive, drive->using_dma);
+}
+
+static int ns87415_ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t      *hwif = HWIF(drive);
+	u8 dma_stat = 0, dma_cmd = 0;
+
+	drive->waiting_for_dma = 0;
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* get dma command mode */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop DMA */
+	hwif->OUTB(dma_cmd & ~1, hwif->dma_command);
+	/* from ERRATA: clear the INTR & ERROR bits */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	hwif->OUTB(dma_cmd|6, hwif->dma_command);
+	/* and free any DMA resources */
+	ide_destroy_dmatable(drive);
+	/* verify good DMA status */
+	return (dma_stat & 7) != 4;
+}
+
+static int ns87415_ide_dma_read (ide_drive_t *drive)
+{
+	/* select DMA xfer */
+	ns87415_prepare_drive(drive, 1);
+	if (!(__ide_dma_read(drive)))
+		return 0;
+	/* DMA failed: select PIO xfer */
+	ns87415_prepare_drive(drive, 0);
+	return 1;
+}
+
+static int ns87415_ide_dma_write (ide_drive_t *drive)
+{
+	/* select DMA xfer */
+	ns87415_prepare_drive(drive, 1);
+	if (!(__ide_dma_write(drive)))
+		return 0;
+	/* DMA failed: select PIO xfer */
+	ns87415_prepare_drive(drive, 0);
+	return 1;
+}
+
+static int ns87415_ide_dma_check (ide_drive_t *drive)
+{
+	if (drive->media != ide_disk)
+		return HWIF(drive)->ide_dma_off_quietly(drive);
+	return __ide_dma_check(drive);
+}
+
+static void __init init_hwif_ns87415 (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+	unsigned int ctrl, using_inta;
+	u8 progif;
+#ifdef __sparc_v9__
+	int timeout;
+	u8 stat;
+#endif
+
+	hwif->autodma = 0;
+	hwif->selectproc = &ns87415_selectproc;
+
+	/* Set a good latency timer and cache line size value. */
+	(void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+#ifdef __sparc_v9__
+	(void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10);
+#endif
+
+	/*
+	 * We cannot probe for IRQ: both ports share common IRQ on INTA.
+	 * Also, leave IRQ masked during drive probing, to prevent infinite
+	 * interrupts from a potentially floating INTA..
+	 *
+	 * IRQs get unmasked in selectproc when drive is first used.
+	 */
+	(void) pci_read_config_dword(dev, 0x40, &ctrl);
+	(void) pci_read_config_byte(dev, 0x09, &progif);
+	/* is irq in "native" mode? */
+	using_inta = progif & (1 << (hwif->channel << 1));
+	if (!using_inta)
+		using_inta = ctrl & (1 << (4 + hwif->channel));
+	if (hwif->mate) {
+		hwif->select_data = hwif->mate->select_data;
+	} else {
+		hwif->select_data = (unsigned long)
+					&ns87415_control[ns87415_count++];
+		ctrl |= (1 << 8) | (1 << 9);	/* mask both IRQs */
+		if (using_inta)
+			ctrl &= ~(1 << 6);	/* unmask INTA */
+		*((unsigned int *)hwif->select_data) = ctrl;
+		(void) pci_write_config_dword(dev, 0x40, ctrl);
+
+		/*
+		 * Set prefetch size to 512 bytes for both ports,
+		 * but don't turn on/off prefetching here.
+		 */
+		pci_write_config_byte(dev, 0x55, 0xee);
+
+#ifdef __sparc_v9__
+		/*
+		 * XXX: Reset the device, if we don't it will not respond
+		 *      to SELECT_DRIVE() properly during first probe_hwif().
+		 */
+		timeout = 10000;
+		hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		udelay(10);
+		hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		do {
+			udelay(50);
+			stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+                	if (stat == 0xff)
+                        	break;
+        	} while ((stat & BUSY_STAT) && --timeout);
+#endif
+	}
+
+	if (!using_inta)
+		hwif->irq = hwif->channel ? 15 : 14;	/* legacy mode */
+	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+		hwif->irq = hwif->mate->irq;	/* share IRQ with mate */
+
+	if (!hwif->dma_base)
+		return;
+
+	hwif->OUTB(0x60, hwif->dma_status);
+	hwif->ide_dma_read = &ns87415_ide_dma_read;
+	hwif->ide_dma_write = &ns87415_ide_dma_write;
+	hwif->ide_dma_check = &ns87415_ide_dma_check;
+	hwif->ide_dma_end = &ns87415_ide_dma_end;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_ns87415 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit ns87415_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &ns87415_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id ns87415_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "NS87415IDE",
+	.id_table	= ns87415_pci_tbl,
+	.probe		= ns87415_init_one,
+};
+
+static int ns87415_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void ns87415_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(ns87415_ide_init);
+module_exit(ns87415_ide_exit);
+
+MODULE_AUTHOR("Mark Lord, Eddie Dost, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for NS87415 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/ns87415.h linux-2.4.21/drivers/ide/pci/ns87415.h
--- linux-2.4.20/drivers/ide/pci/ns87415.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/ns87415.h	2002-12-18 18:58:09.000000000 +0000
@@ -0,0 +1,33 @@
+#ifndef NS87415_H
+#define NS87415_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static void init_hwif_ns87415(ide_hwif_t *);
+static void init_dma_ns87415(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t ns87415_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_NS,
+		.device		= PCI_DEVICE_ID_NS_87415,
+		.name		= "NS87415",
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_ns87415,
+                .init_dma	= init_dma_ns87415,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* NS87415_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/nvidia.c linux-2.4.21/drivers/ide/pci/nvidia.c
--- linux-2.4.20/drivers/ide/pci/nvidia.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/nvidia.c	2002-12-18 18:58:09.000000000 +0000
@@ -0,0 +1,370 @@
+/*
+ * linux/drivers/ide/nvidia.c		Version 0.01
+ *
+ * Copyright (C) 2002-2002		Andre Hedrick <andre@linux-ide.org>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "nvidia.h"
+
+#if defined(DISPLAY_NFORCE_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 nforce_proc = 0;
+static struct pci_dev *bmide_dev;
+
+static int nforce_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	u32 bibma = pci_resource_start(bmide_dev, 4);
+	u8 c0 = 0, c1 = 0;
+
+	/*
+	 * 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);
+
+	p += sprintf(p, "\n                                "
+			"nVidia %04X Chipset.\n", bmide_dev->device);
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled "
+			"                        %sabled\n",
+			(c0&0x80) ? "dis" : " en",
+			(c1&0x80) ? "dis" : " en");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	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 " );
+	p += sprintf(p, "UDMA\n");
+	p += sprintf(p, "DMA\n");
+	p += sprintf(p, "PIO\n");
+
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_NFORCE_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u8 nforce_ratemask (ide_drive_t *drive)
+{
+	u8 mode;
+
+        switch(HWIF(drive)->pci_dev->device) {
+		case PCI_DEVICE_ID_NVIDIA_NFORCE_IDE:
+			mode = 3;
+			break;
+		default:
+			return 0;
+	}
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+/*
+ * Here is where all the hard work goes to program the chipset.
+ */
+static int nforce_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	static const u8 drive_pci[] = { 0x63, 0x62, 0x61, 0x60 };
+	static const u8 drive_pci2[] = { 0x5b, 0x5a, 0x59, 0x58 };
+
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed	= ide_rate_filter(nforce_ratemask(drive), xferspeed);
+	u8 ultra_timing	= 0, dma_pio_timing = 0, pio_timing = 0;
+
+	pci_read_config_byte(dev, drive_pci[drive->dn], &ultra_timing);
+	pci_read_config_byte(dev, drive_pci2[drive->dn], &dma_pio_timing);
+	pci_read_config_byte(dev, 0x5c, &pio_timing);
+
+	ultra_timing	&= ~0xC7;
+	dma_pio_timing	&= ~0xFF;
+	pio_timing	&= ~(0x03 << drive->dn);
+
+	switch(speed) {
+		case XFER_UDMA_7:
+		case XFER_UDMA_6:
+			speed = XFER_UDMA_5;
+		case XFER_UDMA_5:
+			ultra_timing |= 0x46;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_4:
+			ultra_timing |= 0x45;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_3:
+			ultra_timing |= 0x44;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_2:
+			ultra_timing |= 0x40;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_1:
+			ultra_timing |= 0x41;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_0:
+			ultra_timing |= 0x42;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_MW_DMA_2:
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_MW_DMA_1:
+			dma_pio_timing |= 0x21;
+			break;
+		case XFER_MW_DMA_0:
+			dma_pio_timing |= 0x77;
+			break;
+		case XFER_SW_DMA_2:
+			dma_pio_timing |= 0x42;
+			break;
+		case XFER_SW_DMA_1:
+			dma_pio_timing |= 0x65;
+			break;
+		case XFER_SW_DMA_0:
+			dma_pio_timing |= 0xA8;
+			break;
+		case XFER_PIO_4:
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_PIO_3:
+			dma_pio_timing |= 0x22;
+			break;
+		case XFER_PIO_2:
+			dma_pio_timing |= 0x42;
+			break;
+		case XFER_PIO_1:
+			dma_pio_timing |= 0x65;
+			break;
+		case XFER_PIO_0:
+		default:
+			dma_pio_timing |= 0xA8;
+			break;
+        }
+
+	pio_timing |= (0x03 << drive->dn);
+
+	pci_write_config_byte(dev, drive_pci[drive->dn], ultra_timing);
+	pci_write_config_byte(dev, drive_pci2[drive->dn], dma_pio_timing);
+	pci_write_config_byte(dev, 0x5c, pio_timing);
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static void nforce_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	(void) nforce_tune_chipset(drive, (XFER_PIO_0 + pio));
+}
+
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, nforce_ratemask(drive));
+
+	if (!(speed))
+		return 0;
+
+	(void) nforce_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int nforce_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		nforce_tune_drive(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static unsigned int __init init_chipset_nforce (struct pci_dev *dev, const char *name)
+{
+#if defined(DISPLAY_NFORCE_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!nforce_proc) {
+		nforce_proc = 1;
+		bmide_dev = dev;
+		ide_pci_register_host_proc(&nforce_procs[0]);
+	}
+#endif /* DISPLAY_NFORCE_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+static unsigned int __init ata66_nforce (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 cable_80_pin[2]	= { 0, 0 };
+	u8 ata66		= 0;
+	u8 tmpbyte;
+
+	/*
+	 * Ultra66 cable detection (from Host View)
+	 * 7411, 7441, 0x52, bit0: primary, bit2: secondary 80 pin
+	 */
+	pci_read_config_byte(dev, 0x52, &tmpbyte);
+
+	/*
+	 * 0x52, bit0 is 1 => primary channel
+	 * has 80-pin (from host view)
+	 */
+	if (tmpbyte & 0x01) cable_80_pin[0] = 1;
+
+	/*
+	 * 0x52, bit2 is 1 => secondary channel
+	 * has 80-pin (from host view)
+	 */
+	if (tmpbyte & 0x04) cable_80_pin[1] = 1;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_NVIDIA_NFORCE_IDE:
+			ata66 = (hwif->channel) ?
+				cable_80_pin[1] :
+				cable_80_pin[0];
+		default:
+			break;
+	}
+	return (unsigned int) ata66;
+}
+
+static void __init init_hwif_nforce (ide_hwif_t *hwif)
+{
+	hwif->tuneproc = &nforce_tune_drive;
+	hwif->speedproc = &nforce_tune_chipset;
+	hwif->autodma = 0;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66_nforce(hwif);
+	hwif->ide_dma_check = &nforce_config_drive_xfer_rate;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+/* FIXME - not needed */
+static void __init init_dma_nforce (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit nforce_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &nvidia_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id nforce_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "nForce IDE",
+	.id_table	= nforce_pci_tbl,
+	.probe		= nforce_init_one,
+};
+
+static int nforce_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void nforce_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(nforce_ide_init);
+module_exit(nforce_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for nVidia nForce IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/nvidia.h linux-2.4.21/drivers/ide/pci/nvidia.h
--- linux-2.4.20/drivers/ide/pci/nvidia.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/nvidia.h	2002-12-18 18:58:11.000000000 +0000
@@ -0,0 +1,50 @@
+#ifndef NFORCE_H
+#define NFORCE_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_NFORCE_TIMINGS
+
+#if defined(DISPLAY_NFORCE_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 nforce_proc;
+
+static int nforce_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t nforce_procs[] __initdata = {
+	{
+		name:		"nforce",
+		set:		1,
+		get_info:	nforce_get_info,
+		parent:		NULL,
+	},
+};
+#endif  /* defined(DISPLAY_NFORCE_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static unsigned int init_chipset_nforce(struct pci_dev *, const char *);
+static void init_hwif_nforce(ide_hwif_t *);
+static void init_dma_nforce(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t nvidia_chipsets[] __devinitdata = {
+	{
+		vendor:		PCI_VENDOR_ID_NVIDIA,
+		device:		PCI_DEVICE_ID_NVIDIA_NFORCE_IDE,
+		name:		"NFORCE",
+		init_chipset:	init_chipset_nforce,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_nforce,
+		init_dma:	init_dma_nforce,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x50,0x01,0x01}, {0x50,0x02,0x02}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	}
+};
+
+
+#endif /* NFORCE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/opti621.c linux-2.4.21/drivers/ide/pci/opti621.c
--- linux-2.4.20/drivers/ide/pci/opti621.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/opti621.c	2002-12-18 18:58:03.000000000 +0000
@@ -0,0 +1,403 @@
+/*
+ *  linux/drivers/ide/opti621.c		Version 0.7	Sept 10, 2002
+ *
+ *  Copyright (C) 1996-1998  Linus Torvalds & authors (see below)
+ */
+
+/*
+ * Authors:
+ * Jaromir Koutek <miri@punknet.cz>,
+ * Jan Harkes <jaharkes@cwi.nl>,
+ * Mark Lord <mlord@pobox.com>
+ * Some parts of code are from ali14xx.c and from rz1000.c.
+ *
+ * OPTi is trademark of OPTi, Octek is trademark of Octek.
+ *
+ * I used docs from OPTi databook, from ftp.opti.com, file 9123-0002.ps
+ * and disassembled/traced setupvic.exe (DOS program).
+ * It increases kernel code about 2 kB.
+ * I don't have this card no more, but I hope I can get some in case
+ * of needed development.
+ * My card is Octek PIDE 1.01 (on card) or OPTiViC (program).
+ * It has a place for a secondary connector in circuit, but nothing
+ * is there. Also BIOS says no address for
+ * secondary controller (see bellow in ide_init_opti621).
+ * I've only tested this on my system, which only has one disk.
+ * It's Western Digital WDAC2850, with PIO mode 3. The PCI bus
+ * is at 20 MHz (I have DX2/80, I tried PCI at 40, but I got random
+ * lockups). I tried the OCTEK double speed CD-ROM and
+ * it does not work! But I can't boot DOS also, so it's probably
+ * hardware fault. I have connected Conner 80MB, the Seagate 850MB (no
+ * problems) and Seagate 1GB (as slave, WD as master). My experiences
+ * with the third, 1GB drive: I got 3MB/s (hdparm), but sometimes
+ * it slows to about 100kB/s! I don't know why and I have
+ * not this drive now, so I can't try it again.
+ * I write this driver because I lost the paper ("manual") with
+ * settings of jumpers on the card and I have to boot Linux with
+ * Loadlin except LILO, cause I have to run the setupvic.exe program
+ * already or I get disk errors (my test: rpm -Vf
+ * /usr/X11R6/bin/XF86_SVGA - or any big file).
+ * Some numbers from hdparm -t /dev/hda:
+ * Timing buffer-cache reads:   32 MB in  3.02 seconds =10.60 MB/sec
+ * Timing buffered disk reads:  16 MB in  5.52 seconds = 2.90 MB/sec
+ * I have 4 Megs/s before, but I don't know why (maybe changes
+ * in hdparm test).
+ * After release of 0.1, I got some successful reports, so it might work.
+ *
+ * The main problem with OPTi is that some timings for master
+ * and slave must be the same. For example, if you have master
+ * PIO 3 and slave PIO 0, driver have to set some timings of
+ * master for PIO 0. Second problem is that opti621_tune_drive
+ * got only one drive to set, but have to set both drives.
+ * This is solved in compute_pios. If you don't set
+ * the second drive, compute_pios use ide_get_best_pio_mode
+ * for autoselect mode (you can change it to PIO 0, if you want).
+ * If you then set the second drive to another PIO, the old value
+ * (automatically selected) will be overrided by yours.
+ * There is a 25/33MHz switch in configuration
+ * register, but driver is written for use at any frequency which get
+ * (use idebus=xx to select PCI bus speed).
+ * Use ide0=autotune for automatical tune of the PIO modes.
+ * If you get strange results, do not use this and set PIO manually
+ * by hdparm.
+ *
+ * Version 0.1, Nov 8, 1996
+ * by Jaromir Koutek, for 2.1.8. 
+ * Initial version of driver.
+ * 
+ * Version 0.2
+ * Number 0.2 skipped.
+ *
+ * Version 0.3, Nov 29, 1997
+ * by Mark Lord (probably), for 2.1.68
+ * Updates for use with new IDE block driver.
+ *
+ * Version 0.4, Dec 14, 1997
+ * by Jan Harkes
+ * Fixed some errors and cleaned the code.
+ *
+ * Version 0.5, Jan 2, 1998
+ * by Jaromir Koutek
+ * Updates for use with (again) new IDE block driver.
+ * Update of documentation.
+ * 
+ * Version 0.6, Jan 2, 1999
+ * by Jaromir Koutek
+ * Reversed to version 0.3 of the driver, because
+ * 0.5 doesn't work.
+ */
+
+#undef REALLY_SLOW_IO	/* most systems can safely undef this */
+#define OPTI621_DEBUG		/* define for debug messages */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "opti621.h"
+
+#define OPTI621_MAX_PIO 3
+/* In fact, I do not have any PIO 4 drive
+ * (address: 25 ns, data: 70 ns, recovery: 35 ns),
+ * but OPTi 82C621 is programmable and it can do (minimal values):
+ * on 40MHz PCI bus (pulse 25 ns):
+ *  address: 25 ns, data: 25 ns, recovery: 50 ns;
+ * on 20MHz PCI bus (pulse 50 ns):
+ *  address: 50 ns, data: 50 ns, recovery: 100 ns.
+ */
+
+/* #define READ_PREFETCH 0 */
+/* Uncommnent for disable read prefetch.
+ * There is some readprefetch capatibility in hdparm,
+ * but when I type hdparm -P 1 /dev/hda, I got errors
+ * and till reset drive is inaccessible.
+ * This (hw) read prefetch is safe on my drive.
+ */
+
+#ifndef READ_PREFETCH
+#define READ_PREFETCH 0x40 /* read prefetch is enabled */
+#endif /* else read prefetch is disabled */
+
+#define READ_REG 0	/* index of Read cycle timing register */
+#define WRITE_REG 1	/* index of Write cycle timing register */
+#define CNTRL_REG 3	/* index of Control register */
+#define STRAP_REG 5	/* index of Strap register */
+#define MISC_REG 6	/* index of Miscellaneous register */
+
+static int reg_base;
+
+#define PIO_NOT_EXIST 254
+#define PIO_DONT_KNOW 255
+
+/* there are stored pio numbers from other calls of opti621_tune_drive */
+static void compute_pios(ide_drive_t *drive, u8 pio)
+/* Store values into drive->drive_data
+ *	second_contr - 0 for primary controller, 1 for secondary
+ *	slave_drive - 0 -> pio is for master, 1 -> pio is for slave
+ *	pio - PIO mode for selected drive (for other we don't know)
+ */
+{
+	int d;
+	ide_hwif_t *hwif = HWIF(drive);
+
+	drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL);
+	for (d = 0; d < 2; ++d) {
+		drive = &hwif->drives[d];
+		if (drive->present) {
+			if (drive->drive_data == PIO_DONT_KNOW)
+				drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL);
+#ifdef OPTI621_DEBUG
+			printk("%s: Selected PIO mode %d\n",
+				drive->name, drive->drive_data);
+#endif
+		} else {
+			drive->drive_data = PIO_NOT_EXIST;
+		}
+	}
+}
+
+static int cmpt_clk(int time, int bus_speed)
+/* Returns (rounded up) time in clocks for time in ns,
+ * with bus_speed in MHz.
+ * Example: bus_speed = 40 MHz, time = 80 ns
+ * 1000/40 = 25 ns (clk value),
+ * 80/25 = 3.2, rounded up to 4 (I hope ;-)).
+ * Use idebus=xx to select right frequency.
+ */
+{
+	return ((time*bus_speed+999)/1000);
+}
+
+static void write_reg(ide_hwif_t *hwif, u8 value, int reg)
+/* Write value to register reg, base of register
+ * is at reg_base (0x1f0 primary, 0x170 secondary,
+ * if not changed by PCI configuration).
+ * This is from setupvic.exe program.
+ */
+{
+	hwif->INW(reg_base+1);
+	hwif->INW(reg_base+1);
+	hwif->OUTB(3, reg_base+2);
+	hwif->OUTB(value, reg_base+reg);
+	hwif->OUTB(0x83, reg_base+2);
+}
+
+static u8 read_reg(ide_hwif_t *hwif, int reg)
+/* Read value from register reg, base of register
+ * is at reg_base (0x1f0 primary, 0x170 secondary,
+ * if not changed by PCI configuration).
+ * This is from setupvic.exe program.
+ */
+{
+	u8 ret = 0;
+
+	hwif->INW(reg_base+1);
+	hwif->INW(reg_base+1);
+	hwif->OUTB(3, reg_base+2);
+	ret = hwif->INB(reg_base+reg);
+	hwif->OUTB(0x83, reg_base+2);
+	return ret;
+}
+
+typedef struct pio_clocks_s {
+	int	address_time;	/* Address setup (clocks) */
+	int	data_time;	/* Active/data pulse (clocks) */
+	int	recovery_time;	/* Recovery time (clocks) */
+} pio_clocks_t;
+
+static void compute_clocks(int pio, pio_clocks_t *clks)
+{
+        if (pio != PIO_NOT_EXIST) {
+        	int adr_setup, data_pls;
+		int bus_speed = system_bus_clock();
+
+ 	       	adr_setup = ide_pio_timings[pio].setup_time;
+  	      	data_pls = ide_pio_timings[pio].active_time;
+	  	clks->address_time = cmpt_clk(adr_setup, bus_speed);
+	     	clks->data_time = cmpt_clk(data_pls, bus_speed);
+     		clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time
+     			- adr_setup-data_pls, bus_speed);
+     		if (clks->address_time<1) clks->address_time = 1;
+     		if (clks->address_time>4) clks->address_time = 4;
+     		if (clks->data_time<1) clks->data_time = 1;
+     		if (clks->data_time>16) clks->data_time = 16;
+     		if (clks->recovery_time<2) clks->recovery_time = 2;
+     		if (clks->recovery_time>17) clks->recovery_time = 17;
+	} else {
+		clks->address_time = 1;
+		clks->data_time = 1;
+		clks->recovery_time = 2;
+		/* minimal values */
+	}
+ 
+}
+
+/* Main tune procedure, called from tuneproc. */
+static void opti621_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	/* primary and secondary drives share some registers,
+	 * so we have to program both drives
+	 */
+	unsigned long flags;
+	u8 pio1 = 0, pio2 = 0;
+	pio_clocks_t first, second;
+	int ax, drdy;
+	u8 cycle1, cycle2, misc;
+	ide_hwif_t *hwif = HWIF(drive);
+
+	/* sets drive->drive_data for both drives */
+	compute_pios(drive, pio);
+ 	pio1 = hwif->drives[0].drive_data;
+ 	pio2 = hwif->drives[1].drive_data;
+
+	compute_clocks(pio1, &first);
+	compute_clocks(pio2, &second);
+
+	/* ax = max(a1,a2) */
+	ax = (first.address_time < second.address_time) ? second.address_time : first.address_time;
+
+	drdy = 2; /* DRDY is default 2 (by OPTi Databook) */
+
+	cycle1 = ((first.data_time-1)<<4)  | (first.recovery_time-2);
+	cycle2 = ((second.data_time-1)<<4) | (second.recovery_time-2);
+	misc = READ_PREFETCH | ((ax-1)<<4) | ((drdy-2)<<1);
+
+#ifdef OPTI621_DEBUG
+	printk("%s: master: address: %d, data: %d, "
+		"recovery: %d, drdy: %d [clk]\n",
+		hwif->name, ax, first.data_time,
+		first.recovery_time, drdy);
+	printk("%s: slave:  address: %d, data: %d, "
+		"recovery: %d, drdy: %d [clk]\n",
+		hwif->name, ax, second.data_time,
+		second.recovery_time, drdy);
+#endif
+
+	spin_lock_irqsave(&ide_lock, flags);
+
+     	reg_base = hwif->io_ports[IDE_DATA_OFFSET];
+
+	/* allow Register-B */
+	hwif->OUTB(0xc0, reg_base+CNTRL_REG);
+	/* hmm, setupvic.exe does this ;-) */
+	hwif->OUTB(0xff, reg_base+5);
+	/* if reads 0xff, adapter not exist? */
+	(void) hwif->INB(reg_base+CNTRL_REG);
+	/* if reads 0xc0, no interface exist? */
+	read_reg(hwif, CNTRL_REG);
+	/* read version, probably 0 */
+	read_reg(hwif, STRAP_REG);
+
+	/* program primary drive */
+		/* select Index-0 for Register-A */
+	write_reg(hwif, 0,      MISC_REG);
+		/* set read cycle timings */
+	write_reg(hwif, cycle1, READ_REG);
+		/* set write cycle timings */
+	write_reg(hwif, cycle1, WRITE_REG);
+
+	/* program secondary drive */
+		/* select Index-1 for Register-B */
+	write_reg(hwif, 1,      MISC_REG);
+		/* set read cycle timings */
+	write_reg(hwif, cycle2, READ_REG);
+		/* set write cycle timings */
+	write_reg(hwif, cycle2, WRITE_REG);
+
+	/* use Register-A for drive 0 */
+	/* use Register-B for drive 1 */
+	write_reg(hwif, 0x85, CNTRL_REG);
+
+	/* set address setup, DRDY timings,   */
+	/*  and read prefetch for both drives */
+ 	write_reg(hwif, misc, MISC_REG);
+
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/*
+ * init_hwif_opti621() is called once for each hwif found at boot.
+ */
+static void __init init_hwif_opti621 (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->drives[0].drive_data = PIO_DONT_KNOW;
+	hwif->drives[1].drive_data = PIO_DONT_KNOW;
+	hwif->tuneproc = &opti621_tune_drive;
+
+	if (!(hwif->dma_base))
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_opti621 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_opti621 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+static int __devinit opti621_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &opti621_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id opti621_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "Opti621 IDE",
+	.id_table	= opti621_pci_tbl,
+	.probe		= opti621_init_one,
+};
+
+static int opti621_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void opti621_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(opti621_ide_init);
+module_exit(opti621_ide_exit);
+
+MODULE_AUTHOR("Jaromir Koutek, Jan Harkes, Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for Opti621 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/opti621.h linux-2.4.21/drivers/ide/pci/opti621.h
--- linux-2.4.20/drivers/ide/pci/opti621.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/opti621.h	2002-12-18 18:58:01.000000000 +0000
@@ -0,0 +1,49 @@
+#ifndef OPTI621_H
+#define OPTI621_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static void init_setup_opti621(struct pci_dev *, ide_pci_device_t *);
+static void init_hwif_opti621(ide_hwif_t *);
+static void init_dma_opti621(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t opti621_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_OPTI,
+		.device		= PCI_DEVICE_ID_OPTI_82C621,
+		.name		= "OPTI621",
+		.init_setup	= init_setup_opti621,
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_opti621,
+		.init_dma	= init_dma_opti621,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_OPTI,
+		.device		= PCI_DEVICE_ID_OPTI_82C825,
+		.name		= "OPTI621X",
+		.init_setup	= init_setup_opti621,
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_opti621,
+                .init_dma	= init_dma_opti621,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* OPTI621_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/pdc202xx_new.c linux-2.4.21/drivers/ide/pci/pdc202xx_new.c
--- linux-2.4.20/drivers/ide/pci/pdc202xx_new.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/pdc202xx_new.c	2002-12-18 18:58:03.000000000 +0000
@@ -0,0 +1,676 @@
+/*
+ *  Promise TX2/TX4/TX2000/133 IDE driver
+ *
+ *  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.
+ *
+ *  Split from:
+ *  linux/drivers/ide/pdc202xx.c	Version 0.35	Mar. 30, 2002
+ *  Copyright (C) 1998-2002		Andre Hedrick <andre@linux-ide.org>
+ *  Portions Copyright (C) 1999 Promise Technology, Inc.
+ *  Author: Frank Tiernan (frankt@promise.com)
+ *  Released under terms of General Public License
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "pdc202xx_new.h"
+
+#define PDC202_DEBUG_CABLE	0
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdcnew_proc = 0;
+#define PDC202_MAX_DEVS		5
+static struct pci_dev *pdc202_devs[PDC202_MAX_DEVS];
+static int n_pdc202_devs;
+
+static char * pdcnew_info(char *buf, struct pci_dev *dev)
+{
+	char *p = buf;
+
+	p += sprintf(p, "\n                                ");
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+			p += sprintf(p, "SBFastTrak 133 Lite"); break;
+		case PCI_DEVICE_ID_PROMISE_20276:
+			p += sprintf(p, "MBFastTrak 133 Lite"); break;
+		case PCI_DEVICE_ID_PROMISE_20275:
+			p += sprintf(p, "MBUltra133"); break;
+		case PCI_DEVICE_ID_PROMISE_20271:
+			p += sprintf(p, "FastTrak TX2000"); break;
+		case PCI_DEVICE_ID_PROMISE_20270:
+			p += sprintf(p, "FastTrak LP/TX2/TX4"); break;
+		case PCI_DEVICE_ID_PROMISE_20269:
+			p += sprintf(p, "Ultra133 TX2"); break;
+		case PCI_DEVICE_ID_PROMISE_20268:
+			p += sprintf(p, "Ultra100 TX2"); break;
+		default:
+			p += sprintf(p, "Ultra series"); break;
+			break;
+	}
+	p += sprintf(p, " Chipset.\n");
+	return (char *)p;
+}
+
+static int pdcnew_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	for (i = 0; i < n_pdc202_devs; i++) {
+		struct pci_dev *dev	= pdc202_devs[i];
+		p = pdcnew_info(buffer, dev);
+	}
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+
+static u8 pdcnew_ratemask (ide_drive_t *drive)
+{
+	u8 mode;
+
+	switch(HWIF(drive)->pci_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+		case PCI_DEVICE_ID_PROMISE_20276:
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20271:
+		case PCI_DEVICE_ID_PROMISE_20269:
+			mode = 4;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20270:
+		case PCI_DEVICE_ID_PROMISE_20268:
+			mode = 3;
+			break;
+		default:
+			return 0;
+	}
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+	struct hd_driveid *id = drive->id;
+
+	if (pdc_quirk_drives == list) {
+		while (*list) {
+			if (strstr(id->model, *list++)) {
+				return 2;
+			}
+		}
+	} else {
+		while (*list) {
+			if (!strcmp(*list++,id->model)) {
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+static int pdcnew_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 drive_pci		= 0x60 + (drive->dn << 2);
+	u8 speed	= ide_rate_filter(pdcnew_ratemask(drive), xferspeed);
+
+	u32			drive_conf;
+	u8			AP, BP, CP, DP;
+	u8			TA = 0, TB = 0, TC = 0;
+
+	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
+		return -1;
+
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	if (speed < XFER_SW_DMA_0) {
+		if ((AP & 0x0F) || (BP & 0x07)) {
+			/* clear PIO modes of lower 8421 bits of A Register */
+			pci_write_config_byte(dev, (drive_pci), AP &~0x0F);
+			pci_read_config_byte(dev, (drive_pci), &AP);
+
+			/* clear PIO modes of lower 421 bits of B Register */
+			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0x07);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+			pci_read_config_byte(dev, (drive_pci), &AP);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+		}
+	} else {
+		if ((BP & 0xF0) && (CP & 0x0F)) {
+			/* clear DMA modes of upper 842 bits of B Register */
+			/* clear PIO forced mode upper 1 bit of B Register */
+			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0xF0);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+			/* clear DMA modes of lower 8421 bits of C Register */
+			pci_write_config_byte(dev, (drive_pci)|0x02, CP &~0x0F);
+			pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+		}
+	}
+
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+
+	switch(speed) {
+		case XFER_UDMA_6:	speed = XFER_UDMA_5;
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_2:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	TB = 0x40; TC = 0x02; break;
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:	TB = 0x60; TC = 0x03; break;
+		case XFER_MW_DMA_1:	TB = 0x60; TC = 0x04; break;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_2:	TB = 0x60; TC = 0x05; break;
+		case XFER_SW_DMA_1:	TB = 0x80; TC = 0x06; break;
+		case XFER_SW_DMA_0:	TB = 0xC0; TC = 0x0B; break;
+		case XFER_PIO_4:	TA = 0x01; TB = 0x04; break;
+		case XFER_PIO_3:	TA = 0x02; TB = 0x06; break;
+		case XFER_PIO_2:	TA = 0x03; TB = 0x08; break;
+		case XFER_PIO_1:	TA = 0x05; TB = 0x0C; break;
+		case XFER_PIO_0:
+		default:		TA = 0x09; TB = 0x13; break;
+	}
+
+	if (speed < XFER_SW_DMA_0) {
+		pci_write_config_byte(dev, (drive_pci), AP|TA);
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+	} else {
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+		pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
+	}
+
+#if PDC202XX_DECODE_REGISTER_INFO
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	decode_registers(REG_A, AP);
+	decode_registers(REG_B, BP);
+	decode_registers(REG_C, CP);
+	decode_registers(REG_D, DP);
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+#if PDC202XX_DEBUG_DRIVE_INFO
+	printk("%s: %s drive%d 0x%08x ",
+		drive->name, ide_xfer_verbose(speed),
+		drive->dn, drive_conf);
+		pci_read_config_dword(dev, drive_pci, &drive_conf);
+	printk("0x%08x\n", drive_conf);
+#endif /* PDC202XX_DEBUG_DRIVE_INFO */
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static int pdcnew_new_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned long indexreg	= hwif->dma_vendor1;
+	unsigned long datareg	= hwif->dma_vendor3;
+	u8 thold		= 0x10;
+	u8 adj			= (drive->dn%2) ? 0x08 : 0x00;
+	u8 speed		= ide_rate_filter(pdcnew_ratemask(drive), xferspeed);
+
+	if (speed == XFER_UDMA_2) {
+		hwif->OUTB((thold + adj), indexreg);
+		hwif->OUTB((hwif->INB(datareg) & 0x7f), datareg);
+	}
+
+	switch (speed) {
+		case XFER_UDMA_7:
+			speed = XFER_UDMA_6;
+		case XFER_UDMA_6:	set_ultra(0x1a, 0x01, 0xcb); break;
+		case XFER_UDMA_5:	set_ultra(0x1a, 0x02, 0xcb); break;
+		case XFER_UDMA_4:	set_ultra(0x1a, 0x03, 0xcd); break;
+		case XFER_UDMA_3:	set_ultra(0x1a, 0x05, 0xcd); break;
+		case XFER_UDMA_2:	set_ultra(0x2a, 0x07, 0xcd); break;
+		case XFER_UDMA_1:	set_ultra(0x3a, 0x0a, 0xd0); break;
+		case XFER_UDMA_0:	set_ultra(0x4a, 0x0f, 0xd5); break;
+		case XFER_MW_DMA_2:	set_ata2(0x69, 0x25); break;
+		case XFER_MW_DMA_1:	set_ata2(0x6b, 0x27); break;
+		case XFER_MW_DMA_0:	set_ata2(0xdf, 0x5f); break;
+		case XFER_PIO_4:	set_pio(0x23, 0x09, 0x25); break;
+		case XFER_PIO_3:	set_pio(0x27, 0x0d, 0x35); break;
+		case XFER_PIO_2:	set_pio(0x23, 0x26, 0x64); break;
+		case XFER_PIO_1:	set_pio(0x46, 0x29, 0xa4); break;
+		case XFER_PIO_0:	set_pio(0xfb, 0x2b, 0xac); break;
+		default:
+			;
+	}
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+/*   0    1    2    3    4    5    6   7   8
+ * 960, 480, 390, 300, 240, 180, 120, 90, 60
+ *           180, 150, 120,  90,  60
+ * DMA_Speed
+ * 180, 120,  90,  90,  90,  60,  30
+ *  11,   5,   4,   3,   2,   1,   0
+ */
+static int config_chipset_for_pio (ide_drive_t *drive, u8 pio)
+{
+	u8 speed = 0;
+
+	if (pio == 5) pio = 4;
+	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
+        
+	return ((int) pdcnew_tune_chipset(drive, speed));
+}
+
+static void pdcnew_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	(void) config_chipset_for_pio(drive, pio);
+}
+
+static u8 pdcnew_new_cable_detect (ide_hwif_t *hwif)
+{
+	hwif->OUTB(0x0b, hwif->dma_vendor1);
+	return ((u8)((hwif->INB(hwif->dma_vendor3) & 0x04)));
+}
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed		= -1;
+	u8 cable		= 0;
+
+	u8 ultra_66		= ((id->dma_ultra & 0x0010) ||
+				   (id->dma_ultra & 0x0008)) ? 1 : 0;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+		case PCI_DEVICE_ID_PROMISE_20276:
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20271:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20270:
+		case PCI_DEVICE_ID_PROMISE_20268:
+			cable = pdcnew_new_cable_detect(hwif);
+#if PDC202_DEBUG_CABLE
+			printk("%s: %s-pin cable, %s-pin cable, %d\n",
+				hwif->name, hwif->udma_four ? "80" : "40",
+				cable ? "40" : "80", cable);
+#endif /* PDC202_DEBUG_CABLE */
+			break;
+		default:
+			/* If its not one we know we should never
+			   arrive here.. */
+			BUG();
+	}
+
+	/*
+	 * Set the control register to use the 66Mhz system
+	 * clock for UDMA 3/4 mode operation. If one drive on
+	 * a channel is U66 capable but the other isn't we
+	 * fall back to U33 mode. The BIOS INT 13 hooks turn
+	 * the clock on then off for each read/write issued. I don't
+	 * do that here because it would require modifying the
+	 * kernel, seperating the fop routines from the kernel or
+	 * somehow hooking the fops calls. It may also be possible to
+	 * leave the 66Mhz clock on and readjust the timing
+	 * parameters.
+	 */
+
+	if ((ultra_66) && (cable)) {
+#ifdef DEBUG
+		printk("ULTRA 66/100/133: %s channel of Ultra 66/100/133 "
+			"requires an 80-pin cable for Ultra66 operation.\n",
+			hwif->channel ? "Secondary" : "Primary");
+		printk("         Switching to Ultra33 mode.\n");
+#endif /* DEBUG */
+		/* Primary   : zero out second bit */
+		/* Secondary : zero out fourth bit */
+		printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+		printk("%s reduced to Ultra33 mode.\n", drive->name);
+	}
+
+	if (drive->media != ide_disk)
+		return 0;
+	if (id->capability & 4) {	/* IORDY_EN & PREFETCH_EN */
+		hwif->OUTB((0x13 + ((drive->dn%2) ? 0x08 : 0x00)), hwif->dma_vendor1);
+		hwif->OUTB((hwif->INB(hwif->dma_vendor3)|0x03), hwif->dma_vendor3);
+	}
+
+	speed = ide_dma_speed(drive, pdcnew_ratemask(drive));
+
+	if (!(speed)) {
+		hwif->tuneproc(drive, 5);
+		return 0;
+	}
+
+	(void) hwif->speedproc(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int pdcnew_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			    (id->eide_dma_time < 150)) {
+				goto no_dma_set;
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hwif->tuneproc(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static int pdcnew_quirkproc (ide_drive_t *drive)
+{
+	return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
+}
+
+static int pdcnew_ide_dma_lostirq(ide_drive_t *drive)
+{
+	if (HWIF(drive)->resetproc != NULL)
+		HWIF(drive)->resetproc(drive);
+	return __ide_dma_lostirq(drive);
+}
+
+static int pdcnew_ide_dma_timeout(ide_drive_t *drive)
+{
+	if (HWIF(drive)->resetproc != NULL)
+		HWIF(drive)->resetproc(drive);
+	return __ide_dma_timeout(drive);
+}
+
+static void pdcnew_new_reset (ide_drive_t *drive)
+{
+	/*
+	 * Deleted this because it is redundant from the caller.
+	 */
+	printk("PDC202XX: %s channel reset.\n",
+		HWIF(drive)->channel ? "Secondary" : "Primary");
+}
+
+static void pdcnew_reset_host (ide_hwif_t *hwif)
+{
+//	unsigned long high_16	= hwif->dma_base - (8*(hwif->channel));
+	unsigned long high_16	= hwif->dma_master;
+	u8 udma_speed_flag	= hwif->INB(high_16|0x001f);
+
+	hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f));
+	mdelay(100);
+	hwif->OUTB((udma_speed_flag & ~0x10), (high_16|0x001f));
+	mdelay(2000);	/* 2 seconds ?! */
+
+	printk("PDC202XX: %s channel reset.\n",
+		hwif->channel ? "Secondary" : "Primary");
+}
+
+void pdcnew_reset (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	ide_hwif_t *mate	= hwif->mate;
+	
+	pdcnew_reset_host(hwif);
+	pdcnew_reset_host(mate);
+#if 0
+	/*
+	 * FIXME: Have to kick all the drives again :-/
+	 * What a pain in the ACE!
+	 */
+	if (hwif->present) {
+		u16 hunit = 0;
+		hwif->initializing = 1;
+		for (hunit = 0; hunit < MAX_DRIVES; ++hunit) {
+			ide_drive_t *hdrive = &hwif->drives[hunit];
+			if (hdrive->present) {
+				if (hwif->ide_dma_check)
+					hwif->ide_dma_check(hdrive);
+				else
+					hwif->tuneproc(hdrive, 5);
+			}
+		}
+		hwif->initializing = 0;
+	}
+	if (mate->present) {
+		u16 munit = 0;
+		mate->initializing = 1;
+		for (munit = 0; munit < MAX_DRIVES; ++munit) {
+			ide_drive_t *mdrive = &mate->drives[munit];
+			if (mdrive->present) {
+				if (mate->ide_dma_check) 
+					mate->ide_dma_check(mdrive);
+				else
+					mate->tuneproc(mdrive, 5);
+			}
+		}
+		mate->initializing = 0;
+	}
+#else
+	hwif->tuneproc(drive, 5);
+#endif
+}
+
+static unsigned int __init init_chipset_pdcnew (struct pci_dev *dev, const char *name)
+{
+	if (dev->resource[PCI_ROM_RESOURCE].start) {
+		pci_write_config_dword(dev, PCI_ROM_ADDRESS,
+			dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+		printk("%s: ROM enabled at 0x%08lx\n",
+			name, dev->resource[PCI_ROM_RESOURCE].start);
+	}
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+	pdc202_devs[n_pdc202_devs++] = dev;
+
+	if (!pdcnew_proc) {
+		pdcnew_proc = 1;
+		ide_pci_register_host_proc(&pdcnew_procs[0]);
+	}
+#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+
+	return dev->irq;
+}
+
+static void __init init_hwif_pdc202new (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+
+	hwif->tuneproc  = &pdcnew_tune_drive;
+	hwif->quirkproc = &pdcnew_quirkproc;
+	hwif->speedproc = &pdcnew_new_tune_chipset;
+	hwif->resetproc = &pdcnew_new_reset;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+
+	hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate;
+	hwif->ide_dma_lostirq = &pdcnew_ide_dma_lostirq;
+	hwif->ide_dma_timeout = &pdcnew_ide_dma_timeout;
+	if (!(hwif->udma_four))
+		hwif->udma_four = (pdcnew_new_cable_detect(hwif)) ? 0 : 1;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+#if PDC202_DEBUG_CABLE
+	printk("%s: %s-pin cable\n",
+		hwif->name, hwif->udma_four ? "80" : "40");
+#endif /* PDC202_DEBUG_CABLE */
+}
+
+static void __init init_dma_pdc202new (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+extern void ide_setup_pci_devices(struct pci_dev *, struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_pdcnew (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_pdc20270 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct pci_dev *findev;
+
+	if ((dev->bus->self &&
+	     dev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
+	    (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) {
+		if (PCI_SLOT(dev->devfn) & 2) {
+			return;
+		}
+		d->extra = 0;
+		pci_for_each_dev(findev) {
+			if ((findev->vendor == dev->vendor) &&
+			    (findev->device == dev->device) &&
+			    (PCI_SLOT(findev->devfn) & 2)) {
+				u8 irq = 0, irq2 = 0;
+				pci_read_config_byte(dev,
+					PCI_INTERRUPT_LINE, &irq);
+				pci_read_config_byte(findev,
+					PCI_INTERRUPT_LINE, &irq2);
+				if (irq != irq2) {
+					findev->irq = dev->irq;
+					pci_write_config_byte(findev,
+						PCI_INTERRUPT_LINE, irq);
+				}
+				ide_setup_pci_devices(dev, findev, d);
+				return;
+			}
+		}
+	}
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_pdc20276 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((dev->bus->self) &&
+	    (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) &&
+	    ((dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) ||
+	     (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) {
+		printk(KERN_INFO "ide: Skipping Promise PDC20276 "
+			"attached to I2O RAID controller.\n");
+		return;
+	}
+	ide_setup_pci_device(dev, d);
+}
+
+/**
+ *	pdc202new_init_one	-	called when a pdc202xx is found
+ *	@dev: the pdc202new device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit pdc202new_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &pdcnew_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id pdc202new_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20271, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "Promise IDE",
+	.id_table	= pdc202new_pci_tbl,
+	.probe		= pdc202new_init_one,
+};
+
+static int pdc202new_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void pdc202new_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(pdc202new_ide_init);
+module_exit(pdc202new_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
+MODULE_DESCRIPTION("PCI driver module for Promise PDC20268 and higher");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/pdc202xx_new.h linux-2.4.21/drivers/ide/pci/pdc202xx_new.h
--- linux-2.4.20/drivers/ide/pci/pdc202xx_new.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/pdc202xx_new.h	2002-12-18 18:58:05.000000000 +0000
@@ -0,0 +1,308 @@
+#ifndef PDC202XX_H
+#define PDC202XX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_PDC202XX_TIMINGS
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+#define PDC202XX_DEBUG_DRIVE_INFO		0
+#define PDC202XX_DECODE_REGISTER_INFO		0
+
+const static char *pdc_quirk_drives[] = {
+	"QUANTUM FIREBALLlct08 08",
+	"QUANTUM FIREBALLP KA6.4",
+	"QUANTUM FIREBALLP KA9.1",
+	"QUANTUM FIREBALLP LM20.4",
+	"QUANTUM FIREBALLP KX13.6",
+	"QUANTUM FIREBALLP KX20.5",
+	"QUANTUM FIREBALLP KX27.3",
+	"QUANTUM FIREBALLP LM20.5",
+	NULL
+};
+
+/* A Register */
+#define	SYNC_ERRDY_EN	0xC0
+
+#define	SYNC_IN		0x80	/* control bit, different for master vs. slave drives */
+#define	ERRDY_EN	0x40	/* control bit, different for master vs. slave drives */
+#define	IORDY_EN	0x20	/* PIO: IOREADY */
+#define	PREFETCH_EN	0x10	/* PIO: PREFETCH */
+
+#define	PA3		0x08	/* PIO"A" timing */
+#define	PA2		0x04	/* PIO"A" timing */
+#define	PA1		0x02	/* PIO"A" timing */
+#define	PA0		0x01	/* PIO"A" timing */
+
+/* B Register */
+
+#define	MB2		0x80	/* DMA"B" timing */
+#define	MB1		0x40	/* DMA"B" timing */
+#define	MB0		0x20	/* DMA"B" timing */
+
+#define	PB4		0x10	/* PIO_FORCE 1:0 */
+
+#define	PB3		0x08	/* PIO"B" timing */	/* PIO flow Control mode */
+#define	PB2		0x04	/* PIO"B" timing */	/* PIO 4 */
+#define	PB1		0x02	/* PIO"B" timing */	/* PIO 3 half */
+#define	PB0		0x01	/* PIO"B" timing */	/* PIO 3 other half */
+
+/* C Register */
+#define	IORDYp_NO_SPEED	0x4F
+#define	SPEED_DIS	0x0F
+
+#define	DMARQp		0x80
+#define	IORDYp		0x40
+#define	DMAR_EN		0x20
+#define	DMAW_EN		0x10
+
+#define	MC3		0x08	/* DMA"C" timing */
+#define	MC2		0x04	/* DMA"C" timing */
+#define	MC1		0x02	/* DMA"C" timing */
+#define	MC0		0x01	/* DMA"C" timing */
+
+#if PDC202XX_DECODE_REGISTER_INFO
+
+#define REG_A		0x01
+#define REG_B		0x02
+#define REG_C		0x04
+#define REG_D		0x08
+
+static void decode_registers (u8 registers, u8 value)
+{
+	u8	bit = 0, bit1 = 0, bit2 = 0;
+
+	switch(registers) {
+		case REG_A:
+			bit2 = 0;
+			printk("A Register ");
+			if (value & 0x80) printk("SYNC_IN ");
+			if (value & 0x40) printk("ERRDY_EN ");
+			if (value & 0x20) printk("IORDY_EN ");
+			if (value & 0x10) printk("PREFETCH_EN ");
+			if (value & 0x08) { printk("PA3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("PA2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("PA1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("PA0 ");bit2 |= 0x01; }
+			printk("PIO(A) = %d ", bit2);
+			break;
+		case REG_B:
+			bit1 = 0;bit2 = 0;
+			printk("B Register ");
+			if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; }
+			if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; }
+			if (value & 0x20) { printk("MB0 ");bit1 |= 0x20; }
+			printk("DMA(B) = %d ", bit1 >> 5);
+			if (value & 0x10) printk("PIO_FORCED/PB4 ");
+			if (value & 0x08) { printk("PB3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("PB2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("PB1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("PB0 ");bit2 |= 0x01; }
+			printk("PIO(B) = %d ", bit2);
+			break;
+		case REG_C:
+			bit2 = 0;
+			printk("C Register ");
+			if (value & 0x80) printk("DMARQp ");
+			if (value & 0x40) printk("IORDYp ");
+			if (value & 0x20) printk("DMAR_EN ");
+			if (value & 0x10) printk("DMAW_EN ");
+
+			if (value & 0x08) { printk("MC3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("MC2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("MC1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("MC0 ");bit2 |= 0x01; }
+			printk("DMA(C) = %d ", bit2);
+			break;
+		case REG_D:
+			printk("D Register ");
+			break;
+		default:
+			return;
+	}
+	printk("\n        %s ", (registers & REG_D) ? "DP" :
+				(registers & REG_C) ? "CP" :
+				(registers & REG_B) ? "BP" :
+				(registers & REG_A) ? "AP" : "ERROR");
+	for (bit=128;bit>0;bit/=2)
+		printk("%s", (value & bit) ? "1" : "0");
+	printk("\n");
+}
+
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+
+#define set_2regs(a, b)					\
+	do {						\
+		hwif->OUTB((a + adj), indexreg);	\
+		hwif->OUTB(b, datareg);			\
+	} while(0)
+
+#define set_ultra(a, b, c)				\
+	do {						\
+		set_2regs(0x10,(a));			\
+		set_2regs(0x11,(b));			\
+		set_2regs(0x12,(c));			\
+	} while(0)
+
+#define set_ata2(a, b)					\
+	do {						\
+		set_2regs(0x0e,(a));			\
+		set_2regs(0x0f,(b));			\
+	} while(0)
+
+#define set_pio(a, b, c)				\
+	do { 						\
+		set_2regs(0x0c,(a));			\
+		set_2regs(0x0d,(b));			\
+		set_2regs(0x13,(c));			\
+	} while(0)
+
+#define DISPLAY_PDC202XX_TIMINGS
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdcnew_proc;
+
+static int pdcnew_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t pdcnew_procs[] __initdata = {
+	{
+		.name		= "pdcnew",
+		.set		= 1,
+		.get_info	= pdcnew_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+
+
+static void init_setup_pdcnew(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_pdc20270(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_pdc20276(struct pci_dev *dev, ide_pci_device_t *d);
+static unsigned int init_chipset_pdcnew(struct pci_dev *, const char *);
+static void init_hwif_pdc202new(ide_hwif_t *);
+static void init_dma_pdc202new(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20268,
+		.name		= "PDC20268",
+		.init_setup	= init_setup_pdcnew,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20269,
+		.name		= "PDC20269",
+		.init_setup	= init_setup_pdcnew,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20270,
+		.name		= "PDC20270",
+		.init_setup	= init_setup_pdc20270,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20271,
+		.name		= "PDC20271",
+		.init_setup	= init_setup_pdcnew,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 4 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20275,
+		.name		= "PDC20275",
+		.init_setup	= init_setup_pdcnew,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 5 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20276,
+		.name		= "PDC20276",
+		.init_setup	= init_setup_pdc20276,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 6 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20277,
+		.name		= "PDC20277",
+		.init_setup	= init_setup_pdcnew,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* PDC202XX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/pdc202xx_old.c linux-2.4.21/drivers/ide/pci/pdc202xx_old.c
--- linux-2.4.20/drivers/ide/pci/pdc202xx_old.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/pdc202xx_old.c	2002-12-18 18:58:01.000000000 +0000
@@ -0,0 +1,959 @@
+/*
+ *  linux/drivers/ide/pdc202xx.c	Version 0.36	Sept 11, 2002
+ *
+ *  Copyright (C) 1998-2002		Andre Hedrick <andre@linux-ide.org>
+ *
+ *  Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this
+ *  compiled into the kernel if you have more than one card installed.
+ *  Note that BIOS v1.29 is reported to fix the problem.  Since this is
+ *  safe chipset tuning, including this support is harmless
+ *
+ *  Promise Ultra66 cards with BIOS v1.11 this
+ *  compiled into the kernel if you have more than one card installed.
+ *
+ *  Promise Ultra100 cards.
+ *
+ *  The latest chipset code will support the following ::
+ *  Three Ultra33 controllers and 12 drives.
+ *  8 are UDMA supported and 4 are limited to DMA mode 2 multi-word.
+ *  The 8/4 ratio is a BIOS code limit by promise.
+ *
+ *  UNLESS you enable "CONFIG_PDC202XX_BURST"
+ *
+ */
+
+/*
+ *  Portions Copyright (C) 1999 Promise Technology, Inc.
+ *  Author: Frank Tiernan (frankt@promise.com)
+ *  Released under terms of General Public License
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "pdc202xx_old.h"
+
+#define PDC202_DEBUG_CABLE	0
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdc202xx_proc = 0;
+#define PDC202_MAX_DEVS		5
+static struct pci_dev *pdc202_devs[PDC202_MAX_DEVS];
+static int n_pdc202_devs;
+
+static char * pdc202xx_info (char *buf, struct pci_dev *dev)
+{
+	char *p = buf;
+
+	unsigned long bibma  = pci_resource_start(dev, 4);
+	u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
+	u16 reg50h = 0, pmask = (1<<10), smask = (1<<11);
+	u8 hi = 0, lo = 0;
+
+        /*
+         * at that point bibma+0x2 et bibma+0xa are byte registers
+         * to investigate:
+         */
+	u8 c0	= inb_p((u16)bibma + 0x02);
+	u8 c1	= inb_p((u16)bibma + 0x0a);
+
+	u8 sc11	= inb_p((u16)bibma + 0x11);
+	u8 sc1a	= inb_p((u16)bibma + 0x1a);
+	u8 sc1b	= inb_p((u16)bibma + 0x1b);
+	u8 sc1c	= inb_p((u16)bibma + 0x1c); 
+	u8 sc1d	= inb_p((u16)bibma + 0x1d);
+	u8 sc1e	= inb_p((u16)bibma + 0x1e);
+	u8 sc1f	= inb_p((u16)bibma + 0x1f);
+
+	pci_read_config_word(dev, 0x50, &reg50h);
+	pci_read_config_dword(dev, 0x60, &reg60h);
+	pci_read_config_dword(dev, 0x64, &reg64h);
+	pci_read_config_dword(dev, 0x68, &reg68h);
+	pci_read_config_dword(dev, 0x6c, &reg6ch);
+
+	p += sprintf(p, "\n                                ");
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20267:
+			p += sprintf(p, "Ultra100"); break;
+		case PCI_DEVICE_ID_PROMISE_20265:
+			p += sprintf(p, "Ultra100 on M/B"); break;
+		case PCI_DEVICE_ID_PROMISE_20263:
+			p += sprintf(p, "FastTrak 66"); break;
+		case PCI_DEVICE_ID_PROMISE_20262:
+			p += sprintf(p, "Ultra66"); break;
+		case PCI_DEVICE_ID_PROMISE_20246:
+			p += sprintf(p, "Ultra33");
+			reg50h |= 0x0c00;
+			break;
+		default:
+			p += sprintf(p, "Ultra Series"); break;
+	}
+	p += sprintf(p, " Chipset.\n");
+
+	p += sprintf(p, "------------------------------- General Status "
+			"---------------------------------\n");
+	p += sprintf(p, "Burst Mode                           : %sabled\n",
+		(sc1f & 0x01) ? "en" : "dis");
+	p += sprintf(p, "Host Mode                            : %s\n",
+		(sc1f & 0x08) ? "Tri-Stated" : "Normal");
+	p += sprintf(p, "Bus Clocking                         : %s\n",
+		((sc1f & 0xC0) == 0xC0) ? "100 External" :
+		((sc1f & 0x80) == 0x80) ? "66 External" :
+		((sc1f & 0x40) == 0x40) ? "33 External" : "33 PCI Internal");
+	p += sprintf(p, "IO pad select                        : %s mA\n",
+		((sc1c & 0x03) == 0x03) ? "10" :
+		((sc1c & 0x02) == 0x02) ? "8" :
+		((sc1c & 0x01) == 0x01) ? "6" :
+		((sc1c & 0x00) == 0x00) ? "4" : "??");
+	SPLIT_BYTE(sc1e, hi, lo);
+	p += sprintf(p, "Status Polling Period                : %d\n", hi);
+	p += sprintf(p, "Interrupt Check Status Polling Delay : %d\n", lo);
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %s                         %s\n",
+		(c0&0x80)?"disabled":"enabled ",
+		(c1&0x80)?"disabled":"enabled ");
+	p += sprintf(p, "66 Clocking     %s                         %s\n",
+		(sc11&0x02)?"enabled ":"disabled",
+		(sc11&0x08)?"enabled ":"disabled");
+	p += sprintf(p, "           Mode %s                      Mode %s\n",
+		(sc1a & 0x01) ? "MASTER" : "PCI   ",
+		(sc1b & 0x01) ? "MASTER" : "PCI   ");
+	p += sprintf(p, "                %s                     %s\n",
+		(sc1d & 0x08) ? "Error       " :
+		((sc1d & 0x05) == 0x05) ? "Not My INTR " :
+		(sc1d & 0x04) ? "Interrupting" :
+		(sc1d & 0x02) ? "FIFO Full   " :
+		(sc1d & 0x01) ? "FIFO Empty  " : "????????????",
+		(sc1d & 0x80) ? "Error       " :
+		((sc1d & 0x50) == 0x50) ? "Not My INTR " :
+		(sc1d & 0x40) ? "Interrupting" :
+		(sc1d & 0x20) ? "FIFO Full   " :
+		(sc1d & 0x10) ? "FIFO Empty  " : "????????????");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	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 ");
+	p += sprintf(p, "DMA Mode:       %s           %s "
+			"         %s            %s\n",
+		pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)),
+		pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)),
+		pdc202xx_ultra_verbose(reg68h, (reg50h & smask)),
+		pdc202xx_ultra_verbose(reg6ch, (reg50h & smask)));
+	p += sprintf(p, "PIO Mode:       %s            %s "
+			"          %s            %s\n",
+		pdc202xx_pio_verbose(reg60h),
+		pdc202xx_pio_verbose(reg64h),
+		pdc202xx_pio_verbose(reg68h),
+		pdc202xx_pio_verbose(reg6ch));
+#if 0
+	p += sprintf(p, "--------------- Can ATAPI DMA ---------------\n");
+#endif
+	return (char *)p;
+}
+
+static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	for (i = 0; i < n_pdc202_devs; i++) {
+		struct pci_dev *dev	= pdc202_devs[i];
+		p = pdc202xx_info(buffer, dev);
+	}
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+
+static u8 pdc202xx_ratemask (ide_drive_t *drive)
+{
+	u8 mode;
+
+	switch(HWIF(drive)->pci_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+			mode = 3;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20263:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			mode = 2;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20246:
+			return 1;
+		default:
+			return 0;
+	}
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+	struct hd_driveid *id = drive->id;
+
+	if (pdc_quirk_drives == list) {
+		while (*list) {
+			if (strstr(id->model, *list++)) {
+				return 2;
+			}
+		}
+	} else {
+		while (*list) {
+			if (!strcmp(*list++,id->model)) {
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 drive_pci		= 0x60 + (drive->dn << 2);
+	u8 speed	= ide_rate_filter(pdc202xx_ratemask(drive), xferspeed);
+
+	u32			drive_conf;
+	u8			AP, BP, CP, DP;
+	u8			TA = 0, TB = 0, TC = 0;
+
+	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
+		return -1;
+
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	if (speed < XFER_SW_DMA_0) {
+		if ((AP & 0x0F) || (BP & 0x07)) {
+			/* clear PIO modes of lower 8421 bits of A Register */
+			pci_write_config_byte(dev, (drive_pci), AP &~0x0F);
+			pci_read_config_byte(dev, (drive_pci), &AP);
+
+			/* clear PIO modes of lower 421 bits of B Register */
+			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0x07);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+			pci_read_config_byte(dev, (drive_pci), &AP);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+		}
+	} else {
+		if ((BP & 0xF0) && (CP & 0x0F)) {
+			/* clear DMA modes of upper 842 bits of B Register */
+			/* clear PIO forced mode upper 1 bit of B Register */
+			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0xF0);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+			/* clear DMA modes of lower 8421 bits of C Register */
+			pci_write_config_byte(dev, (drive_pci)|0x02, CP &~0x0F);
+			pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+		}
+	}
+
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+
+	switch(speed) {
+		case XFER_UDMA_6:	speed = XFER_UDMA_5;
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_2:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	TB = 0x40; TC = 0x02; break;
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:	TB = 0x60; TC = 0x03; break;
+		case XFER_MW_DMA_1:	TB = 0x60; TC = 0x04; break;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_2:	TB = 0x60; TC = 0x05; break;
+		case XFER_SW_DMA_1:	TB = 0x80; TC = 0x06; break;
+		case XFER_SW_DMA_0:	TB = 0xC0; TC = 0x0B; break;
+		case XFER_PIO_4:	TA = 0x01; TB = 0x04; break;
+		case XFER_PIO_3:	TA = 0x02; TB = 0x06; break;
+		case XFER_PIO_2:	TA = 0x03; TB = 0x08; break;
+		case XFER_PIO_1:	TA = 0x05; TB = 0x0C; break;
+		case XFER_PIO_0:
+		default:		TA = 0x09; TB = 0x13; break;
+	}
+
+	if (speed < XFER_SW_DMA_0) {
+		pci_write_config_byte(dev, (drive_pci), AP|TA);
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+	} else {
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+		pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
+	}
+
+#if PDC202XX_DECODE_REGISTER_INFO
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	decode_registers(REG_A, AP);
+	decode_registers(REG_B, BP);
+	decode_registers(REG_C, CP);
+	decode_registers(REG_D, DP);
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+#if PDC202XX_DEBUG_DRIVE_INFO
+	printk("%s: %s drive%d 0x%08x ",
+		drive->name, ide_xfer_verbose(speed),
+		drive->dn, drive_conf);
+		pci_read_config_dword(dev, drive_pci, &drive_conf);
+	printk("0x%08x\n", drive_conf);
+#endif /* PDC202XX_DEBUG_DRIVE_INFO */
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+
+/*   0    1    2    3    4    5    6   7   8
+ * 960, 480, 390, 300, 240, 180, 120, 90, 60
+ *           180, 150, 120,  90,  60
+ * DMA_Speed
+ * 180, 120,  90,  90,  90,  60,  30
+ *  11,   5,   4,   3,   2,   1,   0
+ */
+static void config_chipset_for_pio (ide_drive_t *drive, u8 pio)
+{
+	u8 speed = 0;
+
+	if (pio == 5) pio = 4;
+	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
+        
+	pdc202xx_tune_chipset(drive, speed);
+}
+
+static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
+{
+	u16 CIS = 0, mask = (hwif->channel) ? (1<<11) : (1<<10);
+	pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
+	return ((u8)(CIS & mask));
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u32 drive_conf		= 0;
+	u8 mask			= hwif->channel ? 0x08 : 0x02;
+	u8 drive_pci		= 0x60 + (drive->dn << 2);
+	u8 test1 = 0, test2 = 0, speed = -1;
+	u8 AP = 0, CLKSPD = 0, cable = 0;
+
+	u8 ultra_66		= ((id->dma_ultra & 0x0010) ||
+				   (id->dma_ultra & 0x0008)) ? 1 : 0;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+		case PCI_DEVICE_ID_PROMISE_20263:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			cable = pdc202xx_old_cable_detect(hwif);
+#if PDC202_DEBUG_CABLE
+			printk("%s: %s-pin cable, %s-pin cable, %d\n",
+				hwif->name, hwif->udma_four ? "80" : "40",
+				cable ? "40" : "80", cable);
+#endif /* PDC202_DEBUG_CABLE */
+			break;
+		case PCI_DEVICE_ID_PROMISE_20246:
+			ultra_66 = 0;
+			break;
+		default:
+			BUG();
+	}
+
+	CLKSPD = hwif->INB(hwif->dma_master + 0x11);
+
+	/*
+	 * Set the control register to use the 66Mhz system
+	 * clock for UDMA 3/4 mode operation. If one drive on
+	 * a channel is U66 capable but the other isn't we
+	 * fall back to U33 mode. The BIOS INT 13 hooks turn
+	 * the clock on then off for each read/write issued. I don't
+	 * do that here because it would require modifying the
+	 * kernel, seperating the fop routines from the kernel or
+	 * somehow hooking the fops calls. It may also be possible to
+	 * leave the 66Mhz clock on and readjust the timing
+	 * parameters.
+	 */
+
+	if ((ultra_66) && (cable)) {
+#ifdef DEBUG
+		printk("ULTRA 66/100/133: %s channel of Ultra 66/100/133 "
+			"requires an 80-pin cable for Ultra66 operation.\n",
+			hwif->channel ? "Secondary" : "Primary");
+		printk("         Switching to Ultra33 mode.\n");
+#endif /* DEBUG */
+		/* Primary   : zero out second bit */
+		/* Secondary : zero out fourth bit */
+		hwif->OUTB(CLKSPD & ~mask, (hwif->dma_master + 0x11));
+		printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+		printk("%s reduced to Ultra33 mode.\n", drive->name);
+	} else {
+		if (ultra_66) {
+			/*
+			 * check to make sure drive on same channel
+			 * is u66 capable
+			 */
+			if (hwif->drives[!(drive->dn%2)].id) {
+				if (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0078) {
+					hwif->OUTB(CLKSPD | mask, (hwif->dma_master + 0x11));
+				} else {
+					hwif->OUTB(CLKSPD & ~mask, (hwif->dma_master + 0x11));
+				}
+			} else { /* udma4 drive by itself */
+				hwif->OUTB(CLKSPD | mask, (hwif->dma_master + 0x11));
+			}
+		}
+	}
+
+	drive_pci = 0x60 + (drive->dn << 2);
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+		goto chipset_is_set;
+
+	pci_read_config_byte(dev, drive_pci, &test1);
+	if (!(test1 & SYNC_ERRDY_EN)) {
+		if (drive->select.b.unit & 0x01) {
+			pci_read_config_byte(dev, drive_pci - 4, &test2);
+			if ((test2 & SYNC_ERRDY_EN) &&
+			    !(test1 & SYNC_ERRDY_EN)) {
+				pci_write_config_byte(dev, drive_pci,
+					test1|SYNC_ERRDY_EN);
+			}
+		} else {
+			pci_write_config_byte(dev, drive_pci,
+				test1|SYNC_ERRDY_EN);
+		}
+	}
+
+chipset_is_set:
+
+	if (drive->media == ide_disk) {
+		pci_read_config_byte(dev, (drive_pci), &AP);
+		if (id->capability & 4)	/* IORDY_EN */
+			pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN);
+		pci_read_config_byte(dev, (drive_pci), &AP);
+		if (drive->media == ide_disk)	/* PREFETCH_EN */
+			pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
+	}
+
+	speed = ide_dma_speed(drive, pdc202xx_ratemask(drive));
+
+	if (!(speed)) {
+		/* restore original pci-config space */
+		pci_write_config_dword(dev, drive_pci, drive_conf);
+		hwif->tuneproc(drive, 5);
+		return 0;
+	}
+
+	(void) hwif->speedproc(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int pdc202xx_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			    (id->eide_dma_time < 150)) {
+				goto no_dma_set;
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hwif->tuneproc(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static int pdc202xx_quirkproc (ide_drive_t *drive)
+{
+	return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
+}
+
+static int pdc202xx_old_ide_dma_begin(ide_drive_t *drive)
+{
+	if (drive->addressing == 1) {
+		struct request *rq	= HWGROUP(drive)->rq;
+		ide_hwif_t *hwif	= HWIF(drive);
+//		struct pci_dev *dev	= hwif->pci_dev;
+//		unsgned long high_16	= pci_resource_start(dev, 4);
+		unsigned long high_16   = hwif->dma_master;
+		unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
+		u32 word_count	= 0;
+		u8 clock = hwif->INB(high_16 + 0x11);
+
+		hwif->OUTB(clock|(hwif->channel ? 0x08 : 0x02), high_16+0x11);
+		word_count = (rq->nr_sectors << 8);
+		word_count = (rq_data_dir(rq) == READ) ?
+					word_count | 0x05000000 :
+					word_count | 0x06000000;
+		hwif->OUTL(word_count, atapi_reg);
+	}
+	return __ide_dma_begin(drive);
+}
+
+static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
+{
+	if (drive->addressing == 1) {
+		ide_hwif_t *hwif	= HWIF(drive);
+//		unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
+		unsigned long high_16	= hwif->dma_master;
+		unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
+		u8 clock		= 0;
+
+		hwif->OUTL(0, atapi_reg); /* zero out extra */
+		clock = hwif->INB(high_16 + 0x11);
+		hwif->OUTB(clock & ~(hwif->channel ? 0x08:0x02), high_16+0x11);
+	}
+	return __ide_dma_end(drive);
+}
+
+static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+//	struct pci_dev *dev	= hwif->pci_dev;
+//	unsigned long high_16	= pci_resource_start(dev, 4);
+	unsigned long high_16	= hwif->dma_master;
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
+	u8 sc1d			= hwif->INB((high_16 + 0x001d));
+
+	if (hwif->channel) {
+		if ((sc1d & 0x50) == 0x50)
+			goto somebody_else;
+		else if ((sc1d & 0x40) == 0x40)
+			return (dma_stat & 4) == 4;
+	} else {
+		if ((sc1d & 0x05) == 0x05)
+			goto somebody_else;
+		else if ((sc1d & 0x04) == 0x04)
+			return (dma_stat & 4) == 4;
+	}
+somebody_else:
+	return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
+}
+
+static int pdc202xx_ide_dma_lostirq(ide_drive_t *drive)
+{
+	if (HWIF(drive)->resetproc != NULL)
+		HWIF(drive)->resetproc(drive);
+	return __ide_dma_lostirq(drive);
+}
+
+static int pdc202xx_ide_dma_timeout(ide_drive_t *drive)
+{
+	if (HWIF(drive)->resetproc != NULL)
+		HWIF(drive)->resetproc(drive);
+	return __ide_dma_timeout(drive);
+}
+
+static void pdc202xx_reset_host (ide_hwif_t *hwif)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+//	unsigned long high_16	= hwif->dma_base - (8*(hwif->channel));
+	unsigned long high_16	= hwif->dma_master;
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+	unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	u8 udma_speed_flag	= hwif->INB(high_16|0x001f);
+
+	hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f));
+	mdelay(100);
+	hwif->OUTB((udma_speed_flag & ~0x10), (high_16|0x001f));
+	mdelay(2000);	/* 2 seconds ?! */
+
+	printk("PDC202XX: %s channel reset.\n",
+		hwif->channel ? "Secondary" : "Primary");
+}
+
+void pdc202xx_reset (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	ide_hwif_t *mate	= hwif->mate;
+	
+	pdc202xx_reset_host(hwif);
+	pdc202xx_reset_host(mate);
+#if 0
+	/*
+	 * FIXME: Have to kick all the drives again :-/
+	 * What a pain in the ACE!
+	 */
+	if (hwif->present) {
+		u16 hunit = 0;
+		hwif->initializing = 1;
+		for (hunit = 0; hunit < MAX_DRIVES; ++hunit) {
+			ide_drive_t *hdrive = &hwif->drives[hunit];
+			if (hdrive->present) {
+				if (hwif->ide_dma_check)
+					hwif->ide_dma_check(hdrive);
+				else
+					hwif->tuneproc(hdrive, 5);
+			}
+		}
+		hwif->initializing = 0;
+	}
+	if (mate->present) {
+		u16 munit = 0;
+		mate->initializing = 1;
+		for (munit = 0; munit < MAX_DRIVES; ++munit) {
+			ide_drive_t *mdrive = &mate->drives[munit];
+			if (mdrive->present) {
+				if (mate->ide_dma_check) 
+					mate->ide_dma_check(mdrive);
+				else
+					mate->tuneproc(mdrive, 5);
+			}
+		}
+		mate->initializing = 0;
+	}
+#else
+	hwif->tuneproc(drive, 5);
+#endif
+}
+
+/*
+ * Since SUN Cobalt is attempting to do this operation, I should disclose
+ * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
+ * HOTSWAP ATA Infrastructure.
+ */
+static int pdc202xx_tristate (ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+//	unsigned long high_16	= hwif->dma_base - (8*(hwif->channel));
+	unsigned long high_16	= hwif->dma_master;
+	u8 sc1f			= hwif->INB(high_16|0x001f);
+
+	if (!hwif)
+		return -EINVAL;
+
+//	hwif->bus_state = state;
+
+	if (state) {
+		hwif->OUTB(sc1f | 0x08, (high_16|0x001f));
+	} else {
+		hwif->OUTB(sc1f & ~0x08, (high_16|0x001f));
+	}
+	return 0;
+}
+
+static unsigned int __init init_chipset_pdc202xx (struct pci_dev *dev, const char *name)
+{
+	if (dev->resource[PCI_ROM_RESOURCE].start) {
+		pci_write_config_dword(dev, PCI_ROM_ADDRESS,
+			dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+		printk("%s: ROM enabled at 0x%08lx\n",
+			name, dev->resource[PCI_ROM_RESOURCE].start);
+	}
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+	pdc202_devs[n_pdc202_devs++] = dev;
+
+	if (!pdc202xx_proc) {
+		pdc202xx_proc = 1;
+		ide_pci_register_host_proc(&pdc202xx_procs[0]);
+	}
+#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+
+	/*
+	 * software reset -  this is required because the bios
+	 * will set UDMA timing on if the hdd supports it. The
+	 * user may want to turn udma off. A bug in the pdc20262
+	 * is that it cannot handle a downgrade in timing from
+	 * UDMA to DMA. Disk accesses after issuing a set
+	 * feature command will result in errors. A software
+	 * reset leaves the timing registers intact,
+	 * but resets the drives.
+	 */
+#if 0
+	if ((dev->device == PCI_DEVICE_ID_PROMISE_20267) ||
+	    (dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
+	    (dev->device == PCI_DEVICE_ID_PROMISE_20263) ||
+	    (dev->device == PCI_DEVICE_ID_PROMISE_20262)) {
+		unsigned long high_16	= pci_resource_start(dev, 4);
+		byte udma_speed_flag	= inb(high_16 + 0x001f);
+		outb(udma_speed_flag | 0x10, high_16 + 0x001f);
+		mdelay(100);
+		outb(udma_speed_flag & ~0x10, high_16 + 0x001f);
+		mdelay(2000);	/* 2 seconds ?! */
+	}
+
+#endif
+	return dev->irq;
+}
+
+static void __init init_hwif_pdc202xx (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->tuneproc  = &config_chipset_for_pio;
+	hwif->quirkproc = &pdc202xx_quirkproc;
+
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20265)
+		hwif->addressing = (hwif->channel) ? 0 : 1;
+
+	if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) {
+		hwif->busproc   = &pdc202xx_tristate;
+		hwif->resetproc = &pdc202xx_reset;
+	}
+
+	hwif->speedproc = &pdc202xx_tune_chipset;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	hwif->ide_dma_check = &pdc202xx_config_drive_xfer_rate;
+	hwif->ide_dma_lostirq = &pdc202xx_ide_dma_lostirq;
+	hwif->ide_dma_timeout = &pdc202xx_ide_dma_timeout;
+
+	if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) {
+		if (!(hwif->udma_four))
+			hwif->udma_four = (pdc202xx_old_cable_detect(hwif)) ? 0 : 1;
+		hwif->ide_dma_begin = &pdc202xx_old_ide_dma_begin;
+		hwif->ide_dma_end = &pdc202xx_old_ide_dma_end;
+	} 
+	hwif->ide_dma_test_irq = &pdc202xx_old_ide_dma_test_irq;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+#if PDC202_DEBUG_CABLE
+	printk("%s: %s-pin cable\n",
+		hwif->name, hwif->udma_four ? "80" : "40");
+#endif /* PDC202_DEBUG_CABLE */	
+}
+
+static void __init init_dma_pdc202xx (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
+
+	if (hwif->channel) {
+		ide_setup_dma(hwif, dmabase, 8);
+		return;
+	}
+
+	udma_speed_flag	= hwif->INB((dmabase|0x1f));
+	primary_mode	= hwif->INB((dmabase|0x1a));
+	secondary_mode	= hwif->INB((dmabase|0x1b));
+	printk("%s: (U)DMA Burst Bit %sABLED " \
+		"Primary %s Mode " \
+		"Secondary %s Mode.\n", hwif->cds->name,
+		(udma_speed_flag & 1) ? "EN" : "DIS",
+		(primary_mode & 1) ? "MASTER" : "PCI",
+		(secondary_mode & 1) ? "MASTER" : "PCI" );
+
+#ifdef CONFIG_PDC202XX_BURST
+	if (!(udma_speed_flag & 1)) {
+		printk("%s: FORCING BURST BIT 0x%02x->0x%02x ",
+			hwif->cds->name, udma_speed_flag,
+			(udma_speed_flag|1));
+		hwif->OUTB(udma_speed_flag|1,(dmabase|0x1f));
+		printk("%sACTIVE\n",
+			(hwif->INB(dmabase|0x1f)&1) ? "":"IN");
+	}
+#endif /* CONFIG_PDC202XX_BURST */
+#ifdef CONFIG_PDC202XX_MASTER
+	if (!(primary_mode & 1)) {
+		printk("%s: FORCING PRIMARY MODE BIT "
+			"0x%02x -> 0x%02x ", hwif->cds->name,
+			primary_mode, (primary_mode|1));
+		hwif->OUTB(primary_mode|1, (dmabase|0x1a));
+		printk("%s\n",
+			(hwif->INB((dmabase|0x1a)) & 1) ? "MASTER" : "PCI");
+	}
+
+	if (!(secondary_mode & 1)) {
+		printk("%s: FORCING SECONDARY MODE BIT "
+			"0x%02x -> 0x%02x ", hwif->cds->name,
+			secondary_mode, (secondary_mode|1));
+		hwif->OUTB(secondary_mode|1, (dmabase|0x1b));
+		printk("%s\n",
+			(hwif->INB((dmabase|0x1b)) & 1) ? "MASTER" : "PCI");
+	}
+#endif /* CONFIG_PDC202XX_MASTER */
+
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+extern void ide_setup_pci_devices(struct pci_dev *, struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_pdc202ata4 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
+		u8 irq = 0, irq2 = 0;
+		pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+		/* 0xbc */
+		pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);
+		if (irq != irq2) {
+			pci_write_config_byte(dev,
+				(PCI_INTERRUPT_LINE)|0x80, irq);     /* 0xbc */
+			printk("%s: pci-config space interrupt "
+				"mirror fixed.\n", d->name);
+		}
+	}
+
+#if 0
+        if (dev->device == PCI_DEVICE_ID_PROMISE_20262)
+        if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
+             (tmp & e->mask) != e->val))
+
+        if (d->enablebits[0].reg != d->enablebits[1].reg) {
+                d->enablebits[0].reg    = d->enablebits[1].reg;
+                d->enablebits[0].mask   = d->enablebits[1].mask;
+                d->enablebits[0].val    = d->enablebits[1].val;
+        }
+#endif
+
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_pdc20265 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((dev->bus->self) &&
+	    (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) &&
+	    ((dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) ||
+	     (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) {
+		printk(KERN_INFO "ide: Skipping Promise PDC20265 "
+			"attached to I2O RAID controller.\n");
+		return;
+	}
+
+#if 0
+        {
+                u8 pri = 0, sec = 0;
+
+        if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
+             (tmp & e->mask) != e->val))
+
+        if (d->enablebits[0].reg != d->enablebits[1].reg) {
+                d->enablebits[0].reg    = d->enablebits[1].reg;
+                d->enablebits[0].mask   = d->enablebits[1].mask;
+                d->enablebits[0].val    = d->enablebits[1].val;
+        }
+        }
+#endif
+
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_pdc202xx (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+/**
+ *	pdc202xx_init_one	-	called when a PDC202xx is found
+ *	@dev: the pdc202xx device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &pdc202xx_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id pdc202xx_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "Promise Old IDE",
+	.id_table	= pdc202xx_pci_tbl,
+	.probe		= pdc202xx_init_one,
+};
+
+static int pdc202xx_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void pdc202xx_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(pdc202xx_ide_init);
+module_exit(pdc202xx_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
+MODULE_DESCRIPTION("PCI driver module for older Promise IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/pdc202xx_old.h linux-2.4.21/drivers/ide/pci/pdc202xx_old.h
--- linux-2.4.20/drivers/ide/pci/pdc202xx_old.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/pdc202xx_old.h	2002-12-18 18:58:01.000000000 +0000
@@ -0,0 +1,326 @@
+#ifndef PDC202XX_H
+#define PDC202XX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_PDC202XX_TIMINGS
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+#define PDC202XX_DEBUG_DRIVE_INFO		0
+#define PDC202XX_DECODE_REGISTER_INFO		0
+
+const static char *pdc_quirk_drives[] = {
+	"QUANTUM FIREBALLlct08 08",
+	"QUANTUM FIREBALLP KA6.4",
+	"QUANTUM FIREBALLP KA9.1",
+	"QUANTUM FIREBALLP LM20.4",
+	"QUANTUM FIREBALLP KX13.6",
+	"QUANTUM FIREBALLP KX20.5",
+	"QUANTUM FIREBALLP KX27.3",
+	"QUANTUM FIREBALLP LM20.5",
+	NULL
+};
+
+static inline u8 *pdc202xx_pio_verbose (u32 drive_pci)
+{
+	if ((drive_pci & 0x000ff000) == 0x000ff000) return("NOTSET");
+	if ((drive_pci & 0x00000401) == 0x00000401) return("PIO 4");
+	if ((drive_pci & 0x00000602) == 0x00000602) return("PIO 3");
+	if ((drive_pci & 0x00000803) == 0x00000803) return("PIO 2");
+	if ((drive_pci & 0x00000C05) == 0x00000C05) return("PIO 1");
+	if ((drive_pci & 0x00001309) == 0x00001309) return("PIO 0");
+	return("PIO ?");
+}
+
+static inline u8 *pdc202xx_dma_verbose (u32 drive_pci)
+{
+	if ((drive_pci & 0x00036000) == 0x00036000) return("MWDMA 2");
+	if ((drive_pci & 0x00046000) == 0x00046000) return("MWDMA 1");
+	if ((drive_pci & 0x00056000) == 0x00056000) return("MWDMA 0");
+	if ((drive_pci & 0x00056000) == 0x00056000) return("SWDMA 2");
+	if ((drive_pci & 0x00068000) == 0x00068000) return("SWDMA 1");
+	if ((drive_pci & 0x000BC000) == 0x000BC000) return("SWDMA 0");
+	return("PIO---");
+}
+
+static inline u8 *pdc202xx_ultra_verbose (u32 drive_pci, u16 slow_cable)
+{
+	if ((drive_pci & 0x000ff000) == 0x000ff000)
+		return("NOTSET");
+	if ((drive_pci & 0x00012000) == 0x00012000)
+		return((slow_cable) ? "UDMA 2" : "UDMA 4");
+	if ((drive_pci & 0x00024000) == 0x00024000)
+		return((slow_cable) ? "UDMA 1" : "UDMA 3");
+	if ((drive_pci & 0x00036000) == 0x00036000)
+		return("UDMA 0");
+	return(pdc202xx_dma_verbose(drive_pci));
+}
+
+/* A Register */
+#define	SYNC_ERRDY_EN	0xC0
+
+#define	SYNC_IN		0x80	/* control bit, different for master vs. slave drives */
+#define	ERRDY_EN	0x40	/* control bit, different for master vs. slave drives */
+#define	IORDY_EN	0x20	/* PIO: IOREADY */
+#define	PREFETCH_EN	0x10	/* PIO: PREFETCH */
+
+#define	PA3		0x08	/* PIO"A" timing */
+#define	PA2		0x04	/* PIO"A" timing */
+#define	PA1		0x02	/* PIO"A" timing */
+#define	PA0		0x01	/* PIO"A" timing */
+
+/* B Register */
+
+#define	MB2		0x80	/* DMA"B" timing */
+#define	MB1		0x40	/* DMA"B" timing */
+#define	MB0		0x20	/* DMA"B" timing */
+
+#define	PB4		0x10	/* PIO_FORCE 1:0 */
+
+#define	PB3		0x08	/* PIO"B" timing */	/* PIO flow Control mode */
+#define	PB2		0x04	/* PIO"B" timing */	/* PIO 4 */
+#define	PB1		0x02	/* PIO"B" timing */	/* PIO 3 half */
+#define	PB0		0x01	/* PIO"B" timing */	/* PIO 3 other half */
+
+/* C Register */
+#define	IORDYp_NO_SPEED	0x4F
+#define	SPEED_DIS	0x0F
+
+#define	DMARQp		0x80
+#define	IORDYp		0x40
+#define	DMAR_EN		0x20
+#define	DMAW_EN		0x10
+
+#define	MC3		0x08	/* DMA"C" timing */
+#define	MC2		0x04	/* DMA"C" timing */
+#define	MC1		0x02	/* DMA"C" timing */
+#define	MC0		0x01	/* DMA"C" timing */
+
+#if PDC202XX_DECODE_REGISTER_INFO
+
+#define REG_A		0x01
+#define REG_B		0x02
+#define REG_C		0x04
+#define REG_D		0x08
+
+static void decode_registers (u8 registers, u8 value)
+{
+	u8	bit = 0, bit1 = 0, bit2 = 0;
+
+	switch(registers) {
+		case REG_A:
+			bit2 = 0;
+			printk("A Register ");
+			if (value & 0x80) printk("SYNC_IN ");
+			if (value & 0x40) printk("ERRDY_EN ");
+			if (value & 0x20) printk("IORDY_EN ");
+			if (value & 0x10) printk("PREFETCH_EN ");
+			if (value & 0x08) { printk("PA3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("PA2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("PA1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("PA0 ");bit2 |= 0x01; }
+			printk("PIO(A) = %d ", bit2);
+			break;
+		case REG_B:
+			bit1 = 0;bit2 = 0;
+			printk("B Register ");
+			if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; }
+			if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; }
+			if (value & 0x20) { printk("MB0 ");bit1 |= 0x20; }
+			printk("DMA(B) = %d ", bit1 >> 5);
+			if (value & 0x10) printk("PIO_FORCED/PB4 ");
+			if (value & 0x08) { printk("PB3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("PB2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("PB1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("PB0 ");bit2 |= 0x01; }
+			printk("PIO(B) = %d ", bit2);
+			break;
+		case REG_C:
+			bit2 = 0;
+			printk("C Register ");
+			if (value & 0x80) printk("DMARQp ");
+			if (value & 0x40) printk("IORDYp ");
+			if (value & 0x20) printk("DMAR_EN ");
+			if (value & 0x10) printk("DMAW_EN ");
+
+			if (value & 0x08) { printk("MC3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("MC2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("MC1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("MC0 ");bit2 |= 0x01; }
+			printk("DMA(C) = %d ", bit2);
+			break;
+		case REG_D:
+			printk("D Register ");
+			break;
+		default:
+			return;
+	}
+	printk("\n        %s ", (registers & REG_D) ? "DP" :
+				(registers & REG_C) ? "CP" :
+				(registers & REG_B) ? "BP" :
+				(registers & REG_A) ? "AP" : "ERROR");
+	for (bit=128;bit>0;bit/=2)
+		printk("%s", (value & bit) ? "1" : "0");
+	printk("\n");
+}
+
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+
+#define set_2regs(a, b)					\
+	do {						\
+		hwif->OUTB((a + adj), indexreg);	\
+		hwif->OUTB(b, datareg);			\
+	} while(0)
+
+#define set_ultra(a, b, c)				\
+	do {						\
+		set_2regs(0x10,(a));			\
+		set_2regs(0x11,(b));			\
+		set_2regs(0x12,(c));			\
+	} while(0)
+
+#define set_ata2(a, b)					\
+	do {						\
+		set_2regs(0x0e,(a));			\
+		set_2regs(0x0f,(b));			\
+	} while(0)
+
+#define set_pio(a, b, c)				\
+	do { 						\
+		set_2regs(0x0c,(a));			\
+		set_2regs(0x0d,(b));			\
+		set_2regs(0x13,(c));			\
+	} while(0)
+
+#define DISPLAY_PDC202XX_TIMINGS
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdc202xx_proc;
+
+static int pdc202xx_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t pdc202xx_procs[] __initdata = {
+	{
+		.name		= "pdc202xx",
+		.set		= 1,
+		.get_info	= pdc202xx_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+
+
+static void init_setup_pdc202ata4(struct pci_dev *dev, ide_pci_device_t *d);
+static void init_setup_pdc20265(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_pdc202xx(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_pdc202xx(struct pci_dev *, const char *);
+static void init_hwif_pdc202xx(ide_hwif_t *);
+static void init_dma_pdc202xx(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20246,
+		.name		= "PDC20246",
+		.init_setup	= init_setup_pdc202ata4,
+		.init_chipset	= init_chipset_pdc202xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202xx,
+		.init_dma	= init_dma_pdc202xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 16,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20262,
+		.name		= "PDC20262",
+		.init_setup	= init_setup_pdc202ata4,
+		.init_chipset	= init_chipset_pdc202xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202xx,
+		.init_dma	= init_dma_pdc202xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 48,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20263,
+		.name		= "PDC20263",
+		.init_setup	= init_setup_pdc202ata4,
+		.init_chipset	= init_chipset_pdc202xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202xx,
+		.init_dma	= init_dma_pdc202xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 48,
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20265,
+		.name		= "PDC20265",
+		.init_setup	= init_setup_pdc20265,
+		.init_chipset	= init_chipset_pdc202xx,
+		.init_hwif	= init_hwif_pdc202xx,
+		.init_dma	= init_dma_pdc202xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 48,
+	},{	/* 4 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20267,
+		.name		= "PDC20267",
+		.init_setup	= init_setup_pdc202xx,
+		.init_chipset	= init_chipset_pdc202xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202xx,
+		.init_dma	= init_dma_pdc202xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 48,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* PDC202XX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/pdcadma.c linux-2.4.21/drivers/ide/pci/pdcadma.c
--- linux-2.4.20/drivers/ide/pci/pdcadma.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/pdcadma.c	2002-12-18 18:58:08.000000000 +0000
@@ -0,0 +1,165 @@
+/*
+ * linux/drivers/ide/pdcadma.c		Version 0.05	Sept 10, 2002
+ *
+ * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "pdcadma.h"
+
+#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdcadma_proc = 0;
+#define PDC_MAX_DEVS		5
+static struct pci_dev *pdc_devs[PDC_MAX_DEVS];
+static int n_pdc_devs;
+
+static int pdcadma_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	for (i = 0; i < n_pdc_devs; i++) {
+		struct pci_dev *dev	= pdc_devs[i];
+		unsigned long bibma = pci_resource_start(dev, 4);
+
+		p += sprintf(p, "\n                                "
+			"PDC ADMA %04X Chipset.\n", dev->device);
+		p += sprintf(p, "UDMA\n");
+		p += sprintf(p, "PIO\n");
+
+	}
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/*
+ * pdcadma_dma functions() initiates/aborts (U)DMA read/write
+ * operations on a drive.
+ */
+#if 0
+        int (*ide_dma_read)(ide_drive_t *drive);
+        int (*ide_dma_write)(ide_drive_t *drive);
+        int (*ide_dma_begin)(ide_drive_t *drive);
+        int (*ide_dma_end)(ide_drive_t *drive);
+        int (*ide_dma_check)(ide_drive_t *drive);
+        int (*ide_dma_on)(ide_drive_t *drive);
+        int (*ide_dma_off)(ide_drive_t *drive);
+        int (*ide_dma_off_quietly)(ide_drive_t *drive);
+        int (*ide_dma_test_irq)(ide_drive_t *drive);
+        int (*ide_dma_host_on)(ide_drive_t *drive);
+        int (*ide_dma_host_off)(ide_drive_t *drive);
+        int (*ide_dma_bad_drive)(ide_drive_t *drive);
+        int (*ide_dma_good_drive)(ide_drive_t *drive);
+        int (*ide_dma_count)(ide_drive_t *drive);
+        int (*ide_dma_verbose)(ide_drive_t *drive);
+        int (*ide_dma_retune)(ide_drive_t *drive);
+        int (*ide_dma_lostirq)(ide_drive_t *drive);
+        int (*ide_dma_timeout)(ide_drive_t *drive);
+
+#endif
+
+static unsigned int __init init_chipset_pdcadma (struct pci_dev *dev, const char *name)
+{
+#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
+	pdc_devs[n_pdc_devs++] = dev;
+
+	if (!pdcadma_proc) {
+		pdcadma_proc = 1;
+		ide_pci_register_host_proc(&pdcadma_procs[0]);
+	}
+#endif /* DISPLAY_PDCADMA_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+static void __init init_hwif_pdcadma (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->dma_base = 0;
+
+//	hwif->tuneproc = &pdcadma_tune_drive;
+//	hwif->speedproc = &pdcadma_tune_chipset;
+
+//	if (hwif->dma_base) {
+//		hwif->autodma = 1;
+//	}
+
+	hwif->udma_four = 1;
+
+//	hwif->atapi_dma = 1;
+//	hwif->ultra_mask = 0x7f;
+//	hwif->mwdma_mask = 0x07;
+//	hwif->swdma_mask = 0x07;
+
+}
+
+static void __init init_dma_pdcadma (ide_hwif_t *hwif, unsigned long dmabase)
+{
+#if 0
+	ide_setup_dma(hwif, dmabase, 8);
+#endif
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit pdcadma_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &pdcadma_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 1;
+}
+
+static struct pci_device_id pdcadma_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_PDC, PCI_DEVICE_ID_PDC_1841, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "PDCADMA-IDE",
+	.id_table	= pdcadma_pci_tbl,
+	.probe		= pdcadma_init_one,
+};
+
+static int pdcadma_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void pdcadma_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(pdcadma_ide_init);
+module_exit(pdcadma_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for PDCADMA IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/pdcadma.h linux-2.4.21/drivers/ide/pci/pdcadma.h
--- linux-2.4.20/drivers/ide/pci/pdcadma.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/pdcadma.h	2002-12-18 18:58:07.000000000 +0000
@@ -0,0 +1,56 @@
+#ifndef PDC_ADMA_H
+#define PDC_ADMA_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#undef DISPLAY_PDCADMA_TIMINGS
+
+#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdcadma_proc;
+
+static int pdcadma_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t pdcadma_procs[] __initdata = {
+	{
+		.name		= "pdcadma",
+		.set		= 1,
+		.get_info	= pdcadma_get_info,
+		.parent		= NULL,
+	},
+};
+#endif  /* defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_pdcadma(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_pdcadma(struct pci_dev *, const char *);
+static void init_hwif_pdcadma(ide_hwif_t *);
+static void init_dma_pdcadma(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t pdcadma_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_PDC,
+		.device		= PCI_DEVICE_ID_PDC_1841,
+		.name		= "PDCADMA",
+		.init_setup	= init_setup_pdcadma,
+		.init_chipset	= init_chipset_pdcadma,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdcadma,
+		.init_dma	= init_dma_pdcadma,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* PDC_ADMA_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/piix.c linux-2.4.21/drivers/ide/pci/piix.c
--- linux-2.4.20/drivers/ide/pci/piix.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/piix.c	2002-12-18 18:58:07.000000000 +0000
@@ -0,0 +1,721 @@
+/*
+ *  linux/drivers/ide/piix.c		Version 0.40	August 18, 2002
+ *
+ *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
+ *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ *  May be copied or modified under the terms of the GNU General Public License
+ *
+ *  PIO mode setting function for Intel chipsets.  
+ *  For use instead of BIOS settings.
+ *
+ * 40-41
+ * 42-43
+ * 
+ *                 41
+ *                 43
+ *
+ * | PIO 0       | c0 | 80 | 0 | 	piix_tune_drive(drive, 0);
+ * | PIO 2 | SW2 | d0 | 90 | 4 | 	piix_tune_drive(drive, 2);
+ * | PIO 3 | MW1 | e1 | a1 | 9 | 	piix_tune_drive(drive, 3);
+ * | PIO 4 | MW2 | e3 | a3 | b | 	piix_tune_drive(drive, 4);
+ * 
+ * sitre = word40 & 0x4000; primary
+ * sitre = word42 & 0x4000; secondary
+ *
+ * 44 8421|8421    hdd|hdb
+ * 
+ * 48 8421         hdd|hdc|hdb|hda udma enabled
+ *
+ *    0001         hda
+ *    0010         hdb
+ *    0100         hdc
+ *    1000         hdd
+ *
+ * 4a 84|21        hdb|hda
+ * 4b 84|21        hdd|hdc
+ *
+ *    ata-33/82371AB
+ *    ata-33/82371EB
+ *    ata-33/82801AB            ata-66/82801AA
+ *    00|00 udma 0              00|00 reserved
+ *    01|01 udma 1              01|01 udma 3
+ *    10|10 udma 2              10|10 udma 4
+ *    11|11 reserved            11|11 reserved
+ *
+ * 54 8421|8421    ata66 drive|ata66 enable
+ *
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &reg40);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, &reg42);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, &reg44);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, &reg48);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, &reg4a);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, &reg54);
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "piix.h"
+
+#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 piix_proc = 0;
+#define PIIX_MAX_DEVS		5
+static struct pci_dev *piix_devs[PIIX_MAX_DEVS];
+static int n_piix_devs;
+
+/**
+ *	piix_get_info		-	fill in /proc for PIIX ide
+ *	@buffer: buffer to fill
+ *	@addr: address of user start in buffer
+ *	@offset: offset into 'file'
+ *	@count: buffer count
+ *
+ *	Walks the PIIX devices and outputs summary data on the tuning and
+ *	anything else that will help with debugging
+ */
+ 
+static int piix_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	for (i = 0; i < n_piix_devs; i++) {
+		struct pci_dev *dev	= piix_devs[i];
+		unsigned long bibma = pci_resource_start(dev, 4);
+	        u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
+		u8  c0 = 0, c1 = 0, reg54 = 0, reg55 = 0;
+		u8  reg44 = 0, reg48 = 0, reg4a = 0, reg4b = 0;
+
+		p += sprintf(p, "\nController: %d\n", i);
+		p += sprintf(p, "\n                                Intel ");
+		switch(dev->device) {
+			case PCI_DEVICE_ID_INTEL_82801BA_8:
+			case PCI_DEVICE_ID_INTEL_82801BA_9:
+			case PCI_DEVICE_ID_INTEL_82801CA_10:
+			case PCI_DEVICE_ID_INTEL_82801CA_11:
+			case PCI_DEVICE_ID_INTEL_82801DB_11:
+			case PCI_DEVICE_ID_INTEL_82801E_11:
+				p += sprintf(p, "PIIX4 Ultra 100 ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82372FB_1:
+			case PCI_DEVICE_ID_INTEL_82801AA_1:
+				p += sprintf(p, "PIIX4 Ultra 66 ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82451NX:
+			case PCI_DEVICE_ID_INTEL_82801AB_1:
+			case PCI_DEVICE_ID_INTEL_82443MX_1:
+			case PCI_DEVICE_ID_INTEL_82371AB:
+				p += sprintf(p, "PIIX4 Ultra 33 ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82371SB_1:
+				p += sprintf(p, "PIIX3 ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82371MX:
+				p += sprintf(p, "MPIIX ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82371FB_1:
+			case PCI_DEVICE_ID_INTEL_82371FB_0:
+			default:
+				p += sprintf(p, "PIIX ");
+				break;
+		}
+		p += sprintf(p, "Chipset.\n");
+
+		if (dev->device == PCI_DEVICE_ID_INTEL_82371MX)
+			continue;
+
+		pci_read_config_word(dev, 0x40, &reg40);
+		pci_read_config_word(dev, 0x42, &reg42);
+		pci_read_config_byte(dev, 0x44, &reg44);
+		pci_read_config_byte(dev, 0x48, &reg48);
+		pci_read_config_byte(dev, 0x4a, &reg4a);
+		pci_read_config_byte(dev, 0x4b, &reg4b);
+		pci_read_config_byte(dev, 0x54, &reg54);
+		pci_read_config_byte(dev, 0x55, &reg55);
+
+		psitre = (reg40 & 0x4000) ? 1 : 0;
+		ssitre = (reg42 & 0x4000) ? 1 : 0;
+
+		/*
+		 * at that point bibma+0x2 et bibma+0xa are byte registers
+		 * to investigate:
+		 */
+		c0 = inb(bibma + 0x02);
+		c1 = inb(bibma + 0x0a);
+
+		p += sprintf(p, "--------------- Primary Channel "
+				"---------------- Secondary Channel "
+				"-------------\n");
+		p += sprintf(p, "                %sabled "
+				"                        %sabled\n",
+				(c0&0x80) ? "dis" : " en",
+				(c1&0x80) ? "dis" : " en");
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"-------- drive0 ---------- drive1 ------\n");
+		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 " );
+		p += sprintf(p, "UDMA enabled:   %s              %s "
+				"            %s               %s\n",
+				(reg48&0x01) ? "yes" : "no ",
+				(reg48&0x02) ? "yes" : "no ",
+				(reg48&0x04) ? "yes" : "no ",
+				(reg48&0x08) ? "yes" : "no " );
+		p += sprintf(p, "UDMA enabled:   %s                %s "
+				"              %s                 %s\n",
+				((reg54&0x11) &&
+				 (reg55&0x10) && (reg4a&0x01)) ? "5" :
+				((reg54&0x11) && (reg4a&0x02)) ? "4" :
+				((reg54&0x11) && (reg4a&0x01)) ? "3" :
+				(reg4a&0x02) ? "2" :
+				(reg4a&0x01) ? "1" :
+				(reg4a&0x00) ? "0" : "X",
+				((reg54&0x22) &&
+				 (reg55&0x20) && (reg4a&0x10)) ? "5" :
+				((reg54&0x22) && (reg4a&0x20)) ? "4" :
+				((reg54&0x22) && (reg4a&0x10)) ? "3" :
+				(reg4a&0x20) ? "2" :
+				(reg4a&0x10) ? "1" :
+				(reg4a&0x00) ? "0" : "X",
+				((reg54&0x44) &&
+				 (reg55&0x40) && (reg4b&0x03)) ? "5" :
+				((reg54&0x44) && (reg4b&0x02)) ? "4" :
+				((reg54&0x44) && (reg4b&0x01)) ? "3" :
+				(reg4b&0x02) ? "2" :
+				(reg4b&0x01) ? "1" :
+				(reg4b&0x00) ? "0" : "X",
+				((reg54&0x88) &&
+				 (reg55&0x80) && (reg4b&0x30)) ? "5" :
+				((reg54&0x88) && (reg4b&0x20)) ? "4" :
+				((reg54&0x88) && (reg4b&0x10)) ? "3" :
+				(reg4b&0x20) ? "2" :
+				(reg4b&0x10) ? "1" :
+				(reg4b&0x00) ? "0" : "X");
+
+		p += sprintf(p, "UDMA\n");
+		p += sprintf(p, "DMA\n");
+		p += sprintf(p, "PIO\n");
+
+		/*
+		 * FIXME.... Add configuration junk data....blah blah......
+		 */
+	}
+	return p-buffer;	 /* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/**
+ *	piix_ratemask		-	compute rate mask for PIIX IDE
+ *	@drive: IDE drive to compute for
+ *
+ *	Returns the available modes for the PIIX IDE controller.
+ */
+ 
+static u8 piix_ratemask (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 mode;
+
+	switch(dev->device) {
+		/* UDMA 100 capable */
+		case PCI_DEVICE_ID_INTEL_82801BA_8:
+		case PCI_DEVICE_ID_INTEL_82801BA_9:
+		case PCI_DEVICE_ID_INTEL_82801CA_10:
+		case PCI_DEVICE_ID_INTEL_82801CA_11:
+		case PCI_DEVICE_ID_INTEL_82801E_11:
+		case PCI_DEVICE_ID_INTEL_82801DB_11:
+			mode = 3;
+			break;
+		/* UDMA 66 capable */
+		case PCI_DEVICE_ID_INTEL_82801AA_1:
+		case PCI_DEVICE_ID_INTEL_82372FB_1:
+			mode = 2;
+			break;
+		/* UDMA 33 capable */
+		case PCI_DEVICE_ID_INTEL_82371AB:
+		case PCI_DEVICE_ID_INTEL_82443MX_1:
+		case PCI_DEVICE_ID_INTEL_82451NX:
+		case PCI_DEVICE_ID_INTEL_82801AB_1:
+			return 1;
+		/* Non UDMA capable (MWDMA2) */
+		case PCI_DEVICE_ID_INTEL_82371SB_1:
+		case PCI_DEVICE_ID_INTEL_82371FB_1:
+		case PCI_DEVICE_ID_INTEL_82371FB_0:
+		case PCI_DEVICE_ID_INTEL_82371MX:
+		default:
+			return 0;
+	}
+	
+	/*
+	 *	If we are UDMA66 capable fall back to UDMA33 
+	 *	if the drive cannot see an 80pin cable.
+	 */
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+/**
+ *	piix_dma_2_pio		-	return the PIO mode matching DMA
+ *	@xfer_rate: transfer speed
+ *
+ *	Returns the nearest equivalent PIO timing for the PIO or DMA
+ *	mode requested by the controller.
+ */
+ 
+static u8 piix_dma_2_pio (u8 xfer_rate) {
+	switch(xfer_rate) {
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:
+		case XFER_PIO_4:
+			return 4;
+		case XFER_MW_DMA_1:
+		case XFER_PIO_3:
+			return 3;
+		case XFER_SW_DMA_2:
+		case XFER_PIO_2:
+			return 2;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+		case XFER_PIO_SLOW:
+		default:
+			return 0;
+	}
+}
+
+/**
+ *	piix_tune_drive		-	tune a drive attached to a PIIX
+ *	@drive: drive to tune
+ *	@pio: desired PIO mode
+ *
+ *	Set the interface PIO mode based upon  the settings done by AMI BIOS
+ *	(might be useful if drive is not registered in CMOS for any reason).
+ */
+static void piix_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	int is_slave		= (&hwif->drives[1] == drive);
+	int master_port		= hwif->channel ? 0x42 : 0x40;
+	int slave_port		= 0x44;
+	unsigned long flags;
+	u16 master_data;
+	u8 slave_data;
+				 /* ISP  RTC */
+	u8 timings[][2]	= { { 0, 0 },
+			    { 0, 0 },
+			    { 1, 0 },
+			    { 2, 1 },
+			    { 2, 3 }, };
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	spin_lock_irqsave(&ide_lock, flags);
+	pci_read_config_word(dev, master_port, &master_data);
+	if (is_slave) {
+		master_data = master_data | 0x4000;
+		if (pio > 1)
+			/* enable PPE, IE and TIME */
+			master_data = master_data | 0x0070;
+		pci_read_config_byte(dev, slave_port, &slave_data);
+		slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
+		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
+	} else {
+		master_data = master_data & 0xccf8;
+		if (pio > 1)
+			/* enable PPE, IE and TIME */
+			master_data = master_data | 0x0007;
+		master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+	}
+	pci_write_config_word(dev, master_port, master_data);
+	if (is_slave)
+		pci_write_config_byte(dev, slave_port, slave_data);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/**
+ *	piix_tune_chipset	-	tune a PIIX interface
+ *	@drive: IDE drive to tune
+ *	@xferspeed: speed to configure
+ *
+ *	Set a PIIX interface channel to the desired speeds. This involves
+ *	requires the right timing data into the PIIX configuration space
+ *	then setting the drive parameters appropriately
+ */
+ 
+static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 maslave		= hwif->channel ? 0x42 : 0x40;
+	u8 speed		= ide_rate_filter(piix_ratemask(drive), xferspeed);
+	int a_speed		= 3 << (drive->dn * 4);
+	int u_flag		= 1 << drive->dn;
+	int v_flag		= 0x01 << drive->dn;
+	int w_flag		= 0x10 << drive->dn;
+	int u_speed		= 0;
+	int			sitre;
+	u16			reg4042, reg44, reg48, reg4a, reg54;
+	u8			reg55;
+
+	pci_read_config_word(dev, maslave, &reg4042);
+	sitre = (reg4042 & 0x4000) ? 1 : 0;
+	pci_read_config_word(dev, 0x44, &reg44);
+	pci_read_config_word(dev, 0x48, &reg48);
+	pci_read_config_word(dev, 0x4a, &reg4a);
+	pci_read_config_word(dev, 0x54, &reg54);
+	pci_read_config_byte(dev, 0x55, &reg55);
+
+	switch(speed) {
+		case XFER_UDMA_4:
+		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
+		case XFER_UDMA_5:
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
+		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_SW_DMA_2:	break;
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_0:	break;
+		default:		return -1;
+	}
+
+	if (speed >= XFER_UDMA_0) {
+		if (!(reg48 & u_flag))
+			pci_write_config_word(dev, 0x48, reg48|u_flag);
+		if (speed == XFER_UDMA_5) {
+			pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
+		} else {
+			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+		}
+		if (!(reg4a & u_speed)) {
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+			pci_write_config_word(dev, 0x4a, reg4a|u_speed);
+		}
+		if (speed > XFER_UDMA_2) {
+			if (!(reg54 & v_flag)) {
+				pci_write_config_word(dev, 0x54, reg54|v_flag);
+			}
+		} else {
+			pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
+		}
+	} else {
+		if (reg48 & u_flag)
+			pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
+		if (reg4a & a_speed)
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+		if (reg54 & v_flag)
+			pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
+		if (reg55 & w_flag)
+			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+	}
+
+	piix_tune_drive(drive, piix_dma_2_pio(speed));
+	return (ide_config_drive_speed(drive, speed));
+}
+
+/**
+ *	piix_config_drive_for_dma	-	configure drive for DMA
+ *	@drive: IDE drive to configure
+ *
+ *	Set up a PIIX interface channel for the best available speed.
+ *	We prefer UDMA if it is available and then MWDMA. If DMA is 
+ *	not available we switch to PIO and return 0. 
+ */
+ 
+static int piix_config_drive_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, piix_ratemask(drive));
+
+	if (!(speed)) {
+		u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
+		speed = piix_dma_2_pio(XFER_PIO_0 + tspeed);
+	}
+
+	(void) piix_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+/**
+ *	piix_config_drive_xfer_rate	-	set up an IDE device
+ *	@drive: IDE drive to configure
+ *
+ *	Set up the PIIX interface for the best available speed on this
+ *	interface, preferring DMA to PIO.
+ */
+ 
+static int piix_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				if ((id->field_valid & 2) &&
+				    (!piix_config_drive_for_dma(drive)))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!piix_config_drive_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!piix_config_drive_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hwif->tuneproc(drive, 255);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+/**
+ *	init_chipset_piix	-	set up the PIIX chipset
+ *	@dev: PCI device to set up
+ *	@name: Name of the device
+ *
+ *	Initialize the PCI device as required. For the PIIX this turns
+ *	out to be nice and simple
+ */
+ 
+static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name)
+{
+        switch(dev->device) {
+		case PCI_DEVICE_ID_INTEL_82801AA_1:
+		case PCI_DEVICE_ID_INTEL_82801AB_1:
+		case PCI_DEVICE_ID_INTEL_82801BA_8:
+		case PCI_DEVICE_ID_INTEL_82801BA_9:
+		case PCI_DEVICE_ID_INTEL_82801CA_10:
+		case PCI_DEVICE_ID_INTEL_82801CA_11:
+		case PCI_DEVICE_ID_INTEL_82801DB_11:
+		case PCI_DEVICE_ID_INTEL_82801E_11:
+		{
+			unsigned int extra = 0;
+			pci_read_config_dword(dev, 0x54, &extra);
+			pci_write_config_dword(dev, 0x54, extra|0x400);
+		}
+		default:
+			break;
+	}
+
+#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
+	piix_devs[n_piix_devs++] = dev;
+
+	if (!piix_proc) {
+		piix_proc = 1;
+		ide_pci_register_host_proc(&piix_procs[0]);
+	}
+#endif /* DISPLAY_PIIX_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+/**
+ *	init_hwif_piix		-	fill in the hwif for the PIIX
+ *	@hwif: IDE interface
+ *
+ *	Set up the ide_hwif_t for the PIIX interface according to the
+ *	capabilities of the hardware.
+ */
+ 
+static void __init init_hwif_piix (ide_hwif_t *hwif)
+{
+	u8 reg54h = 0, reg55h = 0, ata66 = 0;
+	u8 mask = hwif->channel ? 0xc0 : 0x30;
+
+#ifndef CONFIG_IA64
+	if (!hwif->irq)
+		hwif->irq = hwif->channel ? 15 : 14;
+#endif /* CONFIG_IA64 */
+
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_82371MX) {
+		/* This is a painful system best to let it self tune for now */
+		return;
+	}
+
+	hwif->autodma = 0;
+	hwif->tuneproc = &piix_tune_drive;
+	hwif->speedproc = &piix_tune_chipset;
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].autotune = 1;
+
+	if (!hwif->dma_base)
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x06;
+	hwif->swdma_mask = 0x04;
+
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_INTEL_82371MX:
+			hwif->mwdma_mask = 0x80;
+			hwif->swdma_mask = 0x80;
+		case PCI_DEVICE_ID_INTEL_82371FB_0:
+		case PCI_DEVICE_ID_INTEL_82371FB_1:
+		case PCI_DEVICE_ID_INTEL_82371SB_1:
+			hwif->ultra_mask = 0x80;
+			break;
+		case PCI_DEVICE_ID_INTEL_82371AB:
+		case PCI_DEVICE_ID_INTEL_82443MX_1:
+		case PCI_DEVICE_ID_INTEL_82451NX:
+		case PCI_DEVICE_ID_INTEL_82801AB_1:
+			hwif->ultra_mask = 0x07;
+			break;
+		default:
+			pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
+			pci_read_config_byte(hwif->pci_dev, 0x55, &reg55h);
+			ata66 = (reg54h & mask) ? 1 : 0;
+			break;
+	}
+
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66;
+	hwif->ide_dma_check = &piix_config_drive_xfer_rate;
+	if (!noautodma)
+		hwif->autodma = 1;
+
+	hwif->drives[1].autodma = hwif->autodma;
+	hwif->drives[0].autodma = hwif->autodma;
+}
+
+/**
+ *	init_dma_piix		-	set up the PIIX DMA
+ *	@hwif: IDE interface
+ *	@dmabase: DMA PCI base
+ *
+ *	Set up the DMA on the PIIX controller, providing a DMA base is
+ *	available. The PIIX follows the normal specs so we do nothing
+ *	magical here.
+ */
+
+static void __init init_dma_piix (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+/**
+ *	init_setup_piix		-	callback for IDE initialize
+ *	@dev: PIIX PCI device
+ *	@d: IDE pci info
+ *
+ *	Enable the xp fixup for the PIIX controller and then perform
+ *	a standard ide PCI setup
+ */
+ 
+static void __init init_setup_piix (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+/**
+ *	piix_init_one	-	called when a PIIX is found
+ *	@dev: the piix device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit piix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &piix_pci_info[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id piix_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "PIIX IDE",
+	.id_table	= piix_pci_tbl,
+	.probe		= piix_init_one,
+};
+
+static int piix_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void piix_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(piix_ide_init);
+module_exit(piix_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick, Andrzej Krzysztofowicz");
+MODULE_DESCRIPTION("PCI driver module for Intel PIIX IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/piix.h linux-2.4.21/drivers/ide/pci/piix.h
--- linux-2.4.20/drivers/ide/pci/piix.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/piix.h	2002-12-18 18:58:11.000000000 +0000
@@ -0,0 +1,275 @@
+#ifndef PIIX_H
+#define PIIX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define PIIX_DEBUG_DRIVE_INFO		0
+
+#define DISPLAY_PIIX_TIMINGS
+
+#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 piix_proc;
+
+static int piix_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t piix_procs[] __devinitdata = {
+	{
+		.name		= "piix",
+		.set		= 1,
+		.get_info	= piix_get_info,
+		.parent		= NULL,
+	},
+};
+#endif  /* defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_piix(struct pci_dev *, ide_pci_device_t *);
+static unsigned int __devinit init_chipset_piix(struct pci_dev *, const char *);
+static void init_hwif_piix(ide_hwif_t *);
+static void init_dma_piix(ide_hwif_t *, unsigned long);
+
+
+/*
+ *	Table of the various PIIX capability blocks
+ *
+ */
+ 
+static ide_pci_device_t piix_pci_info[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82371FB_0,
+		.name		= "PIIXa",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82371FB_1,
+		.name		= "PIIXb",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82371MX,
+		.name		= "MPIIX",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82371SB_1,
+		.name		= "PIIX3",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 4 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82371AB,
+		.name		= "PIIX4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 5 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801AB_1,
+		.name		= "ICH0",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 6 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82443MX_1,
+		.name		= "PIIX4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 7 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801AA_1,
+		.name		= "ICH",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 8 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82372FB_1,
+		.name		= "PIIX4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 9 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82451NX,
+		.name		= "PIIX4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 10 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801BA_9,
+		.name		= "ICH2",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 11 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801BA_8,
+		.name		= "ICH2M",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 12 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801CA_10,
+		.name		= "ICH3M",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 13 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801CA_11,
+		.name		= "ICH3",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 14 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801DB_11,
+		.name		= "ICH4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 15 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801E_11,
+		.name		= "C-ICH",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.init_setup	= NULL,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* PIIX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/rz1000.c linux-2.4.21/drivers/ide/pci/rz1000.c
--- linux-2.4.20/drivers/ide/pci/rz1000.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/rz1000.c	2002-12-18 18:58:02.000000000 +0000
@@ -0,0 +1,99 @@
+/*
+ *  linux/drivers/ide/rz1000.c		Version 0.05	December 8, 1997
+ *
+ *  Copyright (C) 1995-1998  Linus Torvalds & author (see below)
+ */
+
+/*
+ *  Principal Author:  mlord@pobox.com (Mark Lord)
+ *
+ *  See linux/MAINTAINERS for address of current maintainer.
+ *
+ *  This file provides support for disabling the buggy read-ahead
+ *  mode of the RZ1000 IDE chipset, commonly used on Intel motherboards.
+ *
+ *  Dunno if this fixes both ports, or only the primary port (?).
+ */
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
+#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "rz1000.h"
+
+static void __init init_hwif_rz1000 (ide_hwif_t *hwif)
+{
+	u16 reg;
+	struct pci_dev *dev = hwif->pci_dev;
+
+	hwif->chipset = ide_rz1000;
+	if (!pci_read_config_word (dev, 0x40, &reg) &&
+	    !pci_write_config_word(dev, 0x40, reg & 0xdfff)) {
+		printk("%s: disabled chipset read-ahead "
+			"(buggy RZ1000/RZ1001)\n", hwif->name);
+	} else {
+		hwif->serialized = 1;
+		hwif->drives[0].no_unmask = 1;
+		hwif->drives[1].no_unmask = 1;
+		printk("%s: serialized, disabled unmasking "
+			"(buggy RZ1000/RZ1001)\n", hwif->name);
+	}
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit rz1000_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &rz1000_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id rz1000_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "RZ1000 IDE",
+	.id_table	= rz1000_pci_tbl,
+	.probe		= rz1000_init_one,
+};
+
+static int rz1000_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void rz1000_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(rz1000_ide_init);
+module_exit(rz1000_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for RZ1000 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/rz1000.h linux-2.4.21/drivers/ide/pci/rz1000.h
--- linux-2.4.20/drivers/ide/pci/rz1000.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/rz1000.h	2002-12-18 18:58:05.000000000 +0000
@@ -0,0 +1,45 @@
+#ifndef RZ100X_H
+#define RZ100X_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static void init_hwif_rz1000(ide_hwif_t *);
+
+static ide_pci_device_t rz1000_chipsets[] __devinitdata = {
+{
+		.vendor		= PCI_VENDOR_ID_PCTECH,
+		.device		= PCI_DEVICE_ID_PCTECH_RZ1000,
+		.name		= "RZ1000",
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_rz1000,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= PCI_VENDOR_ID_PCTECH,
+		.device		= PCI_DEVICE_ID_PCTECH_RZ1001,
+		.name		= "RZ1001",
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_rz1000,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* RZ100X_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/sc1200.c linux-2.4.21/drivers/ide/pci/sc1200.c
--- linux-2.4.20/drivers/ide/pci/sc1200.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/sc1200.c	2002-12-18 18:58:02.000000000 +0000
@@ -0,0 +1,593 @@
+/*
+ * linux/drivers/ide/sc1200.c		Version 0.9	24-Oct-2002
+ *
+ * Copyright (C) 2000-2002		Mark Lord <mlord@pobox.com>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * Development of this chipset driver was funded
+ * by the nice folks at National Semiconductor.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <linux/pm.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "sc1200.h"
+
+#define DISPLAY_SC1200_TIMINGS
+
+#if defined(DISPLAY_SC1200_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int sc1200_get_info(char *, char **, off_t, int);
+extern int (*sc1200_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+extern char *ide_media_verbose(ide_drive_t *);
+static u8 sc1200_proc = 0;
+
+#define SC1200_REV_A	0x00
+#define SC1200_REV_B1	0x01
+#define SC1200_REV_B3	0x02
+#define SC1200_REV_C1	0x03
+#define SC1200_REV_D1	0x04
+
+#define PCI_CLK_33	0x00
+#define PCI_CLK_48	0x01
+#define PCI_CLK_66	0x02
+#define PCI_CLK_33A	0x03
+
+static unsigned short sc1200_get_pci_clock (void)
+{
+	unsigned char chip_id, silicon_revision;
+	unsigned int pci_clock;
+	/*
+	 * Check the silicon revision, as not all versions of the chip
+	 * have the register with the fast PCI bus timings.
+	 */
+	chip_id = inb (0x903c);
+	silicon_revision = inb (0x903d);
+
+	// Read the fast pci clock frequency
+	if (chip_id == 0x04 && silicon_revision < SC1200_REV_B1) {
+		pci_clock = PCI_CLK_33;
+	} else {
+		// check clock generator configuration (cfcc)
+		// the clock is in bits 8 and 9 of this word
+
+		pci_clock = inw (0x901e);
+		pci_clock >>= 8;
+		pci_clock &= 0x03;
+		if (pci_clock == PCI_CLK_33A)
+			pci_clock = PCI_CLK_33;
+	}
+	return pci_clock;
+}
+
+static struct pci_dev *bmide_dev;
+
+static int sc1200_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	unsigned long bibma = pci_resource_start(bmide_dev, 4);
+	u8  c0 = 0, c1 = 0;
+
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte registers
+	 * to investigate:
+	 */
+
+	c0 = inb_p(bibma + 0x02);
+	c1 = inb_p(bibma + 0x0a);
+
+	p += sprintf(p, "\n                               National SCx200 Chipset.\n");
+	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+	p += sprintf(p, "                %sabled                         %sabled\n",
+			(c0&0x80) ? "dis" : " en",
+			(c1&0x80) ? "dis" : " en");
+	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
+	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 " );
+
+	p += sprintf(p, "UDMA\n");
+	p += sprintf(p, "DMA\n");
+	p += sprintf(p, "PIO\n");
+
+	return p-buffer;
+}
+#endif /* DISPLAY_SC1200_TIMINGS && CONFIG_PROC_FS */
+
+extern char *ide_xfer_verbose (byte xfer_rate);
+
+/*
+ * Set a new transfer mode at the drive
+ */
+int sc1200_set_xfer_mode (ide_drive_t *drive, byte mode)
+{
+	printk("%s: sc1200_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode));
+	return ide_config_drive_speed(drive, mode);
+}
+
+/*
+ * Here are the standard PIO mode 0-4 timings for each "format".
+ * Format-0 uses fast data reg timings, with slower command reg timings.
+ * Format-1 uses fast timings for all registers, but won't work with all drives.
+ */
+static const unsigned int sc1200_pio_timings[4][5] =
+	{{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},	// format0  33Mhz
+	 {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010},	// format1, 33Mhz
+	 {0xfaa3f4f3, 0xc23232b2, 0x513101c1, 0x31213121, 0x10211021},	// format1, 48Mhz
+	 {0xfff4fff4, 0xf35353d3, 0x814102f1, 0x42314231, 0x11311131}};	// format1, 66Mhz
+
+/*
+ * After chip reset, the PIO timings are set to 0x00009172, which is not valid.
+ */
+//#define SC1200_BAD_PIO(timings) (((timings)&~0x80000000)==0x00009172)
+
+static int sc1200_autoselect_dma_mode (ide_drive_t *drive)
+{
+	int			udma_ok = 1, mode = 0;
+	ide_hwif_t		*hwif = HWIF(drive);
+	int			unit = drive->select.b.unit;
+	ide_drive_t		*mate = &hwif->drives[unit^1];
+	struct hd_driveid	*id = drive->id;
+
+	/*
+	 * The SC1200 specifies that two drives sharing a cable cannot
+	 * mix UDMA/MDMA.  It has to be one or the other, for the pair,
+	 * though different timings can still be chosen for each drive.
+	 * We could set the appropriate timing bits on the fly,
+	 * but that might be a bit confusing.  So, for now we statically
+	 * handle this requirement by looking at our mate drive to see
+	 * what it is capable of, before choosing a mode for our own drive.
+	 */
+	if (mate->present) {
+		struct hd_driveid *mateid = mate->id;
+		if (mateid && (mateid->capability & 1) && !hwif->ide_dma_bad_drive(mate)) {
+			if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7))
+				udma_ok = 1;
+			else if ((mateid->field_valid & 2) && (mateid->dma_mword & 7))
+				udma_ok = 0;
+			else
+				udma_ok = 1;
+		}
+	}
+	/*
+	 * Now see what the current drive is capable of,
+	 * selecting UDMA only if the mate said it was ok.
+	 */
+	if (id && (id->capability & 1) && hwif->autodma && !hwif->ide_dma_bad_drive(drive)) {
+		if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) {
+			if      (id->dma_ultra & 4)
+				mode = XFER_UDMA_2;
+			else if (id->dma_ultra & 2)
+				mode = XFER_UDMA_1;
+			else if (id->dma_ultra & 1)
+				mode = XFER_UDMA_0;
+		}
+		if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) {
+			if      (id->dma_mword & 4)
+				mode = XFER_MW_DMA_2;
+			else if (id->dma_mword & 2)
+				mode = XFER_MW_DMA_1;
+			else if (id->dma_mword & 1)
+				mode = XFER_MW_DMA_0;
+		}
+	}
+	return mode;
+}
+
+/*
+ * sc1200_config_dma2() handles selection/setting of DMA/UDMA modes
+ * for both the chipset and drive.
+ */
+static int sc1200_config_dma2 (ide_drive_t *drive, int mode)
+{
+	ide_hwif_t		*hwif = HWIF(drive);
+	int			unit = drive->select.b.unit;
+	unsigned int		reg, timings;
+	unsigned short		pci_clock;
+	unsigned int		basereg = hwif->channel ? 0x50 : 0x40;
+
+	/*
+	 * Default to DMA-off in case we run into trouble here.
+	 */
+	hwif->ide_dma_off_quietly(drive);			/* turn off DMA while we fiddle */
+	outb(inb(hwif->dma_base+2)&~(unit?0x40:0x20), hwif->dma_base+2); /* clear DMA_capable bit */
+
+	/*
+	 * Tell the drive to switch to the new mode; abort on failure.
+	 */
+	if (!mode || sc1200_set_xfer_mode(drive, mode)) {
+		printk("SC1200: set xfer mode failure\n");
+		return 1;	/* failure */
+	}
+
+	pci_clock = sc1200_get_pci_clock();
+
+	/*
+	 * Now tune the chipset to match the drive:
+	 *
+	 * Note that each DMA mode has several timings associated with it.
+	 * The correct timing depends on the fast PCI clock freq.
+	 */
+	timings = 0;
+	switch (mode) {
+		case XFER_UDMA_0:
+			switch (pci_clock) {
+				case PCI_CLK_33:	timings = 0x00921250;	break;
+				case PCI_CLK_48:	timings = 0x00932470;	break;
+				case PCI_CLK_66:	timings = 0x009436a1;	break;
+			}
+			break;
+		case XFER_UDMA_1:
+			switch (pci_clock) {
+				case PCI_CLK_33:	timings = 0x00911140;	break;
+				case PCI_CLK_48:	timings = 0x00922260;	break;
+				case PCI_CLK_66:	timings = 0x00933481;	break;
+			}
+			break;
+		case XFER_UDMA_2:
+			switch (pci_clock) {
+				case PCI_CLK_33:	timings = 0x00911030;	break;
+				case PCI_CLK_48:	timings = 0x00922140;	break;
+				case PCI_CLK_66:	timings = 0x00923261;	break;
+			}
+			break;
+		case XFER_MW_DMA_0:
+			switch (pci_clock) {
+				case PCI_CLK_33:	timings = 0x00077771;	break;
+				case PCI_CLK_48:	timings = 0x000bbbb2;	break;
+				case PCI_CLK_66:	timings = 0x000ffff3;	break;
+			}
+			break;
+		case XFER_MW_DMA_1:
+			switch (pci_clock) {
+				case PCI_CLK_33:	timings = 0x00012121;	break;
+				case PCI_CLK_48:	timings = 0x00024241;	break;
+				case PCI_CLK_66:	timings = 0x00035352;	break;
+			}
+			break;
+		case XFER_MW_DMA_2:
+			switch (pci_clock) {
+				case PCI_CLK_33:	timings = 0x00002020;	break;
+				case PCI_CLK_48:	timings = 0x00013131;	break;
+				case PCI_CLK_66:	timings = 0x00015151;	break;
+			}
+			break;
+	}
+
+	if (timings == 0) {
+		printk("%s: sc1200_config_dma: huh? mode=%02x clk=%x \n", drive->name, mode, pci_clock);
+		return 1;	/* failure */
+	}
+
+	if (unit == 0) {			/* are we configuring drive0? */
+		pci_read_config_dword(hwif->pci_dev, basereg+4, &reg);
+		timings |= reg & 0x80000000;	/* preserve PIO format bit */
+		pci_write_config_dword(hwif->pci_dev, basereg+4, timings);
+	} else {
+		pci_write_config_dword(hwif->pci_dev, basereg+12, timings);
+	}
+
+	outb(inb(hwif->dma_base+2)|(unit?0x40:0x20), hwif->dma_base+2);	/* set DMA_capable bit */
+
+	/*
+	 * Finally, turn DMA on in software, and exit.
+	 */
+	return hwif->ide_dma_on(drive);	/* success */
+}
+
+/*
+ * sc1200_config_dma() handles selection/setting of DMA/UDMA modes
+ * for both the chipset and drive.
+ */
+static int sc1200_config_dma (ide_drive_t *drive)
+{
+	return sc1200_config_dma2(drive, sc1200_autoselect_dma_mode(drive));
+}
+
+
+/*  Replacement for the standard ide_dma_end action in
+ *  dma_proc.
+ *
+ *  returns 1 on error, 0 otherwise
+ */
+int sc1200_ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long dma_base = hwif->dma_base;
+	byte dma_stat;
+
+	dma_stat = inb(dma_base+2);		/* get DMA status */
+
+	if (!(dma_stat & 4))
+		printk(" ide_dma_end dma_stat=%0x err=%x newerr=%x\n",
+		  dma_stat, ((dma_stat&7)!=4), ((dma_stat&2)==2));
+
+	outb(dma_stat|0x1b, dma_base+2);	/* clear the INTR & ERROR bits */
+	outb(inb(dma_base)&~1, dma_base);	/* !! DO THIS HERE !! stop DMA */
+
+	drive->waiting_for_dma = 0;
+	ide_destroy_dmatable(drive);		/* purge DMA mappings */
+
+	return (dma_stat & 7) != 4;		/* verify good DMA status */
+}
+
+/*
+ * sc1200_tuneproc() handles selection/setting of PIO modes
+ * for both the chipset and drive.
+ *
+ * All existing BIOSs for this chipset guarantee that all drives
+ * will have valid default PIO timings set up before we get here.
+ */
+static void sc1200_tuneproc (ide_drive_t *drive, byte pio)	/* mode=255 means "autotune" */
+{
+	ide_hwif_t	*hwif = HWIF(drive);
+	unsigned int	format;
+	static byte	modes[5] = {XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4};
+	int		mode = -1;
+
+	switch (pio) {
+		case 200: mode = XFER_UDMA_0;	break;
+		case 201: mode = XFER_UDMA_1;	break;
+		case 202: mode = XFER_UDMA_2;	break;
+		case 100: mode = XFER_MW_DMA_0;	break;
+		case 101: mode = XFER_MW_DMA_1;	break;
+		case 102: mode = XFER_MW_DMA_2;	break;
+	}
+	if (mode != -1) {
+		printk("SC1200: %s: changing (U)DMA mode\n", drive->name);
+		(void)sc1200_config_dma2(drive, mode);
+		return;
+	}
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	printk("SC1200: %s: setting PIO mode%d\n", drive->name, pio);
+	if (!sc1200_set_xfer_mode(drive, modes[pio])) {
+		unsigned int basereg = hwif->channel ? 0x50 : 0x40;
+		pci_read_config_dword (hwif->pci_dev, basereg+4, &format);
+		format = (format >> 31) & 1;
+		if (format)
+			format += sc1200_get_pci_clock();
+		pci_write_config_dword(hwif->pci_dev, basereg + (drive->select.b.unit << 3), sc1200_pio_timings[format][pio]);
+ 	}
+}
+
+static ide_hwif_t *lookup_pci_dev (ide_hwif_t *prev, struct pci_dev *dev)
+{
+	int	h;
+
+	for (h = 0; h < MAX_HWIFS; h++) {
+		ide_hwif_t *hwif = &ide_hwifs[h];
+		if (prev) {
+			if (hwif == prev)
+				prev = NULL;	// found previous, now look for next match
+		} else {
+			if (hwif && hwif->pci_dev == dev)
+				return hwif;	// found next match
+		}
+	}
+	return NULL;	// not found
+}
+
+typedef struct sc1200_saved_state_s {
+	__u32		regs[4];
+} sc1200_saved_state_t;
+
+static int sc1200_save_state (struct pci_dev *dev, u32 state)
+{
+	ide_hwif_t		*hwif = NULL;
+
+printk("SC1200: save_state(%u)\n", state);
+	if (state != 0)
+		return 0;	// we only save state when going from full power to less
+	//
+	// Loop over all interfaces that are part of this PCI device:
+	//
+	while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
+		sc1200_saved_state_t	*ss;
+		unsigned int		basereg, r;
+		//
+		// allocate a permanent save area, if not already allocated
+		//
+		ss = (sc1200_saved_state_t *)hwif->config_data;
+		if (ss == NULL) {
+			ss = kmalloc(sizeof(sc1200_saved_state_t), GFP_KERNEL);
+			if (ss == NULL)
+				return -ENOMEM;
+			(sc1200_saved_state_t *)hwif->config_data = ss;
+		}
+		ss = (sc1200_saved_state_t *)hwif->config_data;
+		//
+		// Save timing registers:  this may be unnecessary if BIOS also does it
+		//
+		basereg = hwif->channel ? 0x50 : 0x40;
+		for (r = 0; r < 4; ++r) {
+			pci_read_config_dword (hwif->pci_dev, basereg + (r<<2), &ss->regs[r]);
+		}
+	}
+	return 0;
+}
+
+static int sc1200_suspend (struct pci_dev *dev, u32 state)
+{
+	ide_hwif_t	*hwif = NULL;
+
+	printk("SC1200: suspend(%u)\n", state);
+	/* You don't need to iterate over disks -- sysfs should have done that for you already */ 
+
+	pci_disable_device(dev);
+	pci_set_power_state(dev,state);
+	dev->current_state = state;
+	return 0;
+}
+
+static int sc1200_resume (struct pci_dev *dev)
+{
+	ide_hwif_t	*hwif = NULL;
+
+printk("SC1200: resume\n");
+	pci_set_power_state(dev,0);	// bring chip back from sleep state
+	dev->current_state = 0;
+	pci_enable_device(dev);
+	//
+	// loop over all interfaces that are part of this pci device:
+	//
+	while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
+		unsigned int		basereg, r, d, format;
+		sc1200_saved_state_t	*ss = (sc1200_saved_state_t *)hwif->config_data;
+printk("%s: SC1200: resume\n", hwif->name);
+
+		//
+		// Restore timing registers:  this may be unnecessary if BIOS also does it
+		//
+		basereg = hwif->channel ? 0x50 : 0x40;
+		if (ss != NULL) {
+			for (r = 0; r < 4; ++r) {
+				pci_write_config_dword(hwif->pci_dev, basereg + (r<<2), ss->regs[r]);
+			}
+		}
+		//
+		// Re-program drive PIO modes
+		//
+		pci_read_config_dword(hwif->pci_dev, basereg+4, &format);
+		format = (format >> 31) & 1;
+		if (format)
+			format += sc1200_get_pci_clock();
+		for (d = 0; d < 2; ++d) {
+			ide_drive_t *drive = &(hwif->drives[d]);
+			if (drive->present) {
+				unsigned int pio, timings;
+				pci_read_config_dword(hwif->pci_dev, basereg+(drive->select.b.unit << 3), &timings);
+				for (pio = 0; pio <= 4; ++pio) {
+					if (sc1200_pio_timings[format][pio] == timings)
+						break;
+				}
+				if (pio > 4)
+					pio = 255; /* autotune */
+				(void)sc1200_tuneproc(drive, pio);
+			}
+		}
+		//
+		// Re-program drive DMA modes
+		//
+		for (d = 0; d < MAX_DRIVES; ++d) {
+			ide_drive_t *drive = &(hwif->drives[d]);
+			if (drive->present && !hwif->ide_dma_bad_drive(drive)) {
+				int was_using_dma = drive->using_dma;
+				hwif->ide_dma_off_quietly(drive);
+				sc1200_config_dma(drive);
+				if (!was_using_dma && drive->using_dma) {
+					hwif->ide_dma_off_quietly(drive);
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+/*
+ * Initialize the sc1200 bridge for reliable IDE DMA operation.
+ */
+static unsigned int __init init_chipset_sc1200 (struct pci_dev *dev, const char *name)
+{
+#if defined(DISPLAY_SC1200_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!bmide_dev) {
+		sc1200_proc = 1;
+		bmide_dev = dev;
+		ide_pci_register_host_proc(&sc1200_procs[0]);
+	}
+#endif /* DISPLAY_SC1200_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+/*
+ * This gets invoked by the IDE driver once for each channel,
+ * and performs channel-specific pre-initialization before drive probing.
+ */
+static void __init init_hwif_sc1200 (ide_hwif_t *hwif)
+{
+	if (hwif->mate)
+		hwif->serialized = hwif->mate->serialized = 1;
+	hwif->autodma = 0;
+	if (hwif->dma_base) {
+		hwif->ide_dma_check = &sc1200_config_dma;
+		hwif->ide_dma_end   = &sc1200_ide_dma_end;
+        	if (!noautodma)
+                	hwif->autodma = 1;
+		hwif->tuneproc = &sc1200_tuneproc;
+	}
+        hwif->atapi_dma = 1;
+        hwif->ultra_mask = 0x07;
+        hwif->mwdma_mask = 0x07;
+
+        hwif->drives[0].autodma = hwif->autodma;
+        hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_sc1200 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+
+static int __devinit sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &sc1200_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id sc1200_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "SC1200 IDE",
+	.id_table	= sc1200_pci_tbl,
+	.probe		= sc1200_init_one,
+	.save_state	= sc1200_save_state,
+	.suspend	= sc1200_suspend,
+	.resume		= sc1200_resume,
+};
+
+static int sc1200_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void sc1200_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(sc1200_ide_init);
+module_exit(sc1200_ide_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for NS SC1200 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/sc1200.h linux-2.4.21/drivers/ide/pci/sc1200.h
--- linux-2.4.20/drivers/ide/pci/sc1200.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/sc1200.h	2002-12-18 18:58:05.000000000 +0000
@@ -0,0 +1,54 @@
+#ifndef SC1200_H
+#define SC1200_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_SC1200_TIMINGS
+
+#if defined(DISPLAY_SC1200_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 sc1200_proc;
+
+static int sc1200_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t sc1200_procs[] __initdata = {
+	{
+		name:		"sc1200",
+		set:		1,
+		get_info:	sc1200_get_info,
+		parent:		NULL,
+	},
+};
+#endif /* DISPLAY_SC1200_TIMINGS && CONFIG_PROC_FS */
+
+static unsigned int init_chipset_sc1200(struct pci_dev *, const char *);
+static void init_hwif_sc1200(ide_hwif_t *);
+static void init_dma_sc1200(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t sc1200_chipsets[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_NS,
+		device:		PCI_DEVICE_ID_NS_SCx200_IDE,
+		name:		"SC1200",
+		init_chipset:	init_chipset_sc1200,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_sc1200,
+		init_dma:	init_dma_sc1200,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* SC1200_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/serverworks.c linux-2.4.21/drivers/ide/pci/serverworks.c
--- linux-2.4.20/drivers/ide/pci/serverworks.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/serverworks.c	2002-12-18 18:58:09.000000000 +0000
@@ -0,0 +1,832 @@
+/*
+ * linux/drivers/ide/serverworks.c		Version 0.7	10 Sept 2002
+ *
+ * Copyright (C) 1998-2000 Michel Aubry
+ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ * Portions copyright (c) 2001 Sun Microsystems
+ *
+ *
+ * RCC/ServerWorks IDE driver for Linux
+ *
+ *   OSB4: `Open South Bridge' IDE Interface (fn 1)
+ *         supports UDMA mode 2 (33 MB/s)
+ *
+ *   CSB5: `Champion South Bridge' IDE Interface (fn 1)
+ *         all revisions support UDMA mode 4 (66 MB/s)
+ *         revision A2.0 and up support UDMA mode 5 (100 MB/s)
+ *
+ *         *** The CSB5 does not provide ANY register ***
+ *         *** to detect 80-conductor cable presence. ***
+ *
+ *   CSB6: `Champion South Bridge' IDE Interface (optional: third channel)
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "serverworks.h"
+
+static u8 svwks_revision = 0;
+static struct pci_dev *isa_dev;
+
+#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 svwks_proc = 0;
+#define SVWKS_MAX_DEVS		2
+static struct pci_dev *svwks_devs[SVWKS_MAX_DEVS];
+static int n_svwks_devs;
+
+static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	p += sprintf(p, "\n                             "
+			"ServerWorks OSB4/CSB5/CSB6\n");
+
+	for (i = 0; i < n_svwks_devs; i++) {
+		struct pci_dev *dev = svwks_devs[i];
+		unsigned long bibma = pci_resource_start(dev, 4);
+		u32 reg40, reg44;
+		u16 reg48, reg56;
+		u8  reg54, c0=0, c1=0;
+
+		pci_read_config_dword(dev, 0x40, &reg40);
+		pci_read_config_dword(dev, 0x44, &reg44);
+		pci_read_config_word(dev, 0x48, &reg48);
+		pci_read_config_byte(dev, 0x54, &reg54);
+		pci_read_config_word(dev, 0x56, &reg56);
+
+		/*
+		 * at that point bibma+0x2 et bibma+0xa are byte registers
+		 * to investigate:
+		 */
+		c0 = inb_p(bibma + 0x02);
+		c1 = inb_p(bibma + 0x0a);
+
+		p += sprintf(p, "\n                            ServerWorks ");
+		switch(dev->device) {
+			case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
+			case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
+				p += sprintf(p, "CSB6 ");
+				break;
+			case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+				p += sprintf(p, "CSB5 ");
+				break;
+			case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
+				p += sprintf(p, "OSB4 ");
+				break;
+			default:
+				p += sprintf(p, "%04x ", dev->device);
+				break;
+		}
+		p += sprintf(p, "Chipset (rev %02x)\n", svwks_revision);
+
+		p += sprintf(p, "------------------------------- "
+				"General Status "
+				"---------------------------------\n");
+		p += sprintf(p, "--------------- Primary Channel "
+				"---------------- Secondary Channel "
+				"-------------\n");
+		p += sprintf(p, "                %sabled"
+				"                         %sabled\n",
+				(c0&0x80) ? "dis" : " en",
+				(c1&0x80) ? "dis" : " en");
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"-------- drive0 ---------- drive1 ------\n");
+		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 " );
+		p += sprintf(p, "UDMA enabled:   %s              %s"
+				"             %s               %s\n",
+			(reg54 & 0x01) ? "yes" : "no ",
+			(reg54 & 0x02) ? "yes" : "no ",
+			(reg54 & 0x04) ? "yes" : "no ",
+			(reg54 & 0x08) ? "yes" : "no " );
+		p += sprintf(p, "UDMA enabled:   %s                %s"
+				"               %s                 %s\n",
+			((reg56&0x0005)==0x0005)?"5":
+				((reg56&0x0004)==0x0004)?"4":
+				((reg56&0x0003)==0x0003)?"3":
+				((reg56&0x0002)==0x0002)?"2":
+				((reg56&0x0001)==0x0001)?"1":
+				((reg56&0x000F))?"?":"0",
+			((reg56&0x0050)==0x0050)?"5":
+				((reg56&0x0040)==0x0040)?"4":
+				((reg56&0x0030)==0x0030)?"3":
+				((reg56&0x0020)==0x0020)?"2":
+				((reg56&0x0010)==0x0010)?"1":
+				((reg56&0x00F0))?"?":"0",
+			((reg56&0x0500)==0x0500)?"5":
+				((reg56&0x0400)==0x0400)?"4":
+				((reg56&0x0300)==0x0300)?"3":
+				((reg56&0x0200)==0x0200)?"2":
+				((reg56&0x0100)==0x0100)?"1":
+				((reg56&0x0F00))?"?":"0",
+			((reg56&0x5000)==0x5000)?"5":
+				((reg56&0x4000)==0x4000)?"4":
+				((reg56&0x3000)==0x3000)?"3":
+				((reg56&0x2000)==0x2000)?"2":
+				((reg56&0x1000)==0x1000)?"1":
+				((reg56&0xF000))?"?":"0");
+		p += sprintf(p, "DMA enabled:    %s                %s"
+				"               %s                 %s\n",
+			((reg44&0x00002000)==0x00002000)?"2":
+				((reg44&0x00002100)==0x00002100)?"1":
+				((reg44&0x00007700)==0x00007700)?"0":
+				((reg44&0x0000FF00)==0x0000FF00)?"X":"?",
+			((reg44&0x00000020)==0x00000020)?"2":
+				((reg44&0x00000021)==0x00000021)?"1":
+				((reg44&0x00000077)==0x00000077)?"0":
+				((reg44&0x000000FF)==0x000000FF)?"X":"?",
+			((reg44&0x20000000)==0x20000000)?"2":
+				((reg44&0x21000000)==0x21000000)?"1":
+				((reg44&0x77000000)==0x77000000)?"0":
+				((reg44&0xFF000000)==0xFF000000)?"X":"?",
+			((reg44&0x00200000)==0x00200000)?"2":
+				((reg44&0x00210000)==0x00210000)?"1":
+				((reg44&0x00770000)==0x00770000)?"0":
+				((reg44&0x00FF0000)==0x00FF0000)?"X":"?");
+
+		p += sprintf(p, "PIO  enabled:   %s                %s"
+				"               %s                 %s\n",
+			((reg40&0x00002000)==0x00002000)?"4":
+				((reg40&0x00002200)==0x00002200)?"3":
+				((reg40&0x00003400)==0x00003400)?"2":
+				((reg40&0x00004700)==0x00004700)?"1":
+				((reg40&0x00005D00)==0x00005D00)?"0":"?",
+			((reg40&0x00000020)==0x00000020)?"4":
+				((reg40&0x00000022)==0x00000022)?"3":
+				((reg40&0x00000034)==0x00000034)?"2":
+				((reg40&0x00000047)==0x00000047)?"1":
+				((reg40&0x0000005D)==0x0000005D)?"0":"?",
+			((reg40&0x20000000)==0x20000000)?"4":
+				((reg40&0x22000000)==0x22000000)?"3":
+				((reg40&0x34000000)==0x34000000)?"2":
+				((reg40&0x47000000)==0x47000000)?"1":
+				((reg40&0x5D000000)==0x5D000000)?"0":"?",
+			((reg40&0x00200000)==0x00200000)?"4":
+				((reg40&0x00220000)==0x00220000)?"3":
+				((reg40&0x00340000)==0x00340000)?"2":
+				((reg40&0x00470000)==0x00470000)?"1":
+				((reg40&0x005D0000)==0x005D0000)?"0":"?");
+
+	}
+	p += sprintf(p, "\n");
+
+	return p-buffer;	 /* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u8 svwks_ratemask (ide_drive_t *drive)
+{
+	struct pci_dev *dev     = HWIF(drive)->pci_dev;
+	u8 mode;
+
+	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+		u32 reg = 0;
+		if (isa_dev)
+			pci_read_config_dword(isa_dev, 0x64, &reg);
+			
+		/*
+		 *	Don't enable UDMA on disk devices for the moment
+		 */
+		if(drive->media == ide_disk)
+			return 0;
+		/* Check the OSB4 DMA33 enable bit */
+		return ((reg & 0x00004000) == 0x00004000) ? 1 : 0;
+	} else if (svwks_revision < SVWKS_CSB5_REVISION_NEW) {
+		return 1;
+	} else if (svwks_revision >= SVWKS_CSB5_REVISION_NEW) {
+		u8 btr = 0;
+		pci_read_config_byte(dev, 0x5A, &btr);
+		mode = btr;
+		if (!eighty_ninty_three(drive))
+			mode = min(mode, (u8)1);
+	}
+	if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+	     (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)))
+		mode = 2;
+	return mode;
+}
+
+static u8 svwks_csb_check (struct pci_dev *dev)
+{
+	switch (dev->device) {
+		case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+		case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
+		case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
+			return 1;
+		default:
+			break;
+	}
+	return 0;
+}
+static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	u8 udma_modes[]		= { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
+	u8 dma_modes[]		= { 0x77, 0x21, 0x20 };
+	u8 pio_modes[]		= { 0x5d, 0x47, 0x34, 0x22, 0x20 };
+	u8 drive_pci[]		= { 0x41, 0x40, 0x43, 0x42 };
+	u8 drive_pci2[]		= { 0x45, 0x44, 0x47, 0x46 };
+
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed		= ide_rate_filter(svwks_ratemask(drive), xferspeed);
+	u8 pio			= ide_get_best_pio_mode(drive, 255, 5, NULL);
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 csb5			= svwks_csb_check(dev);
+	u8 ultra_enable		= 0, ultra_timing = 0;
+	u8 dma_timing		= 0, pio_timing = 0;
+	u16 csb5_pio		= 0;
+
+	/* If we are about to put a disk into UDMA mode we screwed up.
+	   Our code assumes we never _ever_ do this on an OSB4 */
+	   
+	if(dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4 &&
+		drive->media == ide_disk && speed >= XFER_UDMA_0)
+			BUG();
+			
+	pci_read_config_byte(dev, drive_pci[drive->dn], &pio_timing);
+	pci_read_config_byte(dev, drive_pci2[drive->dn], &dma_timing);
+	pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing);
+	pci_read_config_word(dev, 0x4A, &csb5_pio);
+	pci_read_config_byte(dev, 0x54, &ultra_enable);
+
+	/* Per Specified Design by OEM, and ASIC Architect */
+	if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+	    (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {
+		if (!drive->init_speed) {
+			u8 dma_stat = hwif->INB(hwif->dma_status);
+
+dma_pio:
+			if (((ultra_enable << (7-drive->dn) & 0x80) == 0x80) &&
+			    ((dma_stat & (1<<(5+unit))) == (1<<(5+unit)))) {
+				drive->current_speed = drive->init_speed = XFER_UDMA_0 + udma_modes[(ultra_timing >> (4*unit)) & ~(0xF0)];
+				return 0;
+			} else if ((dma_timing) &&
+				   ((dma_stat&(1<<(5+unit)))==(1<<(5+unit)))) {
+				u8 dmaspeed = dma_timing;
+
+				dma_timing &= ~0xFF;
+				if ((dmaspeed & 0x20) == 0x20)
+					dmaspeed = XFER_MW_DMA_2;
+				else if ((dmaspeed & 0x21) == 0x21)
+					dmaspeed = XFER_MW_DMA_1;
+				else if ((dmaspeed & 0x77) == 0x77)
+					dmaspeed = XFER_MW_DMA_0;
+				else
+					goto dma_pio;
+				drive->current_speed = drive->init_speed = dmaspeed;
+				return 0;
+			} else if (pio_timing) {
+				u8 piospeed = pio_timing;
+
+				pio_timing &= ~0xFF;
+				if ((piospeed & 0x20) == 0x20)
+					piospeed = XFER_PIO_4;
+				else if ((piospeed & 0x22) == 0x22)
+					piospeed = XFER_PIO_3;
+				else if ((piospeed & 0x34) == 0x34)
+					piospeed = XFER_PIO_2;
+				else if ((piospeed & 0x47) == 0x47)
+					piospeed = XFER_PIO_1;
+				else if ((piospeed & 0x5d) == 0x5d)
+					piospeed = XFER_PIO_0;
+				else
+					goto oem_setup_failed;
+				drive->current_speed = drive->init_speed = piospeed;
+				return 0;
+			}
+		}
+	}
+
+oem_setup_failed:
+
+	pio_timing	&= ~0xFF;
+	dma_timing	&= ~0xFF;
+	ultra_timing	&= ~(0x0F << (4*unit));
+	ultra_enable	&= ~(0x01 << drive->dn);
+	csb5_pio	&= ~(0x0F << (4*drive->dn));
+
+	switch(speed) {
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+			pio_timing |= pio_modes[speed - XFER_PIO_0];
+			csb5_pio   |= ((speed - XFER_PIO_0) << (4*drive->dn));
+			break;
+
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+			pio_timing |= pio_modes[pio];
+			csb5_pio   |= (pio << (4*drive->dn));
+			dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
+			break;
+
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+			pio_timing   |= pio_modes[pio];
+			csb5_pio     |= (pio << (4*drive->dn));
+			dma_timing   |= dma_modes[2];
+			ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
+			ultra_enable |= (0x01 << drive->dn);
+		default:
+			break;
+	}
+
+	pci_write_config_byte(dev, drive_pci[drive->dn], pio_timing);
+	if (csb5)
+		pci_write_config_word(dev, 0x4A, csb5_pio);
+
+	pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
+	pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
+	pci_write_config_byte(dev, 0x54, ultra_enable);
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive)
+{
+	u16 eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
+	u16 xfer_pio = drive->id->eide_pio_modes;
+	u8 timing, speed, pio;
+
+	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+	if (xfer_pio > 4)
+		xfer_pio = 0;
+
+	if (drive->id->eide_pio_iordy > 0)
+		for (xfer_pio = 5;
+			xfer_pio>0 &&
+			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+			xfer_pio--);
+	else
+		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+			   (drive->id->eide_pio_modes & 2) ? 0x04 :
+			   (drive->id->eide_pio_modes & 1) ? 0x03 :
+			   (drive->id->tPIO & 2) ? 0x02 :
+			   (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
+
+	timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+	switch(timing) {
+		case 4: speed = XFER_PIO_4;break;
+		case 3: speed = XFER_PIO_3;break;
+		case 2: speed = XFER_PIO_2;break;
+		case 1: speed = XFER_PIO_1;break;
+		default:
+			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
+			break;
+	}
+	(void) svwks_tune_chipset(drive, speed);
+	drive->current_speed = speed;
+}
+
+static void svwks_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	(void) svwks_tune_chipset(drive, (XFER_PIO_0 + pio));
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, svwks_ratemask(drive));
+
+	if (!(speed))
+		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+	(void) svwks_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int svwks_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto no_dma_set;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		config_chipset_for_pio(drive);
+		//	hwif->tuneproc(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static int svwks_ide_dma_end (ide_drive_t *drive)
+{
+	/*
+	 *	We never place the OSB4 into a UDMA mode with a disk
+	 *	medium, that means the UDMA "all my data is 4 byte shifted"
+	 *	problem cannot occur.
+	 */
+#if 0
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
+
+	if ((dma_stat & 1) && drive->media == ide_disk)
+	{
+		printk(KERN_CRIT "Serverworks OSB4 in impossible state.\n");
+		printk(KERN_CRIT "Disable UDMA or if you are using Seagate then try switching disk types\n");
+		printk(KERN_CRIT "on this controller. Please report this event to osb4-bug@ide.cabal.tm\n");
+		/* Panic might sys_sync -> death by corrupt disk */
+		printk(KERN_CRIT "OSB4: continuing might cause disk corruption.\n");
+		while(1)
+			cpu_relax();
+	}
+#endif	
+	return __ide_dma_end(drive);
+}
+
+static unsigned int __init init_chipset_svwks (struct pci_dev *dev, const char *name)
+{
+	unsigned int reg;
+	u8 btr;
+
+	/* save revision id to determine DMA capability */
+	pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
+
+	/* force Master Latency Timer value to 64 PCICLKs */
+	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
+
+	/* OSB4 : South Bridge and IDE */
+	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+		isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+			  PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+		if (isa_dev) {
+			pci_read_config_dword(isa_dev, 0x64, &reg);
+			reg &= ~0x00002000; /* disable 600ns interrupt mask */
+			if(!(reg & 0x00004000))
+				printk(KERN_DEBUG "%s: UDMA not BIOS enabled.\n", name);
+			reg |=  0x00004000; /* enable UDMA/33 support */
+			pci_write_config_dword(isa_dev, 0x64, reg);
+		}
+	}
+
+	/* setup CSB5/CSB6 : South Bridge and IDE option RAID */
+	else if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ||
+		 (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+		 (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {
+//		u32 pioreg = 0, dmareg = 0;
+
+		/* Third Channel Test */
+		if (!(PCI_FUNC(dev->devfn) & 1)) {
+#if 1
+			struct pci_dev * findev = NULL;
+			u32 reg4c = 0;
+			findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+				PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL);
+			if (findev) {
+				pci_read_config_dword(findev, 0x4C, &reg4c);
+				reg4c &= ~0x000007FF;
+				reg4c |=  0x00000040;
+				reg4c |=  0x00000020;
+				pci_write_config_dword(findev, 0x4C, reg4c);
+			}
+#endif
+			outb_p(0x06, 0x0c00);
+			dev->irq = inb_p(0x0c01);
+#if 0
+			/* WE need to figure out how to get the correct one */
+			printk("%s: interrupt %d\n", name, dev->irq);
+			if (dev->irq != 0x0B)
+				dev->irq = 0x0B;
+#endif
+#if 0
+			printk("%s: device class (0x%04x)\n",
+				name, dev->class);
+#else
+			if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
+				dev->class &= ~0x000F0F00;
+		//		dev->class |= ~0x00000400;
+				dev->class |= ~0x00010100;
+				/**/
+			}
+#endif
+		} else {
+			struct pci_dev * findev = NULL;
+			u8 reg41 = 0;
+
+			findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+					PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL);
+			if (findev) {
+				pci_read_config_byte(findev, 0x41, &reg41);
+				reg41 &= ~0x40;
+				pci_write_config_byte(findev, 0x41, reg41);
+			}
+			/*
+			 * This is a device pin issue on CSB6.
+			 * Since there will be a future raid mode,
+			 * early versions of the chipset require the
+			 * interrupt pin to be set, and it is a compatablity
+			 * mode issue.
+			 */
+			dev->irq = 0;
+		}
+//		pci_read_config_dword(dev, 0x40, &pioreg)
+//		pci_write_config_dword(dev, 0x40, 0x99999999);
+//		pci_read_config_dword(dev, 0x44, &dmareg);
+//		pci_write_config_dword(dev, 0x44, 0xFFFFFFFF);
+		/* setup the UDMA Control register
+		 *
+		 * 1. clear bit 6 to enable DMA
+		 * 2. enable DMA modes with bits 0-1
+		 * 	00 : legacy
+		 * 	01 : udma2
+		 * 	10 : udma2/udma4
+		 * 	11 : udma2/udma4/udma5
+		 */
+		pci_read_config_byte(dev, 0x5A, &btr);
+		btr &= ~0x40;
+		if (!(PCI_FUNC(dev->devfn) & 1))
+			btr |= 0x2;
+		else
+			btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
+		pci_write_config_byte(dev, 0x5A, btr);
+	}
+
+
+#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
+	svwks_devs[n_svwks_devs++] = dev;
+
+	if (!svwks_proc) {
+		svwks_proc = 1;
+		ide_pci_register_host_proc(&svwks_procs[0]);
+	}
+#endif /* DISPLAY_SVWKS_TIMINGS && CONFIG_PROC_FS */
+
+	return (dev->irq) ? dev->irq : 0;
+}
+
+static unsigned int __init ata66_svwks_svwks (ide_hwif_t *hwif)
+{
+//	struct pci_dev *dev = hwif->pci_dev;
+//	return 0;
+	return 1;
+}
+
+/* On Dell PowerEdge servers with a CSB5/CSB6, the top two bits
+ * of the subsystem device ID indicate presence of an 80-pin cable.
+ * Bit 15 clear = secondary IDE channel does not have 80-pin cable.
+ * Bit 15 set   = secondary IDE channel has 80-pin cable.
+ * Bit 14 clear = primary IDE channel does not have 80-pin cable.
+ * Bit 14 set   = primary IDE channel has 80-pin cable.
+ */
+static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
+	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
+	    (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE ||
+	     dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE))
+		return ((1 << (hwif->channel + 14)) &
+			dev->subsystem_device) ? 1 : 0;
+	return 0;
+}
+
+/* Sun Cobalt Alpine hardware avoids the 80-pin cable
+ * detect issue by attaching the drives directly to the board.
+ * This check follows the Dell precedent (how scary is that?!)
+ *
+ * WARNING: this only works on Alpine hardware!
+ */
+static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
+	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
+	    dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+		return ((1 << (hwif->channel + 14)) &
+			dev->subsystem_device) ? 1 : 0;
+	return 0;
+}
+
+static unsigned int __init ata66_svwks (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+
+	/* Per Specified Design by OEM, and ASIC Architect */
+	if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+	    (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2))
+		return 1;
+
+	/* Server Works */
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS)
+		return ata66_svwks_svwks (hwif);
+	
+	/* Dell PowerEdge */
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL)
+		return ata66_svwks_dell (hwif);
+
+	/* Cobalt Alpine */
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN)
+		return ata66_svwks_cobalt (hwif);
+
+	return 0;
+}
+
+#undef CAN_SW_DMA
+static void __init init_hwif_svwks (ide_hwif_t *hwif)
+{
+	u8 dma_stat = 0;
+
+	if (!hwif->irq)
+		hwif->irq = hwif->channel ? 15 : 14;
+
+	hwif->tuneproc = &svwks_tune_drive;
+	hwif->speedproc = &svwks_tune_chipset;
+
+	hwif->atapi_dma = 1;
+
+	if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
+		hwif->ultra_mask = 0x3f;
+
+	hwif->mwdma_mask = 0x07;
+#ifdef CAN_SW_DMA
+	hwif->swdma_mask = 0x07;
+#endif /* CAN_SW_DMA */
+
+	hwif->autodma = 0;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ide_dma_check = &svwks_config_drive_xfer_rate;
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
+		hwif->ide_dma_end = &svwks_ide_dma_end;
+	else if (!(hwif->udma_four))
+		hwif->udma_four = ata66_svwks(hwif);
+	if (!noautodma)
+		hwif->autodma = 1;
+
+	dma_stat = hwif->INB(hwif->dma_status);
+	hwif->drives[0].autodma = (dma_stat & 0x20);
+	hwif->drives[1].autodma = (dma_stat & 0x40);
+	hwif->drives[0].autotune = (!(dma_stat & 0x20));
+	hwif->drives[1].autotune = (!(dma_stat & 0x40));
+//	hwif->drives[0].autodma = hwif->autodma;
+//	hwif->drives[1].autodma = hwif->autodma;
+}
+
+/*
+ * We allow the BM-DMA driver to only work on enabled interfaces.
+ */
+static void __init init_dma_svwks (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+
+	if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+	     (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)) && (hwif->channel))
+		return;
+
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if (!(PCI_FUNC(dev->devfn) & 1)) {
+		d->bootable = NEVER_BOARD;
+		if (dev->resource[0].start == 0x01f1)
+			d->bootable = ON_BOARD;
+	} else {
+		if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
+			return;
+	}
+#if 0
+	if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_CSB6) &&
+             (!(PCI_FUNC(dev->devfn) & 1)))
+		d->autodma = AUTODMA;
+#endif
+
+	d->channels = (((d->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+			(d->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
+		       (!(PCI_FUNC(dev->devfn) & 1))) ? 1 : 2;
+
+	ide_setup_pci_device(dev, d);
+}
+
+
+/**
+ *	svwks_init_one	-	called when a OSB/CSB is found
+ *	@dev: the svwks device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit svwks_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &serverworks_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id svwks_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "Serverworks IDE",
+	.id_table	= svwks_pci_tbl,
+	.probe		= svwks_init_one,
+#if 0	/* FIXME: implement */
+	.suspend	= ,
+	.resume		= ,
+#endif
+};
+
+static int svwks_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void svwks_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(svwks_ide_init);
+module_exit(svwks_ide_exit);
+
+MODULE_AUTHOR("Michael Aubry. Andrzej Krzysztofowicz, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for Serverworks OSB4/CSB5/CSB6 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/serverworks.h linux-2.4.21/drivers/ide/pci/serverworks.h
--- linux-2.4.20/drivers/ide/pci/serverworks.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/serverworks.h	2002-12-18 18:58:11.000000000 +0000
@@ -0,0 +1,105 @@
+
+#ifndef SERVERWORKS_H
+#define SERVERWORKS_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#undef SVWKS_DEBUG_DRIVE_INFO
+
+#define SVWKS_CSB5_REVISION_NEW	0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
+#define SVWKS_CSB6_REVISION	0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
+
+#define DISPLAY_SVWKS_TIMINGS	1
+
+#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 svwks_proc;
+
+static int svwks_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t svwks_procs[] __initdata = {
+{
+		.name		= "svwks",
+		.set		= 1,
+		.get_info	= svwks_get_info,
+		.parent		= NULL,
+	},
+};
+#endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_svwks(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_csb6(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_svwks(struct pci_dev *, const char *);
+static void init_hwif_svwks(ide_hwif_t *);
+static void init_dma_svwks(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t serverworks_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_SERVERWORKS,
+		.device		= PCI_DEVICE_ID_SERVERWORKS_OSB4IDE,
+		.name		= "SvrWks OSB4",
+		.init_setup	= init_setup_svwks,
+		.init_chipset	= init_chipset_svwks,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_svwks,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_SERVERWORKS,
+		.device		= PCI_DEVICE_ID_SERVERWORKS_CSB5IDE,
+		.name		= "SvrWks CSB5",
+		.init_setup	= init_setup_svwks,
+		.init_chipset	= init_chipset_svwks,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_svwks,
+		.init_dma	= init_dma_svwks,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_SERVERWORKS,
+		.device		= PCI_DEVICE_ID_SERVERWORKS_CSB6IDE,
+		.name		= "SvrWks CSB6",
+		.init_setup	= init_setup_csb6,
+		.init_chipset	= init_chipset_svwks,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_svwks,
+		.init_dma	= init_dma_svwks,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_SERVERWORKS,
+		.device		= PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2,
+		.name		= "SvrWks CSB6",
+		.init_setup	= init_setup_csb6,
+		.init_chipset	= init_chipset_svwks,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_svwks,
+		.init_dma	= init_dma_svwks,
+		.channels	= 1,	/* 2 */
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* SERVERWORKS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/siimage.c linux-2.4.21/drivers/ide/pci/siimage.c
--- linux-2.4.20/drivers/ide/pci/siimage.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/siimage.c	2002-12-18 18:58:05.000000000 +0000
@@ -0,0 +1,874 @@
+/*
+ * linux/drivers/ide/siimage.c		Version 1.01	Sept 11, 2002
+ *
+ * Copyright (C) 2001-2002	Andre Hedrick <andre@linux-ide.org>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "siimage.h"
+
+#if defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 siimage_proc = 0;
+#define SIIMAGE_MAX_DEVS		5
+static struct pci_dev *siimage_devs[SIIMAGE_MAX_DEVS];
+static int n_siimage_devs;
+
+static char * print_siimage_get_info (char *buf, struct pci_dev *dev, int index)
+{
+	char *p		= buf;
+	u8 mmio		= (pci_get_drvdata(dev) != NULL) ? 1 : 0;
+	unsigned long bmdma	= (mmio) ? ((unsigned long) pci_get_drvdata(dev)) :
+				    (pci_resource_start(dev, 4));
+
+	p += sprintf(p, "\nController: %d\n", index);
+	p += sprintf(p, "SiI%x Chipset.\n", dev->device);
+	if (mmio)
+		p += sprintf(p, "MMIO Base 0x%lx\n", bmdma);
+	p += sprintf(p, "%s-DMA Base 0x%lx\n", (mmio)?"MMIO":"BM", bmdma);
+	p += sprintf(p, "%s-DMA Base 0x%lx\n", (mmio)?"MMIO":"BM", bmdma+8);
+
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "PIO Mode:       %s                %s"
+			"               %s                 %s\n",
+			"?", "?", "?", "?");
+	return (char *)p;
+}
+
+static int siimage_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	u16 i;
+
+	p += sprintf(p, "\n");
+	for (i = 0; i < n_siimage_devs; i++) {
+		struct pci_dev *dev	= siimage_devs[i];
+		p = print_siimage_get_info(p, dev, i);
+	}
+	return p-buffer;	/* => must be less than 4k! */
+}
+
+#endif	/* defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static byte siimage_ratemask (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 mode	= 0, scsc = 0;
+
+	if (hwif->mmio)
+		scsc = hwif->INB(HWIFADDR(0x4A));
+	else
+		pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);
+
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_SII_3112:
+			return 4;
+		case PCI_DEVICE_ID_SII_680:
+			if ((scsc & 0x10) == 0x10)	/* 133 */
+				mode = 4;
+			else if ((scsc & 0x30) == 0x00)	/* 100 */
+				mode = 3;
+			else if ((scsc & 0x20) == 0x20)	/* 66 eek */
+				BUG();	// mode = 2;
+			break;
+		default:	return 0;
+	}
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static byte siimage_taskfile_timing (ide_hwif_t *hwif)
+{
+	u16 timing	= 0x328a;
+
+	if (hwif->mmio)
+		timing = hwif->INW(SELADDR(2));
+	else
+		pci_read_config_word(hwif->pci_dev, SELREG(2), &timing);
+
+	switch (timing) {
+		case 0x10c1:	return 4;
+		case 0x10c3:	return 3;
+		case 0x1281:	return 2;
+		case 0x2283:	return 1;
+		case 0x328a:
+		default:	return 0;
+	}
+}
+
+static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u16 speedt		= 0;
+	u8 unit			= drive->select.b.unit;
+
+	if (hwif->mmio)
+		speedt = hwif->INW(SELADDR(0x04|(unit<<unit)));
+	else
+		pci_read_config_word(dev, SELADDR(0x04|(unit<<unit)), &speedt);
+
+	/* cheat for now and use the docs */
+//	switch(siimage_taskfile_timing(hwif)) {
+	switch(mode_wanted) {
+		case 4:		speedt = 0x10c1; break;
+		case 3:		speedt = 0x10C3; break;
+		case 2:		speedt = 0x1104; break;
+		case 1:		speedt = 0x2283; break;
+		case 0:
+		default:	speedt = 0x328A; break;
+	}
+	if (hwif->mmio)
+		hwif->OUTW(speedt, SELADDR(0x04|(unit<<unit)));
+	else
+		pci_write_config_word(dev, SELADDR(0x04|(unit<<unit)), speedt);
+}
+
+static void config_siimage_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+	u8 channel_timings	= siimage_taskfile_timing(HWIF(drive));
+	u8 speed = 0, set_pio	= ide_get_best_pio_mode(drive, 4, 5, NULL);
+
+	/* WARNING PIO timing mess is going to happen b/w devices, argh */
+	if ((channel_timings != set_pio) && (set_pio > channel_timings))
+		set_pio = channel_timings;
+
+	siimage_tuneproc(drive, set_pio);
+	speed = XFER_PIO_0 + set_pio;
+	if (set_speed)
+		(void) ide_config_drive_speed(drive, speed);
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+	config_siimage_chipset_for_pio(drive, set_speed);
+}
+
+static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
+{
+	u8 ultra6[]		= { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 };
+	u8 ultra5[]		= { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 };
+	u16 dma[]		= { 0x2208, 0x10C2, 0x10C1 };
+
+	ide_hwif_t *hwif	= HWIF(drive);
+	u16 ultra = 0, multi	= 0;
+	u8 mode = 0, unit	= drive->select.b.unit;
+	u8 speed	= ide_rate_filter(siimage_ratemask(drive), xferspeed);
+	u8 scsc = 0, addr_mask	= ((hwif->channel) ?
+				    ((hwif->mmio) ? 0xF4 : 0x84) :
+				    ((hwif->mmio) ? 0xB4 : 0x80));
+
+	if (hwif->mmio) {
+		scsc = hwif->INB(HWIFADDR(0x4A));
+		mode = hwif->INB(HWIFADDR(addr_mask));
+		multi = hwif->INW(SELADDR(0x08|(unit<<unit)));
+		ultra = hwif->INW(SELADDR(0x0C|(unit<<unit)));
+	} else {
+		pci_read_config_byte(hwif->pci_dev, HWIFADDR(0x8A), &scsc);
+		pci_read_config_byte(hwif->pci_dev, addr_mask, &mode);
+		pci_read_config_word(hwif->pci_dev,
+				SELREG(0x08|(unit<<unit)), &multi);
+		pci_read_config_word(hwif->pci_dev,
+				SELREG(0x0C|(unit<<unit)), &ultra);
+	}
+
+	mode &= ~((unit) ? 0x30 : 0x03);
+	ultra &= ~0x3F;
+	scsc = ((scsc & 0x30) == 0x00) ? 0 : 1;
+
+	scsc = (hwif->pci_dev->device == PCI_DEVICE_ID_SII_3112) ? 1 : scsc;
+
+	switch(speed) {
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+			siimage_tuneproc(drive, (speed - XFER_PIO_0));
+			mode |= ((unit) ? 0x10 : 0x01);
+			break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+			multi = dma[speed - XFER_MW_DMA_0];
+			mode |= ((unit) ? 0x20 : 0x02);
+			config_siimage_chipset_for_pio(drive, 0);
+			break;
+		case XFER_UDMA_6:
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+			multi = dma[2];
+			ultra |= ((scsc) ? (ultra5[speed - XFER_UDMA_0]) :
+					   (ultra6[speed - XFER_UDMA_0]));
+			mode |= ((unit) ? 0x30 : 0x03);
+			config_siimage_chipset_for_pio(drive, 0);
+			break;
+		default:
+			return 1;
+	}
+
+	if (hwif->mmio) {
+		hwif->OUTB(mode, HWIFADDR(addr_mask));
+		hwif->OUTW(multi, SELADDR(0x08|(unit<<unit)));
+		hwif->OUTW(ultra, SELADDR(0x0C|(unit<<unit)));
+	} else {
+		pci_write_config_byte(hwif->pci_dev, addr_mask, mode);
+		pci_write_config_word(hwif->pci_dev,
+				SELREG(0x08|(unit<<unit)), multi);
+		pci_write_config_word(hwif->pci_dev,
+				SELREG(0x0C|(unit<<unit)), ultra);
+	}
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed	= ide_dma_speed(drive, siimage_ratemask(drive));
+
+	config_chipset_for_pio(drive, (!(speed)));
+
+	if ((!(speed)))
+		return 0;
+
+	if (ide_set_xfer_rate(drive, speed))
+		return 0;
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+
+	return ide_dma_enable(drive);
+}
+
+static int siimage_config_drive_for_dma (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	if ((id != NULL) && ((id->capability & 1) != 0) && drive->autodma) {
+		if (!(hwif->atapi_dma))
+			goto fast_ata_pio;
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+
+		if ((id->field_valid & 4) && siimage_ratemask(drive)) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		config_chipset_for_pio(drive, 1);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+/* returns 1 if dma irq issued, 0 otherwise */
+static int siimage_io_ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_altstat		= 0;
+
+	/* return 1 if INTR asserted */
+	if ((hwif->INB(hwif->dma_status) & 4) == 4)
+		return 1;
+
+	/* return 1 if Device INTR asserted */
+	if ((pci_read_config_byte(hwif->pci_dev, SELREG(1), &dma_altstat)),
+	    ((dma_altstat & 8) == 8))
+		return 0;	//return 1;
+
+	return 0;
+}
+
+static int siimage_mmio_ide_dma_count (ide_drive_t *drive)
+{
+#ifdef SIIMAGE_VIRTUAL_DMAPIO
+	struct request *rq	= HWGROUP(drive)->rq;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u32 count		= (rq->nr_sectors * SECTOR_SIZE);
+	u32 rcount		= 0;
+
+	hwif->OUTL(count, SELADDR(0x1C));
+	rcount = hwif->INL(SELADDR(0x1C));
+
+	printk("\n%s: count = %d, rcount = %d, nr_sectors = %lu\n",
+		drive->name, count, rcount, rq->nr_sectors);
+
+#endif /* SIIMAGE_VIRTUAL_DMAPIO */
+	return __ide_dma_count(drive);
+}
+
+/* returns 1 if dma irq issued, 0 otherwise */
+static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+
+	if (SATA_ERROR_REG) {
+		u32 ext_stat = hwif->INL(HWIFADDR(0x10));
+		u8 watchdog = 0;
+		if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) {
+			u32 sata_error = hwif->INL(SATA_ERROR_REG);
+			hwif->OUTL(sata_error, SATA_ERROR_REG);
+			watchdog = (sata_error & 0x00680000) ? 1 : 0;
+#if 1
+			printk("%s: sata_error = 0x%08x, "
+				"watchdog = %d, %s\n",
+				drive->name, sata_error, watchdog,
+				__FUNCTION__);
+#endif
+
+		} else {
+			watchdog = (ext_stat & 0x8000) ? 1 : 0;
+		}
+		ext_stat >>= 16;
+
+		if (!(ext_stat & 0x0404) && !watchdog)
+			return 0;
+	}
+
+	/* return 1 if INTR asserted */
+	if ((hwif->INB(hwif->dma_status) & 0x04) == 0x04)
+		return 1;
+
+	/* return 1 if Device INTR asserted */
+	if ((hwif->INB(SELADDR(1)) & 8) == 8)
+		return 0;	//return 1;
+
+	return 0;
+}
+
+static int siimage_mmio_ide_dma_verbose (ide_drive_t *drive)
+{
+	int temp = __ide_dma_verbose(drive);
+#if 0
+	drive->using_dma = 0;
+#endif
+	return temp;
+}
+
+static int siimage_busproc (ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u32 stat_config		= 0;
+
+	if (hwif->mmio) {
+		stat_config = hwif->INL(SELADDR(0));
+	} else
+		pci_read_config_dword(hwif->pci_dev, SELREG(0), &stat_config);
+
+	switch (state) {
+		case BUSSTATE_ON:
+			hwif->drives[0].failures = 0;
+			hwif->drives[1].failures = 0;
+			break;
+		case BUSSTATE_OFF:
+			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+			break;
+		case BUSSTATE_TRISTATE:
+			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+			break;
+		default:
+			return 0;
+	}
+	hwif->bus_state = state;
+	return 0;
+}
+
+static int siimage_reset_poll (ide_drive_t *drive)
+{
+	if (SATA_STATUS_REG) {
+		ide_hwif_t *hwif	= HWIF(drive);
+
+		if ((hwif->INL(SATA_STATUS_REG) & 0x03) != 0x03) {
+			printk("%s: reset phy dead, status=0x%08x\n",
+				hwif->name, hwif->INL(SATA_STATUS_REG));
+			HWGROUP(drive)->poll_timeout = 0;
+#if 0
+			drive->failures++;
+			return ide_stopped;
+#else
+			return ide_started;
+#endif
+			return 1;
+		}
+		return 0;
+	} else {
+		return 0;
+	}
+}
+
+static void siimage_pre_reset (ide_drive_t *drive)
+{
+	if (drive->media != ide_disk)
+		return;
+
+	if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_SII_3112) {
+		drive->special.b.set_geometry = 0;
+		drive->special.b.recalibrate = 0;
+	}
+}
+
+static void siimage_reset (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 reset		= 0;
+
+	if (hwif->mmio) {
+		reset = hwif->INB(SELADDR(0));
+		hwif->OUTB((reset|0x03), SELADDR(0));
+		udelay(25);
+		hwif->OUTB(reset, SELADDR(0));
+		(void) hwif->INB(SELADDR(0));
+	} else {
+		pci_read_config_byte(hwif->pci_dev, SELREG(0), &reset);
+		pci_write_config_byte(hwif->pci_dev, SELREG(0), reset|0x03);
+		udelay(25);
+		pci_write_config_byte(hwif->pci_dev, SELREG(0), reset);
+		pci_read_config_byte(hwif->pci_dev, SELREG(0), &reset);
+	}
+
+	if (SATA_STATUS_REG) {
+		u32 sata_stat = hwif->INL(SATA_STATUS_REG);
+		printk("%s: reset phy, status=0x%08x, %s\n",
+			hwif->name, sata_stat, __FUNCTION__);
+		if (!(sata_stat)) {
+			printk("%s: reset phy dead, status=0x%08x\n",
+				hwif->name, sata_stat);
+			drive->failures++;
+		}
+	}
+
+}
+
+static void proc_reports_siimage (struct pci_dev *dev, u8 clocking, const char *name)
+{
+	if (dev->device == PCI_DEVICE_ID_SII_3112)
+		goto sata_skip;
+
+	printk("%s: BASE CLOCK ", name);
+	clocking &= ~0x0C;
+	switch(clocking) {
+		case 0x03: printk("DISABLED !\n"); break;
+		case 0x02: printk("== 2X PCI \n"); break;
+		case 0x01: printk("== 133 \n"); break;
+		case 0x00: printk("== 100 \n"); break;
+		default:
+			BUG();
+	}
+
+sata_skip:
+
+#if defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS)
+	siimage_devs[n_siimage_devs++] = dev;
+
+	if (!siimage_proc) {
+		siimage_proc = 1;
+		ide_pci_register_host_proc(&siimage_procs[0]);
+	}
+#endif /* DISPLAY_SIIMAGE_TIMINGS && CONFIG_PROC_FS */
+}
+
+#ifdef CONFIG_TRY_MMIO_SIIMAGE
+static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name)
+{
+	unsigned long bar5	= pci_resource_start(dev, 5);
+	unsigned long end5	= pci_resource_end(dev, 5);
+	u8 tmpbyte	= 0;
+	unsigned long addr;
+	void *ioaddr;
+
+	ioaddr = ioremap_nocache(bar5, (end5 - bar5));
+
+	if (ioaddr == NULL)
+		return 0;
+
+	pci_set_master(dev);
+	pci_set_drvdata(dev, ioaddr);
+	addr = (unsigned long) ioaddr;
+
+	if (dev->device == PCI_DEVICE_ID_SII_3112) {
+		sii_outl(0, DEVADDR(0x148));
+		sii_outl(0, DEVADDR(0x1C8));
+	}
+
+	sii_outb(0, DEVADDR(0xB4));
+	sii_outb(0, DEVADDR(0xF4));
+	tmpbyte = sii_inb(DEVADDR(0x4A));
+
+	switch(tmpbyte) {
+		case 0x01:
+			sii_outb(tmpbyte|0x10, DEVADDR(0x4A));
+			tmpbyte = sii_inb(DEVADDR(0x4A));
+		case 0x31:
+			/* if clocking is disabled */
+			/* 133 clock attempt to force it on */
+			sii_outb(tmpbyte & ~0x20, DEVADDR(0x4A));
+			tmpbyte = sii_inb(DEVADDR(0x4A));
+		case 0x11:
+		case 0x21:
+			break;
+		default:
+			tmpbyte &= ~0x30;
+			tmpbyte |= 0x20;
+			sii_outb(tmpbyte, DEVADDR(0x4A));
+			break;
+	}
+	
+	sii_outb(0x72, DEVADDR(0xA1));
+	sii_outw(0x328A, DEVADDR(0xA2));
+	sii_outl(0x62DD62DD, DEVADDR(0xA4));
+	sii_outl(0x43924392, DEVADDR(0xA8));
+	sii_outl(0x40094009, DEVADDR(0xAC));
+	sii_outb(0x72, DEVADDR(0xE1));
+	sii_outw(0x328A, DEVADDR(0xE2));
+	sii_outl(0x62DD62DD, DEVADDR(0xE4));
+	sii_outl(0x43924392, DEVADDR(0xE8));
+	sii_outl(0x40094009, DEVADDR(0xEC));
+
+	if (dev->device == PCI_DEVICE_ID_SII_3112) {
+		sii_outl(0xFFFF0000, DEVADDR(0x108));
+		sii_outl(0xFFFF0000, DEVADDR(0x188));
+		sii_outl(0x00680000, DEVADDR(0x148));
+		sii_outl(0x00680000, DEVADDR(0x1C8));
+	}
+
+	tmpbyte = sii_inb(DEVADDR(0x4A));
+
+	proc_reports_siimage(dev, (tmpbyte>>=4), name);
+	return 1;
+}
+#endif /* CONFIG_TRY_MMIO_SIIMAGE */
+
+static unsigned int __init init_chipset_siimage (struct pci_dev *dev, const char *name)
+{
+	u32 class_rev	= 0;
+	u8 tmpbyte	= 0;
+#ifdef CONFIG_TRY_MMIO_SIIMAGE
+	u8 BA5_EN	= 0;
+#endif /* CONFIG_TRY_MMIO_SIIMAGE */
+
+        pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+        class_rev &= 0xff;
+	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (class_rev) ? 1 : 255);	
+
+#ifdef CONFIG_TRY_MMIO_SIIMAGE
+	pci_read_config_byte(dev, 0x8A, &BA5_EN);
+	if ((BA5_EN & 0x01) || (pci_resource_start(dev, 5))) {
+		if (setup_mmio_siimage(dev, name)) {
+			return 0;
+		}
+	}
+#endif /* CONFIG_TRY_MMIO_SIIMAGE */
+
+	pci_write_config_byte(dev, 0x80, 0x00);
+	pci_write_config_byte(dev, 0x84, 0x00);
+	pci_read_config_byte(dev, 0x8A, &tmpbyte);
+	switch(tmpbyte) {
+		case 0x00:
+		case 0x01:
+			/* 133 clock attempt to force it on */
+			pci_write_config_byte(dev, 0x8A, tmpbyte|0x10);
+			pci_read_config_byte(dev, 0x8A, &tmpbyte);
+		case 0x30:
+		case 0x31:
+			/* if clocking is disabled */
+			/* 133 clock attempt to force it on */
+			pci_write_config_byte(dev, 0x8A, tmpbyte & ~0x20);
+			pci_read_config_byte(dev, 0x8A, &tmpbyte);
+		case 0x10:
+		case 0x11:
+		case 0x20:
+		case 0x21:
+			break;
+		default:
+			tmpbyte &= ~0x30;
+			tmpbyte |= 0x20;
+			pci_write_config_byte(dev, 0x8A, tmpbyte);
+			break;
+	}
+
+	pci_read_config_byte(dev, 0x8A, &tmpbyte);
+	pci_write_config_byte(dev, 0xA1, 0x72);
+	pci_write_config_word(dev, 0xA2, 0x328A);
+	pci_write_config_dword(dev, 0xA4, 0x62DD62DD);
+	pci_write_config_dword(dev, 0xA8, 0x43924392);
+	pci_write_config_dword(dev, 0xAC, 0x40094009);
+	pci_write_config_byte(dev, 0xB1, 0x72);
+	pci_write_config_word(dev, 0xB2, 0x328A);
+	pci_write_config_dword(dev, 0xB4, 0x62DD62DD);
+	pci_write_config_dword(dev, 0xB8, 0x43924392);
+	pci_write_config_dword(dev, 0xBC, 0x40094009);
+
+	pci_read_config_byte(dev, 0x8A, &tmpbyte);
+	proc_reports_siimage(dev, (tmpbyte>>=4), name);
+	return 0;
+}
+
+static void __init init_mmio_iops_siimage (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned long addr	= (unsigned long) pci_get_drvdata(hwif->pci_dev);
+	u8 ch			= hwif->channel;
+//	u16 i			= 0;
+	hw_regs_t hw;
+
+	hwif->OUTB  = sii_outb;
+	hwif->OUTW  = sii_outw;
+	hwif->OUTL  = sii_outl;
+	hwif->OUTSW = sii_outsw;
+	hwif->OUTSL = sii_outsl;
+	hwif->INB   = sii_inb;
+	hwif->INW   = sii_inw;
+	hwif->INL   = sii_inl;
+	hwif->INSW  = sii_insw;
+	hwif->INSL  = sii_insl;
+
+	memset(&hw, 0, sizeof(hw_regs_t));
+
+#if 1
+#ifdef SIIMAGE_BUFFERED_TASKFILE
+	hw.io_ports[IDE_DATA_OFFSET]	= DEVADDR((ch) ? 0xD0 : 0x90);
+	hw.io_ports[IDE_ERROR_OFFSET]	= DEVADDR((ch) ? 0xD1 : 0x91);
+	hw.io_ports[IDE_NSECTOR_OFFSET]	= DEVADDR((ch) ? 0xD2 : 0x92);
+	hw.io_ports[IDE_SECTOR_OFFSET]	= DEVADDR((ch) ? 0xD3 : 0x93);
+	hw.io_ports[IDE_LCYL_OFFSET]	= DEVADDR((ch) ? 0xD4 : 0x94);
+	hw.io_ports[IDE_HCYL_OFFSET]	= DEVADDR((ch) ? 0xD5 : 0x95);
+	hw.io_ports[IDE_SELECT_OFFSET]	= DEVADDR((ch) ? 0xD6 : 0x96);
+	hw.io_ports[IDE_STATUS_OFFSET]	= DEVADDR((ch) ? 0xD7 : 0x97);
+	hw.io_ports[IDE_CONTROL_OFFSET]	= DEVADDR((ch) ? 0xDA : 0x9A);
+#else /* ! SIIMAGE_BUFFERED_TASKFILE */
+	hw.io_ports[IDE_DATA_OFFSET]	= DEVADDR((ch) ? 0xC0 : 0x80);
+	hw.io_ports[IDE_ERROR_OFFSET]	= DEVADDR((ch) ? 0xC1 : 0x81);
+	hw.io_ports[IDE_NSECTOR_OFFSET]	= DEVADDR((ch) ? 0xC2 : 0x82);
+	hw.io_ports[IDE_SECTOR_OFFSET]	= DEVADDR((ch) ? 0xC3 : 0x83);
+	hw.io_ports[IDE_LCYL_OFFSET]	= DEVADDR((ch) ? 0xC4 : 0x84);
+	hw.io_ports[IDE_HCYL_OFFSET]	= DEVADDR((ch) ? 0xC5 : 0x85);
+	hw.io_ports[IDE_SELECT_OFFSET]	= DEVADDR((ch) ? 0xC6 : 0x86);
+	hw.io_ports[IDE_STATUS_OFFSET]	= DEVADDR((ch) ? 0xC7 : 0x87);
+	hw.io_ports[IDE_CONTROL_OFFSET]	= DEVADDR((ch) ? 0xCA : 0x8A);
+#endif /* SIIMAGE_BUFFERED_TASKFILE */
+#else
+#ifdef SIIMAGE_BUFFERED_TASKFILE
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		hw.io_ports[i] = DEVADDR((ch) ? 0xD0 : 0x90)|(i);
+	hw.io_ports[IDE_CONTROL_OFFSET] = DEVADDR((ch) ? 0xDA : 0x9A);
+#else /* ! SIIMAGE_BUFFERED_TASKFILE */
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		hw.io_ports[i] = DEVADDR((ch) ? 0xC0 : 0x80)|(i);
+	hw.io_ports[IDE_CONTROL_OFFSET] = DEVADDR((ch) ? 0xCA : 0x8A);
+#endif /* SIIMAGE_BUFFERED_TASKFILE */
+#endif
+
+#if 0
+	printk("%s: ", hwif->name);
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		printk("0x%08x ", DEVADDR((ch) ? 0xC0 : 0x80)|(i));
+	printk("0x%08x ", DEVADDR((ch) ? 0xCA : 0x8A)|(i));
+#endif
+
+	hw.io_ports[IDE_IRQ_OFFSET]	= 0;
+
+        if (dev->device == PCI_DEVICE_ID_SII_3112) {
+		hw.sata_scr[SATA_STATUS_OFFSET]	= DEVADDR((ch) ? 0x184 : 0x104);
+		hw.sata_scr[SATA_ERROR_OFFSET]	= DEVADDR((ch) ? 0x188 : 0x108);
+		hw.sata_scr[SATA_CONTROL_OFFSET]= DEVADDR((ch) ? 0x180 : 0x100);
+		hw.sata_misc[SATA_MISC_OFFSET]	= DEVADDR((ch) ? 0x1C0 : 0x140);
+		hw.sata_misc[SATA_PHY_OFFSET]	= DEVADDR((ch) ? 0x1C4 : 0x144);
+		hw.sata_misc[SATA_IEN_OFFSET]	= DEVADDR((ch) ? 0x1C8 : 0x148);
+	}
+
+	hw.priv				= (void *) addr;
+//	hw.priv				= pci_get_drvdata(hwif->pci_dev);
+	hw.irq				= hwif->pci_dev->irq;
+//	hw.iops				= siimage_iops;
+
+	memcpy(&hwif->hw, &hw, sizeof(hw));
+	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));
+
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_SII_3112) {
+		memcpy(hwif->sata_scr, hwif->hw.sata_scr, sizeof(hwif->hw.sata_scr));
+		memcpy(hwif->sata_misc, hwif->hw.sata_misc, sizeof(hwif->hw.sata_misc));
+	}
+
+#ifdef SIIMAGE_BUFFERED_TASKFILE
+        hwif->addressing = 1;
+#endif /* SIIMAGE_BUFFERED_TASKFILE */
+	hwif->irq			= hw.irq;
+	hwif->hwif_data			= pci_get_drvdata(hwif->pci_dev);
+
+#ifdef SIIMAGE_LARGE_DMA
+	hwif->dma_base			= DEVADDR((ch) ? 0x18 : 0x10);
+	hwif->dma_base2			= DEVADDR((ch) ? 0x08 : 0x00);
+	hwif->dma_prdtable		= (hwif->dma_base2 + 4);
+#else /* ! SIIMAGE_LARGE_DMA */
+	hwif->dma_base			= DEVADDR((ch) ? 0x08 : 0x00);
+	hwif->dma_base2			= DEVADDR((ch) ? 0x18 : 0x10);
+#endif /* SIIMAGE_LARGE_DMA */
+	hwif->mmio			= 1;
+}
+
+static void __init init_iops_siimage (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	u32 class_rev		= 0;
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+	hwif->rqsize = 128;
+	if ((dev->device == PCI_DEVICE_ID_SII_3112) && (!(class_rev)))
+		hwif->rqsize = 16;
+
+	if (pci_get_drvdata(dev) == NULL)
+		return;
+	init_mmio_iops_siimage(hwif);
+}
+
+static unsigned int __init ata66_siimage (ide_hwif_t *hwif)
+{
+	if (pci_get_drvdata(hwif->pci_dev) == NULL) {
+		u8 ata66 = 0;
+		pci_read_config_byte(hwif->pci_dev, SELREG(0), &ata66);
+		return (ata66 & 0x01) ? 1 : 0;
+	}
+#ifndef CONFIG_TRY_MMIO_SIIMAGE
+	if (hwif->mmio) BUG();
+#endif /* CONFIG_TRY_MMIO_SIIMAGE */
+
+	return (hwif->INB(SELADDR(0)) & 0x01) ? 1 : 0;
+}
+
+static void __init init_hwif_siimage (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->busproc   = &siimage_busproc;
+	hwif->resetproc = &siimage_reset;
+	hwif->speedproc = &siimage_tune_chipset;
+	hwif->tuneproc	= &siimage_tuneproc;
+	hwif->reset_poll = &siimage_reset_poll;
+	hwif->pre_reset = &siimage_pre_reset;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (hwif->pci_dev->device != PCI_DEVICE_ID_SII_3112)
+		hwif->atapi_dma = 1;
+
+	hwif->ide_dma_check = &siimage_config_drive_for_dma;
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66_siimage(hwif);
+
+	if (hwif->mmio) {
+		hwif->ide_dma_count = &siimage_mmio_ide_dma_count;
+		hwif->ide_dma_test_irq = &siimage_mmio_ide_dma_test_irq;
+		hwif->ide_dma_verbose = &siimage_mmio_ide_dma_verbose;
+	} else {
+		hwif->ide_dma_test_irq = & siimage_io_ide_dma_test_irq;
+	}
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_siimage (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+
+static int __devinit siimage_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &siimage_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id siimage_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "SiI IDE",
+	.id_table	= siimage_pci_tbl,
+	.probe		= siimage_init_one,
+};
+
+static int siimage_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void siimage_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(siimage_ide_init);
+module_exit(siimage_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for SiI IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/siimage.h linux-2.4.21/drivers/ide/pci/siimage.h
--- linux-2.4.20/drivers/ide/pci/siimage.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/siimage.h	2002-12-18 18:58:01.000000000 +0000
@@ -0,0 +1,148 @@
+#ifndef SIIMAGE_H
+#define SIIMAGE_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#define DISPLAY_SIIMAGE_TIMINGS
+
+#define CONFIG_TRY_MMIO_SIIMAGE
+//#undef CONFIG_TRY_MMIO_SIIMAGE
+#undef SIIMAGE_VIRTUAL_DMAPIO
+#undef SIIMAGE_BUFFERED_TASKFILE
+#undef SIIMAGE_LARGE_DMA
+
+#if 0
+typedef struct ide_io_ops_s siimage_iops {
+
+}
+#endif
+
+#define SII_DEBUG 0
+
+#if SII_DEBUG
+#define siiprintk(x...)	printk(x)
+#else
+#define siiprintk(x...)
+#endif
+
+#define ADJREG(B,R)	((B)|(R)|((hwif->channel)<<(4+(2*(hwif->mmio)))))
+#define SELREG(R)	ADJREG((0xA0),(R))
+#define SELADDR(R)	((((unsigned long)hwif->hwif_data)*(hwif->mmio))|SELREG((R)))
+#define HWIFADDR(R)	((((unsigned long)hwif->hwif_data)*(hwif->mmio))|(R))
+#define DEVADDR(R)	(((unsigned long) pci_get_drvdata(dev))|(R))
+
+
+inline u8 sii_inb (unsigned long port)
+{
+	return (u8) readb(port);
+}
+
+inline u16 sii_inw (unsigned long port)
+{
+	return (u16) readw(port);
+}
+
+inline void sii_insw (unsigned long port, void *addr, u32 count)
+{
+	__ide_mm_insw(port, addr, count);
+}
+
+inline u32 sii_inl (unsigned long port)
+{
+	return (u32) readl(port);
+}
+
+inline void sii_insl (unsigned long port, void *addr, u32 count)
+{
+	__ide_mm_insw(port, addr, (count)<<1);
+}
+
+inline void sii_outb (u8 value, unsigned long port)
+{
+	writeb(value, port);
+}
+
+inline void sii_outw (u16 value, unsigned long port)
+{
+	writew(value, port);
+}
+
+inline void sii_outsw (unsigned long port, void *addr, u32 count)
+{
+	__ide_mm_outsw(port, addr, count);
+}
+
+inline void sii_outl (u32 value, unsigned long port)
+{
+	writel(value, port);
+}
+
+inline void sii_outsl (unsigned long port, void *addr, u32 count)
+{
+	__ide_mm_outsw(port, addr, (count)<<1);
+}
+
+#if defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static char * print_siimage_get_info(char *, struct pci_dev *, int);
+static int siimage_get_info(char *, char **, off_t, int);
+
+static u8 siimage_proc;
+
+static ide_pci_host_proc_t siimage_procs[] __initdata = {
+	{
+		.name		= "siimage",
+		.set		= 1,
+		.get_info	= siimage_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_SIIMAGE_TIMINGS && CONFIG_PROC_FS */	
+
+static unsigned int init_chipset_siimage(struct pci_dev *, const char *);
+static void init_iops_siimage(ide_hwif_t *);
+static void init_hwif_siimage(ide_hwif_t *);
+static void init_dma_siimage(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t siimage_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_SII_680,
+		.name		= "SiI680",
+		.init_chipset	= init_chipset_siimage,
+		.init_iops	= init_iops_siimage,
+		.init_hwif	= init_hwif_siimage,
+		.init_dma	= init_dma_siimage,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_SII_3112,
+		.name		= "SiI3112 Serial ATA",
+		.init_chipset	= init_chipset_siimage,
+		.init_iops	= init_iops_siimage,
+		.init_hwif	= init_hwif_siimage,
+		.init_dma	= init_dma_siimage,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* SIIMAGE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/sis5513.c linux-2.4.21/drivers/ide/pci/sis5513.c
--- linux-2.4.20/drivers/ide/pci/sis5513.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/sis5513.c	2002-12-18 18:58:07.000000000 +0000
@@ -0,0 +1,1099 @@
+/*
+ * linux/drivers/ide/sis5513.c		Version 0.14ac	Sept 11, 2002
+ *
+ * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2002		Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ *
+ * Thanks :
+ *
+ * SiS Taiwan		: for direct support and hardware.
+ * Daniela Engert	: for initial ATA100 advices and numerous others.
+ * John Fremlin, Manfred Spraul, Dave Morgan, Peter Kjellerstedt	:
+ *			  for checking code correctness, providing patches.
+ *
+ *
+ * Original tests and design on the SiS620/5513 chipset.
+ * ATA100 tests and design on the SiS735/5513 chipset.
+ * ATA16/33 support from specs
+ * ATA133 support for SiS961/962 by L.C. Chang <lcchang@sis.com.tw>
+ */
+
+/*
+ * Notes/Special cases:
+ * - SiS5513 derivatives usually have the same PCI IDE register layout when
+ *  supporting the same UDMA modes.
+ * - There are exceptions :
+ *  . SiS730 and SiS550 use the same layout than ATA_66 chipsets but support
+ *   ATA_100
+ *  . ATA_133 capable chipsets mark a shift in SiS chipset designs : previously
+ *   south and northbridge were integrated, making IDE (a southbridge function)
+ *   capabilities easily deduced from the northbridge PCI id. With ATA_133,
+ *   chipsets started to be split in the usual north/south bridges chips
+ *   -> the driver needs to detect the correct southbridge when faced to newest
+ *   northbridges.
+ *  . On ATA133 capable chipsets when bit 30 of dword at 0x54 is 1 the
+ *   configuration space is moved from 0x40 to 0x70.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "sis5513.h"
+
+/* When DEBUG is defined it outputs initial PCI config register
+   values and changes made to them by the driver */
+// #define DEBUG
+/* When BROKEN_LEVEL is defined it limits the DMA mode
+   at boot time to its value */
+// #define BROKEN_LEVEL XFER_SW_DMA_0
+
+/* Miscellaneaous flags */
+#define SIS5513_LATENCY		0x01
+
+/* registers layout and init values are chipset family dependant */
+/* 1/ define families */
+#define ATA_00		0x00
+#define ATA_16		0x01
+#define ATA_33		0x02
+#define ATA_66		0x03
+#define ATA_100a	0x04 // SiS730 is ATA100 with ATA66 layout
+#define ATA_100		0x05
+#define ATA_133a	0x06 // SiS961b with 133 support
+#define ATA_133		0x07 // SiS962
+/* 2/ variable holding the controller chipset family value */
+static u8 chipset_family;
+
+
+/*
+ * Debug code: following IDE config registers' changes
+ */
+#ifdef DEBUG
+/* Copy of IDE Config registers fewer will be used
+ * Some odd chipsets hang if unused registers are accessed
+ * -> We only access them in #DEBUG code (then we'll see if SiS did
+ * it right from day one) */
+static u8 ide_regs_copy[0xff];
+
+/* Read config registers, print differences from previous read */
+static void sis5513_load_verify_registers(struct pci_dev* dev, char* info) {
+	int i;
+	u8 reg_val;
+	u8 changed=0;
+
+	printk("SIS5513: %s, changed registers:\n", info);
+	for(i=0; i<=0xff; i++) {
+		pci_read_config_byte(dev, i, &reg_val);
+		if (reg_val != ide_regs_copy[i]) {
+			printk("%02x: %02x -> %02x\n",
+			       i, ide_regs_copy[i], reg_val);
+			ide_regs_copy[i]=reg_val;
+			changed=1;
+		}
+	}
+
+	if (!changed) {
+		printk("none\n");
+	}
+}
+
+/* Load config registers, no printing */
+static void sis5513_load_registers(struct pci_dev* dev) {
+	int i;
+
+	for(i=0; i<=0xff; i++) {
+		pci_read_config_byte(dev, i, &(ide_regs_copy[i]));
+	}
+}
+
+/* Print config space registers a la "lspci -vxxx" */
+static void sis5513_print_registers(struct pci_dev* dev, char* marker) {
+	int i,j;
+
+	sis5513_load_registers(dev);
+	printk("SIS5513 %s\n", marker);
+
+	for(i=0; i<=0xf; i++) {
+		printk("SIS5513 dump: %d" "0:", i);
+		for(j=0; j<=0xf; j++) {
+			printk(" %02x", ide_regs_copy[(i<<16)+j]);
+		}
+		printk("\n");
+	}
+}
+#endif
+
+
+/*
+ * Devices supported
+ */
+static const struct {
+	const char *name;
+	u16 host_id;
+	u8 chipset_family;
+	u8 flags;
+} SiSHostChipInfo[] = {
+	{ "SiS752",	PCI_DEVICE_ID_SI_752,	ATA_133,	0 },
+	{ "SiS751",	PCI_DEVICE_ID_SI_751,	ATA_133,	0 },
+	{ "SiS750",	PCI_DEVICE_ID_SI_750,	ATA_133,	0 },
+	{ "SiS748",	PCI_DEVICE_ID_SI_748,	ATA_133,	0 },
+	{ "SiS746",	PCI_DEVICE_ID_SI_746,	ATA_133,	0 },
+	{ "SiS745",	PCI_DEVICE_ID_SI_745,	ATA_133,	0 },
+	{ "SiS740",	PCI_DEVICE_ID_SI_740,	ATA_100,	0 },
+	{ "SiS735",	PCI_DEVICE_ID_SI_735,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS730",	PCI_DEVICE_ID_SI_730,	ATA_100a,	SIS5513_LATENCY },
+	{ "SiS652",	PCI_DEVICE_ID_SI_652,	ATA_133,	0 },
+	{ "SiS651",	PCI_DEVICE_ID_SI_651,	ATA_133,	0 },
+	{ "SiS650",	PCI_DEVICE_ID_SI_650,	ATA_133,	0 },
+	{ "SiS648",	PCI_DEVICE_ID_SI_648,	ATA_133,	0 },
+	{ "SiS646",	PCI_DEVICE_ID_SI_646,	ATA_133,	0 },
+	{ "SiS645",	PCI_DEVICE_ID_SI_645,	ATA_133,	0 },
+	{ "SiS635",	PCI_DEVICE_ID_SI_635,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS640",	PCI_DEVICE_ID_SI_640,	ATA_66,		SIS5513_LATENCY },
+	{ "SiS630",	PCI_DEVICE_ID_SI_630,	ATA_66,		SIS5513_LATENCY },
+	{ "SiS620",	PCI_DEVICE_ID_SI_620,	ATA_66,		SIS5513_LATENCY },
+	{ "SiS550",	PCI_DEVICE_ID_SI_550,	ATA_100a,	0},
+	{ "SiS540",	PCI_DEVICE_ID_SI_540,	ATA_66,		0},
+	{ "SiS530",	PCI_DEVICE_ID_SI_530,	ATA_66,		0},
+	{ "SiS5600",	PCI_DEVICE_ID_SI_5600,	ATA_33,		0},
+	{ "SiS5598",	PCI_DEVICE_ID_SI_5598,	ATA_33,		0},
+	{ "SiS5597",	PCI_DEVICE_ID_SI_5597,	ATA_33,		0},
+	{ "SiS5591",	PCI_DEVICE_ID_SI_5591,	ATA_33,		0},
+	{ "SiS5513",	PCI_DEVICE_ID_SI_5513,	ATA_16,		0},
+	{ "SiS5511",	PCI_DEVICE_ID_SI_5511,	ATA_16,		0},
+};
+
+/* Cycle time bits and values vary accross chip dma capabilities
+   These three arrays hold the register layout and the values to set.
+   Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */
+
+/* {ATA_00, ATA_16, ATA_33, ATA_66, ATA_100a, ATA_100, ATA_133} */
+static u8 cycle_time_offset[] = {0,0,5,4,4,0,0};
+static u8 cycle_time_range[] = {0,0,2,3,3,4,4};
+static u8 cycle_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = {
+	{0,0,0,0,0,0,0}, /* no udma */
+	{0,0,0,0,0,0,0}, /* no udma */
+	{3,2,1,0,0,0,0}, /* ATA_33 */
+	{7,5,3,2,1,0,0}, /* ATA_66 */
+	{7,5,3,2,1,0,0}, /* ATA_100a (730 specific), differences are on cycle_time range and offset */
+	{11,7,5,4,2,1,0}, /* ATA_100 */
+	{15,10,7,5,3,2,1}, /* ATA_133a (earliest 691 southbridges) */
+	{15,10,7,5,3,2,1}, /* ATA_133 */
+};
+/* CRC Valid Setup Time vary accross IDE clock setting 33/66/100/133
+   See SiS962 data sheet for more detail */
+static u8 cvs_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = {
+	{0,0,0,0,0,0,0}, /* no udma */
+	{0,0,0,0,0,0,0}, /* no udma */
+	{2,1,1,0,0,0,0},
+	{4,3,2,1,0,0,0},
+	{4,3,2,1,0,0,0},
+	{6,4,3,1,1,1,0},
+	{9,6,4,2,2,2,2},
+	{9,6,4,2,2,2,2},
+};
+/* Initialize time, Active time, Recovery time vary accross
+   IDE clock settings. These 3 arrays hold the register value
+   for PIO0/1/2/3/4 and DMA0/1/2 mode in order */
+static u8 ini_time_value[][8] = {
+	{0,0,0,0,0,0,0,0},
+	{0,0,0,0,0,0,0,0},
+	{2,1,0,0,0,1,0,0},
+	{4,3,1,1,1,3,1,1},
+	{4,3,1,1,1,3,1,1},
+	{6,4,2,2,2,4,2,2},
+	{9,6,3,3,3,6,3,3},
+	{9,6,3,3,3,6,3,3},
+};
+static u8 act_time_value[][8] = {
+	{0,0,0,0,0,0,0,0},
+	{0,0,0,0,0,0,0,0},
+	{9,9,9,2,2,7,2,2},
+	{19,19,19,5,4,14,5,4},
+	{19,19,19,5,4,14,5,4},
+	{28,28,28,7,6,21,7,6},
+	{38,38,38,10,9,28,10,9},
+	{38,38,38,10,9,28,10,9},
+};
+static u8 rco_time_value[][8] = {
+	{0,0,0,0,0,0,0,0},
+	{0,0,0,0,0,0,0,0},
+	{9,2,0,2,0,7,1,1},
+	{19,5,1,5,2,16,3,2},
+	{19,5,1,5,2,16,3,2},
+	{30,9,3,9,4,25,6,4},
+	{40,12,4,12,5,34,12,5},
+	{40,12,4,12,5,34,12,5},
+};
+
+static struct pci_dev *host_dev = NULL;
+
+/*
+ * Printing configuration
+ */
+/* Used for chipset type printing at boot time */
+static char* chipset_capability[] = {
+	"ATA", "ATA 16",
+	"ATA 33", "ATA 66",
+	"ATA 100", "ATA 100",
+	"ATA 133", "ATA 133"
+};
+
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 sis_proc = 0;
+
+static struct pci_dev *bmide_dev;
+
+static char* cable_type[] = {
+	"80 pins",
+	"40 pins"
+};
+
+static char* recovery_time[] ={
+	"12 PCICLK", "1 PCICLK",
+	"2 PCICLK", "3 PCICLK",
+	"4 PCICLK", "5 PCICLCK",
+	"6 PCICLK", "7 PCICLCK",
+	"8 PCICLK", "9 PCICLCK",
+	"10 PCICLK", "11 PCICLK",
+	"13 PCICLK", "14 PCICLK",
+	"15 PCICLK", "15 PCICLK"
+};
+
+static char* active_time[] = {
+	"8 PCICLK", "1 PCICLCK",
+	"2 PCICLK", "3 PCICLK",
+	"4 PCICLK", "5 PCICLK",
+	"6 PCICLK", "12 PCICLK"
+};
+
+static char* cycle_time[] = {
+	"Reserved", "2 CLK",
+	"3 CLK", "4 CLK",
+	"5 CLK", "6 CLK",
+	"7 CLK", "8 CLK",
+	"9 CLK", "10 CLK",
+	"11 CLK", "12 CLK",
+	"13 CLK", "14 CLK",
+	"15 CLK", "16 CLK"
+};
+
+/* Generic add master or slave info function */
+static char* get_drives_info (char *buffer, u8 pos)
+{
+	u8 reg00, reg01, reg10, reg11; /* timing registers */
+	u32 regdw0, regdw1;
+	char* p = buffer;
+
+/* Postwrite/Prefetch */
+	if (chipset_family < ATA_133) {
+		pci_read_config_byte(bmide_dev, 0x4b, &reg00);
+		p += sprintf(p, "Drive %d:        Postwrite %s \t \t Postwrite %s\n",
+			     pos, (reg00 & (0x10 << pos)) ? "Enabled" : "Disabled",
+			     (reg00 & (0x40 << pos)) ? "Enabled" : "Disabled");
+		p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
+			     (reg00 & (0x01 << pos)) ? "Enabled" : "Disabled",
+			     (reg00 & (0x04 << pos)) ? "Enabled" : "Disabled");
+		pci_read_config_byte(bmide_dev, 0x40+2*pos, &reg00);
+		pci_read_config_byte(bmide_dev, 0x41+2*pos, &reg01);
+		pci_read_config_byte(bmide_dev, 0x44+2*pos, &reg10);
+		pci_read_config_byte(bmide_dev, 0x45+2*pos, &reg11);
+	} else {
+		u32 reg54h;
+		u8 drive_pci = 0x40;
+		pci_read_config_dword(bmide_dev, 0x54, &reg54h);
+		if (reg54h & 0x40000000) {
+			// Configuration space remapped to 0x70
+			drive_pci = 0x70;
+		}
+		pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+8*pos, &regdw0);
+		pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+8*pos+4, &regdw1);
+		p += sprintf(p, "Drive %d:\n", pos);
+	}
+
+
+/* UDMA */
+	if (chipset_family >= ATA_133) {
+		p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
+			     (regdw0 & 0x04) ? "Enabled" : "Disabled",
+			     (regdw1 & 0x04) ? "Enabled" : "Disabled");
+		p += sprintf(p, "                UDMA Cycle Time    %s \t UDMA Cycle Time    %s\n",
+			     cycle_time[(regdw0 & 0xF0) >> 4],
+			     cycle_time[(regdw1 & 0xF0) >> 4]);
+	} else if (chipset_family >= ATA_33) {
+		p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
+			     (reg01 & 0x80) ? "Enabled" : "Disabled",
+			     (reg11 & 0x80) ? "Enabled" : "Disabled");
+
+		p += sprintf(p, "                UDMA Cycle Time    ");
+		switch(chipset_family) {
+			case ATA_33:	p += sprintf(p, cycle_time[(reg01 & 0x60) >> 5]); break;
+			case ATA_66:
+			case ATA_100a:	p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break;
+			case ATA_100:
+			case ATA_133a:	p += sprintf(p, cycle_time[reg01 & 0x0F]); break;
+			case ATA_133:
+			default:	p += sprintf(p, "133+ ?"); break;
+		}
+		p += sprintf(p, " \t UDMA Cycle Time    ");
+		switch(chipset_family) {
+			case ATA_33:	p += sprintf(p, cycle_time[(reg11 & 0x60) >> 5]); break;
+			case ATA_66:
+			case ATA_100a:	p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break;
+			case ATA_100:
+			case ATA_133a:  p += sprintf(p, cycle_time[reg11 & 0x0F]); break;
+			case ATA_133:
+			default:	p += sprintf(p, "133+ ?"); break;
+		}
+		p += sprintf(p, "\n");
+	}
+
+/* Data Active */
+	p += sprintf(p, "                Data Active Time   ");
+	switch(chipset_family) {
+		case ATA_00:
+		case ATA_16: /* confirmed */
+		case ATA_33:
+		case ATA_66:
+		case ATA_100a: p += sprintf(p, active_time[reg01 & 0x07]); break;
+		case ATA_100:
+		case ATA_133a: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break;
+		case ATA_133:
+		default: p += sprintf(p, "133+ ?"); break;
+	}
+	p += sprintf(p, " \t Data Active Time   ");
+	switch(chipset_family) {
+		case ATA_00:
+		case ATA_16:
+		case ATA_33:
+		case ATA_66:
+		case ATA_100a: p += sprintf(p, active_time[reg11 & 0x07]); break;
+		case ATA_100:
+		case ATA_133a: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break;
+		case ATA_133:
+		default: p += sprintf(p, "133+ ?"); break;
+	}
+	p += sprintf(p, "\n");
+
+/* Data Recovery */
+	/* warning: may need (reg&0x07) for pre ATA66 chips */
+	if (chipset_family < ATA_133) {
+		p += sprintf(p, "                Data Recovery Time %s \t Data Recovery Time %s\n",
+			     recovery_time[reg00 & 0x0f], recovery_time[reg10 & 0x0f]);
+	}
+
+	return p;
+}
+
+static char* get_masters_info(char* buffer)
+{
+	return get_drives_info(buffer, 0);
+}
+
+static char* get_slaves_info(char* buffer)
+{
+	return get_drives_info(buffer, 1);
+}
+
+/* Main get_info, called on /proc/ide/sis reads */
+static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	u8 reg;
+	u16 reg2, reg3;
+
+	p += sprintf(p, "\nSiS 5513 ");
+	switch(chipset_family) {
+		case ATA_00: p += sprintf(p, "Unknown???"); break;
+		case ATA_16: p += sprintf(p, "DMA 16"); break;
+		case ATA_33: p += sprintf(p, "Ultra 33"); break;
+		case ATA_66: p += sprintf(p, "Ultra 66"); break;
+		case ATA_100a:
+		case ATA_100: p += sprintf(p, "Ultra 100"); break;
+		case ATA_133a:
+		case ATA_133: p += sprintf(p, "Ultra 133"); break;
+		default: p+= sprintf(p, "Unknown???"); break;
+	}
+	p += sprintf(p, " chipset\n");
+	p += sprintf(p, "--------------- Primary Channel "
+		     "---------------- Secondary Channel "
+		     "-------------\n");
+
+/* Status */
+	pci_read_config_byte(bmide_dev, 0x4a, &reg);
+	if (chipset_family == ATA_133) {
+		pci_read_config_word(bmide_dev, 0x50, &reg2);
+		pci_read_config_word(bmide_dev, 0x52, &reg3);
+	}
+	p += sprintf(p, "Channel Status: ");
+	if (chipset_family < ATA_66) {
+		p += sprintf(p, "%s \t \t \t \t %s\n",
+			     (reg & 0x04) ? "On" : "Off",
+			     (reg & 0x02) ? "On" : "Off");
+	} else if (chipset_family < ATA_133) {
+		p += sprintf(p, "%s \t \t \t \t %s \n",
+			     (reg & 0x02) ? "On" : "Off",
+			     (reg & 0x04) ? "On" : "Off");
+	} else { /* ATA_133 */
+		p += sprintf(p, "%s \t \t \t \t %s \n",
+			     (reg2 & 0x02) ? "On" : "Off",
+			     (reg3 & 0x02) ? "On" : "Off");
+	}
+
+/* Operation Mode */
+	pci_read_config_byte(bmide_dev, 0x09, &reg);
+	p += sprintf(p, "Operation Mode: %s \t \t \t %s \n",
+		     (reg & 0x01) ? "Native" : "Compatible",
+		     (reg & 0x04) ? "Native" : "Compatible");
+
+/* 80-pin cable ? */
+	if (chipset_family >= ATA_133) {
+		p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
+			     (reg2 & 0x01) ? cable_type[1] : cable_type[0],
+			     (reg3 & 0x01) ? cable_type[1] : cable_type[0]);
+	} else if (chipset_family > ATA_33) {
+		pci_read_config_byte(bmide_dev, 0x48, &reg);
+		p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
+			     (reg & 0x10) ? cable_type[1] : cable_type[0],
+			     (reg & 0x20) ? cable_type[1] : cable_type[0]);
+	}
+
+/* Prefetch Count */
+	if (chipset_family < ATA_133) {
+		pci_read_config_word(bmide_dev, 0x4c, &reg2);
+		pci_read_config_word(bmide_dev, 0x4e, &reg3);
+		p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n",
+			     reg2, reg3);
+	}
+
+	p = get_masters_info(p);
+	p = get_slaves_info(p);
+
+	return p-buffer;
+}
+#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u8 sis5513_ratemask (ide_drive_t *drive)
+{
+#if 0
+	u8 rates[] = { 0, 0, 1, 2, 3, 3, 4, 4 };
+	u8 mode = rates[chipset_family];
+#else
+	u8 mode;
+
+	switch(chipset_family) {
+		case ATA_133:
+		case ATA_133a:
+			mode = 4;
+			break;
+		case ATA_100:
+		case ATA_100a:
+			mode = 3;
+			break;
+		case ATA_66:
+			mode = 2;
+			break;
+		case ATA_33:
+			return 1;
+		case ATA_16:
+                case ATA_00:	
+		default:
+			return 0;
+	}
+#endif
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+/*
+ * Configuration functions
+ */
+/* Enables per-drive prefetch and postwrite */
+static void config_drive_art_rwp (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	u8 reg4bh		= 0;
+	u8 rw_prefetch		= (0x11 << drive->dn);
+
+#ifdef DEBUG
+	printk("SIS5513: config_drive_art_rwp, drive %d\n", drive->dn);
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp start");
+#endif
+
+	if (drive->media != ide_disk)
+		return;
+	pci_read_config_byte(dev, 0x4b, &reg4bh);
+
+	if ((reg4bh & rw_prefetch) != rw_prefetch)
+		pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp end");
+#endif
+}
+
+
+/* Set per-drive active and recovery time */
+static void config_art_rwp_pio (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	u8			timing, drive_pci, test1, test2;
+
+	u16 eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
+	u16 xfer_pio = drive->id->eide_pio_modes;
+
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
+#endif
+
+	config_drive_art_rwp(drive);
+	pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
+
+	if (xfer_pio> 4)
+		xfer_pio = 0;
+
+	if (drive->id->eide_pio_iordy > 0) {
+		for (xfer_pio = 5;
+			(xfer_pio > 0) &&
+			(drive->id->eide_pio_iordy > eide_pio_timing[xfer_pio]);
+			xfer_pio--);
+	} else {
+		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+			   (drive->id->eide_pio_modes & 2) ? 0x04 :
+			   (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
+	}
+
+	timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+#ifdef DEBUG
+	printk("SIS5513: config_drive_art_rwp_pio, "
+		"drive %d, pio %d, timing %d\n",
+	       drive->dn, pio, timing);
+#endif
+
+	/* In pre ATA_133 case, drives sit at 0x40 + 4*drive->dn */
+	drive_pci = 0x40;
+	/* In SiS962 case drives sit at (0x40 or 0x70) + 8*drive->dn) */
+	if (chipset_family >= ATA_133) {
+		u32 reg54h;
+		pci_read_config_dword(dev, 0x54, &reg54h);
+		if (reg54h & 0x40000000) drive_pci = 0x70;
+		drive_pci += ((drive->dn)*0x4);
+	} else {
+		drive_pci += ((drive->dn)*0x2);
+	}
+
+	/* register layout changed with newer ATA100 chips */
+	if (chipset_family < ATA_100) {
+		pci_read_config_byte(dev, drive_pci, &test1);
+		pci_read_config_byte(dev, drive_pci+1, &test2);
+
+		/* Clear active and recovery timings */
+		test1 &= ~0x0F;
+		test2 &= ~0x07;
+
+		switch(timing) {
+			case 4:		test1 |= 0x01; test2 |= 0x03; break;
+			case 3:		test1 |= 0x03; test2 |= 0x03; break;
+			case 2:		test1 |= 0x04; test2 |= 0x04; break;
+			case 1:		test1 |= 0x07; test2 |= 0x06; break;
+			default:	break;
+		}
+		pci_write_config_byte(dev, drive_pci, test1);
+		pci_write_config_byte(dev, drive_pci+1, test2);
+	} else if (chipset_family < ATA_133) {
+		switch(timing) { /*		active  recovery
+						  v     v */
+			case 4:		test1 = 0x30|0x01; break;
+			case 3:		test1 = 0x30|0x03; break;
+			case 2:		test1 = 0x40|0x04; break;
+			case 1:		test1 = 0x60|0x07; break;
+			default:	break;
+		}
+		pci_write_config_byte(dev, drive_pci, test1);
+	} else { /* ATA_133 */
+		u32 test3;
+		pci_read_config_dword(dev, drive_pci, &test3);
+		test3 &= 0xc0c00fff;
+		if (test3 & 0x08) {
+			test3 |= (unsigned long)ini_time_value[ATA_133-ATA_00][timing] << 12;
+			test3 |= (unsigned long)act_time_value[ATA_133-ATA_00][timing] << 16;
+			test3 |= (unsigned long)rco_time_value[ATA_133-ATA_00][timing] << 24;
+		} else {
+			test3 |= (unsigned long)ini_time_value[ATA_100-ATA_00][timing] << 12;
+			test3 |= (unsigned long)act_time_value[ATA_100-ATA_00][timing] << 16;
+			test3 |= (unsigned long)rco_time_value[ATA_100-ATA_00][timing] << 24;
+		}
+		pci_write_config_dword(dev, drive_pci, test3);
+	}
+
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
+#endif
+}
+
+static int config_chipset_for_pio (ide_drive_t *drive, u8 pio)
+{
+#if 0
+	config_art_rwp_pio(drive, pio);
+	return ide_config_drive_speed(drive, (XFER_PIO_0 + pio));
+#else
+	u8 speed;
+
+	switch(pio) {
+		case 4:		speed = XFER_PIO_4; break;
+		case 3:		speed = XFER_PIO_3; break;
+		case 2:		speed = XFER_PIO_2; break;
+		case 1:		speed = XFER_PIO_1; break;
+		default:	speed = XFER_PIO_0; break;
+	}
+
+	config_art_rwp_pio(drive, pio);
+	return ide_config_drive_speed(drive, speed);
+#endif
+}
+
+static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	u8 drive_pci, reg, speed;
+	u32 regdw;
+
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "sis5513_tune_chipset start");
+#endif
+
+#ifdef BROKEN_LEVEL
+#ifdef DEBUG
+	printk("SIS5513: BROKEN_LEVEL activated, speed=%d -> speed=%d\n", xferspeed, BROKEN_LEVEL);
+#endif
+	if (xferspeed > BROKEN_LEVEL) xferspeed = BROKEN_LEVEL;
+#endif
+
+	speed = ide_rate_filter(sis5513_ratemask(drive), xferspeed);
+
+#ifdef DEBUG
+	printk("SIS5513: sis5513_tune_chipset, drive %d, speed %d\n",
+	       drive->dn, xferspeed);
+#endif
+
+	/* See config_art_rwp_pio for drive pci config registers */
+	drive_pci = 0x40;
+	if (chipset_family >= ATA_133) {
+		u32 reg54h;
+		pci_read_config_dword(dev, 0x54, &reg54h);
+		if (reg54h & 0x40000000) drive_pci = 0x70;
+		drive_pci += ((drive->dn)*0x4);
+		pci_read_config_dword(dev, (unsigned long)drive_pci, &regdw);
+		/* Disable UDMA bit for non UDMA modes on UDMA chips */
+		if (speed < XFER_UDMA_0) {
+			regdw &= 0xfffffffb;
+			pci_write_config_dword(dev, (unsigned long)drive_pci, regdw);
+		}
+	
+	} else {
+		drive_pci += ((drive->dn)*0x2);
+		pci_read_config_byte(dev, drive_pci+1, &reg);
+		/* Disable UDMA bit for non UDMA modes on UDMA chips */
+		if ((speed < XFER_UDMA_0) && (chipset_family > ATA_16)) {
+			reg &= 0x7F;
+			pci_write_config_byte(dev, drive_pci+1, reg);
+		}
+	}
+
+	/* Config chip for mode */
+	switch(speed) {
+		case XFER_UDMA_6:
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+			if (chipset_family >= ATA_133) {
+				regdw |= 0x04;
+				regdw &= 0xfffff00f;
+				/* check if ATA133 enable */
+				if (regdw & 0x08) {
+					regdw |= (unsigned long)cycle_time_value[ATA_133-ATA_00][speed-XFER_UDMA_0] << 4;
+					regdw |= (unsigned long)cvs_time_value[ATA_133-ATA_00][speed-XFER_UDMA_0] << 8;
+				} else {
+				/* if ATA133 disable, we should not set speed above UDMA5 */
+					if (speed > XFER_UDMA_5)
+						speed = XFER_UDMA_5;
+					regdw |= (unsigned long)cycle_time_value[ATA_100-ATA_00][speed-XFER_UDMA_0] << 4;
+					regdw |= (unsigned long)cvs_time_value[ATA_100-ATA_00][speed-XFER_UDMA_0] << 8;
+				}
+				pci_write_config_dword(dev, (unsigned long)drive_pci, regdw);
+			} else {
+				/* Force the UDMA bit on if we want to use UDMA */
+				reg |= 0x80;
+				/* clean reg cycle time bits */
+				reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family]))
+					 << cycle_time_offset[chipset_family]);
+				/* set reg cycle time bits */
+				reg |= cycle_time_value[chipset_family-ATA_00][speed-XFER_UDMA_0]
+					<< cycle_time_offset[chipset_family];
+				pci_write_config_byte(dev, drive_pci+1, reg);
+			}
+			break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_2:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+			break;
+		case XFER_PIO_4: return((int) config_chipset_for_pio(drive, 4));
+		case XFER_PIO_3: return((int) config_chipset_for_pio(drive, 3));
+		case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2));
+		case XFER_PIO_1: return((int) config_chipset_for_pio(drive, 1));
+		case XFER_PIO_0:
+		default:	 return((int) config_chipset_for_pio(drive, 0));	
+	}
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "sis5513_tune_chipset end");
+#endif
+	return ((int) ide_config_drive_speed(drive, speed));
+}
+
+static void sis5513_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	(void) config_chipset_for_pio(drive, pio);
+}
+
+/*
+ * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four))
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed	= ide_dma_speed(drive, sis5513_ratemask(drive));
+
+#ifdef DEBUG
+	printk("SIS5513: config_chipset_for_dma, drive %d, ultra %x\n",
+	       drive->dn, drive->id->dma_ultra);
+#endif
+
+	if (!(speed))
+		return 0;
+
+	sis5513_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int sis5513_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		sis5513_tune_drive(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+/* initiates/aborts (U)DMA read/write operations on a drive. */
+static int sis5513_config_xfer_rate (ide_drive_t *drive)
+{
+	config_drive_art_rwp(drive);
+	config_art_rwp_pio(drive, 5);
+	return sis5513_config_drive_xfer_rate(drive);
+}
+
+/* Chip detection and general config */
+static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char *name)
+{
+	struct pci_dev *host;
+	int i = 0;
+
+	/* Find the chip */
+	for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !host_dev; i++) {
+		host = pci_find_device (PCI_VENDOR_ID_SI,
+					SiSHostChipInfo[i].host_id,
+					NULL);
+		if (!host)
+			continue;
+
+		host_dev = host;
+		chipset_family = SiSHostChipInfo[i].chipset_family;
+	
+		/* check 100/133 chipset family */
+		if (chipset_family == ATA_133) {
+			u32 reg54h;
+			u16 reg02h;
+			pci_read_config_dword(dev, 0x54, &reg54h);
+			pci_write_config_dword(dev, 0x54, (reg54h & 0x7fffffff));
+			pci_read_config_word(dev, 0x02, &reg02h);
+			pci_write_config_dword(dev, 0x54, reg54h);
+			/* devid 5518 here means SiS962 or later
+			   which supports ATA133 */
+			if (reg02h != 0x5518) {
+				u8 reg49h;
+				unsigned long sbrev;
+				/* SiS961 family */
+
+		/*
+		 * FIXME !!! GAK!!!!!!!!!! PCI DIRECT POKING 
+		 */
+				outl(0x80001008, 0x0cf8);
+				sbrev = inl(0x0cfc);
+
+				pci_read_config_byte(dev, 0x49, &reg49h);
+				if (((sbrev & 0xff) == 0x10) && (reg49h & 0x80))
+					chipset_family = ATA_133a;
+				else
+					chipset_family = ATA_100;
+			}
+		}
+		printk(SiSHostChipInfo[i].name);
+		printk("    %s controller", chipset_capability[chipset_family]);
+		printk("\n");
+
+#ifdef DEBUG
+		sis5513_print_registers(dev, "pci_init_sis5513 start");
+#endif
+
+		if (SiSHostChipInfo[i].flags & SIS5513_LATENCY) {
+			u8 latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */
+			pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency);
+		}
+	}
+
+	/* Make general config ops here
+	   1/ tell IDE channels to operate in Compabitility mode only
+	   2/ tell old chips to allow per drive IDE timings */
+	if (host_dev) {
+		u8 reg;
+		u16 regw;
+		switch(chipset_family) {
+			case ATA_133:
+				/* SiS962 operation mode */
+				pci_read_config_word(dev, 0x50, &regw);
+				if (regw & 0x08)
+					pci_write_config_word(dev, 0x50, regw&0xfff7);
+				pci_read_config_word(dev, 0x52, &regw);
+				if (regw & 0x08)
+					pci_write_config_word(dev, 0x52, regw&0xfff7);
+				break;
+			case ATA_133a:
+			case ATA_100:
+				/* Set compatibility bit */
+				pci_read_config_byte(dev, 0x49, &reg);
+				if (!(reg & 0x01)) {
+					pci_write_config_byte(dev, 0x49, reg|0x01);
+				}
+				break;
+			case ATA_100a:
+			case ATA_66:
+				/* On ATA_66 chips the bit was elsewhere */
+				pci_read_config_byte(dev, 0x52, &reg);
+				if (!(reg & 0x04)) {
+					pci_write_config_byte(dev, 0x52, reg|0x04);
+				}
+				break;
+			case ATA_33:
+				/* On ATA_33 we didn't have a single bit to set */
+				pci_read_config_byte(dev, 0x09, &reg);
+				if ((reg & 0x0f) != 0x00) {
+					pci_write_config_byte(dev, 0x09, reg&0xf0);
+				}
+			case ATA_16:
+				/* force per drive recovery and active timings
+				   needed on ATA_33 and below chips */
+				pci_read_config_byte(dev, 0x52, &reg);
+				if (!(reg & 0x08)) {
+					pci_write_config_byte(dev, 0x52, reg|0x08);
+				}
+				break;
+			case ATA_00:
+			default: break;
+		}
+
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+		if (!sis_proc) {
+			sis_proc = 1;
+			bmide_dev = dev;
+			ide_pci_register_host_proc(&sis_procs[0]);
+		}
+#endif
+	}
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "pci_init_sis5513 end");
+#endif
+	return 0;
+}
+
+static unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
+{
+	u8 ata66 = 0;
+
+	if (chipset_family >= ATA_133) {
+		u16 regw = 0;
+		u16 reg_addr = hwif->channel ? 0x52: 0x50;
+		pci_read_config_word(hwif->pci_dev, reg_addr, &regw);
+		ata66 = (regw & 0x8000) ? 0 : 1;
+	} else if (chipset_family >= ATA_66) {
+		u8 reg48h = 0;
+		u8 mask = hwif->channel ? 0x20 : 0x10;
+		pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
+		ata66 = (reg48h & mask) ? 0 : 1;
+	}
+        return ata66;
+}
+
+static void __init init_hwif_sis5513 (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+
+	if (!hwif->irq)
+		hwif->irq = hwif->channel ? 15 : 14;
+
+	hwif->tuneproc = &sis5513_tune_drive;
+	hwif->speedproc = &sis5513_tune_chipset;
+
+	if (!(hwif->dma_base)) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (!host_dev)
+		return;
+
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66_sis5513(hwif);
+
+	if (chipset_family > ATA_16) {
+		hwif->ide_dma_check = &sis5513_config_xfer_rate;
+		if (!noautodma)
+			hwif->autodma = 1;
+	}
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+	return;
+}
+
+static void __init init_dma_sis5513 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+
+static int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &sis5513_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id sis5513_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "SIS IDE",
+	.id_table	= sis5513_pci_tbl,
+	.probe		= sis5513_init_one,
+};
+
+static int sis5513_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void sis5513_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(sis5513_ide_init);
+module_exit(sis5513_ide_exit);
+
+MODULE_AUTHOR("Lionel Bouton, L C Chang, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for SIS IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
+
+/*
+ * TODO:
+ *	- Get ridden of SisHostChipInfo[] completness dependancy.
+ *	- Study drivers/ide/ide-timing.h.
+ *	- Are there pre-ATA_16 SiS5513 chips ? -> tune init code for them
+ *	  or remove ATA_00 define
+ *	- More checks in the config registers (force values instead of
+ *	  relying on the BIOS setting them correctly).
+ *	- Further optimisations ?
+ *	  . for example ATA66+ regs 0x48 & 0x4A
+ */
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/sis5513.h linux-2.4.21/drivers/ide/pci/sis5513.h
--- linux-2.4.20/drivers/ide/pci/sis5513.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/sis5513.h	2002-12-18 18:58:05.000000000 +0000
@@ -0,0 +1,54 @@
+#ifndef SIS5513_H
+#define SIS5513_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_SIS_TIMINGS
+
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 sis_proc;
+
+static int sis_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t sis_procs[] __initdata = {
+{
+		.name		= "sis",
+		.set		= 1,
+		.get_info	= sis_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static unsigned int init_chipset_sis5513(struct pci_dev *, const char *);
+static void init_hwif_sis5513(ide_hwif_t *);
+static void init_dma_sis5513(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t sis5513_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_5513,
+		.name		= "SIS5513",
+		.init_chipset	= init_chipset_sis5513,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_sis5513,
+		.init_dma	= init_dma_sis5513,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* SIS5513_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/sl82c105.c linux-2.4.21/drivers/ide/pci/sl82c105.c
--- linux-2.4.20/drivers/ide/pci/sl82c105.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/sl82c105.c	2002-12-18 18:58:05.000000000 +0000
@@ -0,0 +1,322 @@
+/*
+ * linux/drivers/ide/sl82c105.c
+ *
+ * SL82C105/Winbond 553 IDE driver
+ *
+ * Maintainer unknown.
+ *
+ * Drive tuning added from Rebel.com's kernel sources
+ *  -- Russell King (15/11/98) linux@arm.linux.org.uk
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include "ide_modes.h"
+#include "sl82c105.h"
+
+/*
+ * Convert a PIO mode and cycle time to the required on/off
+ * times for the interface.  This has protection against run-away
+ * timings.
+ */
+static unsigned int get_timing_sl82c105(ide_pio_data_t *p)
+{
+	unsigned int cmd_on;
+	unsigned int cmd_off;
+
+	cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30;
+	cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30;
+
+	if (cmd_on > 32)
+		cmd_on = 32;
+	if (cmd_on == 0)
+		cmd_on = 1;
+
+	if (cmd_off > 32)
+		cmd_off = 32;
+	if (cmd_off == 0)
+		cmd_off = 1;
+
+	return (cmd_on - 1) << 8 | (cmd_off - 1) | (p->use_iordy ? 0x40 : 0x00);
+}
+
+/*
+ * Configure the drive and chipset for PIO
+ */
+static void config_for_pio(ide_drive_t *drive, int pio, int report)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	ide_pio_data_t p;
+	u16 drv_ctrl = 0x909;
+	unsigned int xfer_mode, reg;
+
+	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, &p);
+
+	xfer_mode = XFER_PIO_0 + pio;
+
+	if (ide_config_drive_speed(drive, xfer_mode) == 0)
+		drv_ctrl = get_timing_sl82c105(&p);
+
+	if (drive->using_dma == 0) {
+		/*
+		 * If we are actually using MW DMA, then we can not
+		 * reprogram the interface drive control register.
+		 */
+		pci_write_config_word(dev, reg, drv_ctrl);
+		pci_read_config_word(dev, reg, &drv_ctrl);
+
+		if (report) {
+			printk("%s: selected %s (%dns) (%04X)\n", drive->name,
+			       ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl);
+		}
+	}
+}
+
+/*
+ * Configure the drive and the chipset for DMA
+ */
+static int config_for_dma (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	u16 drv_ctrl = 0x909;
+	unsigned int reg;
+
+	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+
+	if (ide_config_drive_speed(drive, XFER_MW_DMA_2) == 0)
+		drv_ctrl = 0x0240;
+
+	pci_write_config_word(dev, reg, drv_ctrl);
+
+	return 0;
+}
+
+/*
+ * Check to see if the drive and
+ * chipset is capable of DMA mode
+ */
+
+static int sl82c105_check_drive (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	do {
+		struct hd_driveid *id = drive->id;
+
+		if (!drive->autodma)
+			break;
+
+		if (!id || !(id->capability & 1))
+			break;
+
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			break;
+
+		if (id->field_valid & 2) {
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask))
+				return hwif->ide_dma_on(drive);
+		}
+
+		if (hwif->ide_dma_good_drive(drive))
+			return hwif->ide_dma_on(drive);
+	} while (0);
+
+	return hwif->ide_dma_off_quietly(drive);
+}
+
+static int sl82c105_ide_dma_on (ide_drive_t *drive)
+{
+	if (config_for_dma(drive)) {
+		config_for_pio(drive, 4, 0);
+		return HWIF(drive)->ide_dma_off_quietly(drive);
+	}
+	return __ide_dma_on(drive);
+}
+
+static int sl82c105_ide_dma_off (ide_drive_t *drive)
+{
+	config_for_pio(drive, 4, 0);
+	return __ide_dma_off(drive);
+}
+
+static int sl82c105_ide_dma_off_quietly (ide_drive_t *drive)
+{
+	config_for_pio(drive, 4, 0);
+	return __ide_dma_off_quietly(drive);
+}
+
+/*
+ * We only deal with PIO mode here - DMA mode 'using_dma' is not
+ * initialised at the point that this function is called.
+ */
+static void tune_sl82c105(ide_drive_t *drive, u8 pio)
+{
+	config_for_pio(drive, pio, 1);
+
+	/*
+	 * We support 32-bit I/O on this interface, and it
+	 * doesn't have problems with interrupts.
+	 */
+	drive->io_32bit = 1;
+	drive->unmask = 1;
+}
+
+/*
+ * Return the revision of the Winbond bridge
+ * which this function is part of.
+ */
+static unsigned int sl82c105_bridge_revision(struct pci_dev *dev)
+{
+	struct pci_dev *bridge;
+	u8 rev;
+
+	bridge = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, NULL);
+
+	/*
+	 * If we are part of a Winbond 553
+	 */
+	if (!bridge || bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA)
+		return -1;
+
+	if (bridge->bus != dev->bus ||
+	    PCI_SLOT(bridge->devfn) != PCI_SLOT(dev->devfn))
+		return -1;
+
+	/*
+	 * We need to find function 0's revision, not function 1
+	 */
+	pci_read_config_byte(bridge, PCI_REVISION_ID, &rev);
+
+	return rev;
+}
+
+/*
+ * Enable the PCI device
+ */
+static unsigned int __init init_chipset_sl82c105(struct pci_dev *dev, const char *msg)
+{
+	u8 ctrl_stat;
+
+	/*
+	 * Enable the ports
+	 */
+	pci_read_config_byte(dev, 0x40, &ctrl_stat);
+	pci_write_config_byte(dev, 0x40, ctrl_stat | 0x33);
+
+	return dev->irq;
+}
+
+static void __init init_dma_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
+{
+	unsigned int rev;
+	u8 dma_state;
+
+	hwif->autodma = 0;
+
+	if (!dma_base)
+		return;
+
+	dma_state = hwif->INB(dma_base + 2);
+	rev = sl82c105_bridge_revision(hwif->pci_dev);
+	if (rev <= 5) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		printk("    %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
+		       hwif->name, rev);
+		dma_state &= ~0x60;
+	} else {
+		dma_state |= 0x60;
+		if (!noautodma)
+			hwif->autodma = 1;
+	}
+	hwif->OUTB(dma_state, dma_base + 2);
+
+	ide_setup_dma(hwif, dma_base, 8);
+}
+
+/*
+ * Initialise the chip
+ */
+
+static void __init init_hwif_sl82c105(ide_hwif_t *hwif)
+{
+	hwif->tuneproc = tune_sl82c105;
+
+	if (!hwif->dma_base)
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->ide_dma_check = &sl82c105_check_drive;
+	hwif->ide_dma_on = &sl82c105_ide_dma_on;
+	hwif->ide_dma_off = &sl82c105_ide_dma_off;
+	hwif->ide_dma_off_quietly = &sl82c105_ide_dma_off_quietly;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &sl82c105_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id sl82c105_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "W82C105 IDE",
+	.id_table	= sl82c105_pci_tbl,
+	.probe		= sl82c105_init_one,
+};
+
+static int sl82c105_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void sl82c105_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(sl82c105_ide_init);
+module_exit(sl82c105_ide_exit);
+
+MODULE_DESCRIPTION("PCI driver module for W82C105 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/sl82c105.h linux-2.4.21/drivers/ide/pci/sl82c105.h
--- linux-2.4.20/drivers/ide/pci/sl82c105.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/sl82c105.h	2002-12-18 18:58:01.000000000 +0000
@@ -0,0 +1,34 @@
+#ifndef W82C105_H
+#define W82C105_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static unsigned int init_chipset_sl82c105(struct pci_dev *, const char *);
+static void init_hwif_sl82c105(ide_hwif_t *);
+static void init_dma_sl82c105(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t sl82c105_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_WINBOND,
+		.device		= PCI_DEVICE_ID_WINBOND_82C105,
+		.name		= "W82C105",
+		.init_chipset	= init_chipset_sl82c105,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_sl82c105,
+		.init_dma	= init_dma_sl82c105,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x40,0x01,0x01}, {0x40,0x10,0x10}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* W82C105_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/slc90e66.c linux-2.4.21/drivers/ide/pci/slc90e66.c
--- linux-2.4.20/drivers/ide/pci/slc90e66.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/slc90e66.c	2002-12-18 18:58:02.000000000 +0000
@@ -0,0 +1,407 @@
+/*
+ *  linux/drivers/ide/slc90e66.c	Version 0.11	September 11, 2002
+ *
+ *  Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
+ *
+ * This a look-a-like variation of the ICH0 PIIX4 Ultra-66,
+ * but this keeps the ISA-Bridge and slots alive.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "slc90e66.h"
+
+#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 slc90e66_proc = 0;
+static struct pci_dev *bmide_dev;
+
+static int slc90e66_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	unsigned long bibma = pci_resource_start(bmide_dev, 4);
+        u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
+	u8  c0 = 0, c1 = 0;
+	u8  reg44 = 0, reg47 = 0, reg48 = 0, reg4a = 0, reg4b = 0;
+
+	pci_read_config_word(bmide_dev, 0x40, &reg40);
+	pci_read_config_word(bmide_dev, 0x42, &reg42);
+	pci_read_config_byte(bmide_dev, 0x44, &reg44);
+	pci_read_config_byte(bmide_dev, 0x47, &reg47);
+	pci_read_config_byte(bmide_dev, 0x48, &reg48);
+	pci_read_config_byte(bmide_dev, 0x4a, &reg4a);
+	pci_read_config_byte(bmide_dev, 0x4b, &reg4b);
+
+	psitre = (reg40 & 0x4000) ? 1 : 0;
+	ssitre = (reg42 & 0x4000) ? 1 : 0;
+
+        /*
+         * at that point bibma+0x2 et bibma+0xa are byte registers
+         * to investigate:
+         */
+	c0 = inb_p(bibma + 0x02);
+	c1 = inb_p(bibma + 0x0a);
+
+	p += sprintf(p, "                                SLC90E66 Chipset.\n");
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled "
+			"                        %sabled\n",
+			(c0&0x80) ? "dis" : " en",
+			(c1&0x80) ? "dis" : " en");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	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 " );
+	p += sprintf(p, "UDMA enabled:   %s              %s "
+			"            %s               %s\n",
+			(reg48&0x01) ? "yes" : "no ",
+			(reg48&0x02) ? "yes" : "no ",
+			(reg48&0x04) ? "yes" : "no ",
+			(reg48&0x08) ? "yes" : "no " );
+	p += sprintf(p, "UDMA enabled:   %s                %s "
+			"              %s                 %s\n",
+			((reg4a&0x04)==0x04) ? "4" :
+			((reg4a&0x03)==0x03) ? "3" :
+			(reg4a&0x02) ? "2" :
+			(reg4a&0x01) ? "1" :
+			(reg4a&0x00) ? "0" : "X",
+			((reg4a&0x40)==0x40) ? "4" :
+			((reg4a&0x30)==0x30) ? "3" :
+			(reg4a&0x20) ? "2" :
+			(reg4a&0x10) ? "1" :
+			(reg4a&0x00) ? "0" : "X",
+			((reg4b&0x04)==0x04) ? "4" :
+			((reg4b&0x03)==0x03) ? "3" :
+			(reg4b&0x02) ? "2" :
+			(reg4b&0x01) ? "1" :
+			(reg4b&0x00) ? "0" : "X",
+			((reg4b&0x40)==0x40) ? "4" :
+			((reg4b&0x30)==0x30) ? "3" :
+			(reg4b&0x20) ? "2" :
+			(reg4b&0x10) ? "1" :
+			(reg4b&0x00) ? "0" : "X");
+
+	p += sprintf(p, "UDMA\n");
+	p += sprintf(p, "DMA\n");
+	p += sprintf(p, "PIO\n");
+
+/*
+ *	FIXME.... Add configuration junk data....blah blah......
+ */
+
+	return p-buffer;	 /* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u8 slc90e66_ratemask (ide_drive_t *drive)
+{
+	u8 mode	= 2;
+
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static u8 slc90e66_dma_2_pio (u8 xfer_rate) {
+	switch(xfer_rate) {
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:
+		case XFER_PIO_4:
+			return 4;
+		case XFER_MW_DMA_1:
+		case XFER_PIO_3:
+			return 3;
+		case XFER_SW_DMA_2:
+		case XFER_PIO_2:
+			return 2;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+		case XFER_PIO_SLOW:
+		default:
+			return 0;
+	}
+}
+
+/*
+ *  Based on settings done by AMI BIOS
+ *  (might be useful if drive is not registered in CMOS for any reason).
+ */
+static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	int is_slave		= (&hwif->drives[1] == drive);
+	int master_port		= hwif->channel ? 0x42 : 0x40;
+	int slave_port		= 0x44;
+	unsigned long flags;
+	u16 master_data;
+	u8 slave_data;
+				 /* ISP  RTC */
+	u8 timings[][2]	= { { 0, 0 },
+				    { 0, 0 },
+				    { 1, 0 },
+				    { 2, 1 },
+				    { 2, 3 }, };
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	spin_lock_irqsave(&ide_lock, flags);
+	pci_read_config_word(dev, master_port, &master_data);
+	if (is_slave) {
+		master_data = master_data | 0x4000;
+		if (pio > 1)
+			/* enable PPE, IE and TIME */
+			master_data = master_data | 0x0070;
+		pci_read_config_byte(dev, slave_port, &slave_data);
+		slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
+		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
+	} else {
+		master_data = master_data & 0xccf8;
+		if (pio > 1)
+			/* enable PPE, IE and TIME */
+			master_data = master_data | 0x0007;
+		master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+	}
+	pci_write_config_word(dev, master_port, master_data);
+	if (is_slave)
+		pci_write_config_byte(dev, slave_port, slave_data);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 maslave		= hwif->channel ? 0x42 : 0x40;
+	u8 speed	= ide_rate_filter(slc90e66_ratemask(drive), xferspeed);
+	int sitre = 0, a_speed	= 7 << (drive->dn * 4);
+	int u_speed = 0, u_flag = 1 << drive->dn;
+	u16			reg4042, reg44, reg48, reg4a;
+
+	pci_read_config_word(dev, maslave, &reg4042);
+	sitre = (reg4042 & 0x4000) ? 1 : 0;
+	pci_read_config_word(dev, 0x44, &reg44);
+	pci_read_config_word(dev, 0x48, &reg48);
+	pci_read_config_word(dev, 0x4a, &reg4a);
+
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_4:	u_speed = 4 << (drive->dn * 4); break;
+		case XFER_UDMA_3:	u_speed = 3 << (drive->dn * 4); break;
+		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
+		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
+		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_SW_DMA_2:	break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_0:        break;
+		default:		return -1;
+	}
+
+	if (speed >= XFER_UDMA_0) {
+		if (!(reg48 & u_flag))
+			pci_write_config_word(dev, 0x48, reg48|u_flag);
+		if ((reg4a & u_speed) != u_speed) {
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+			pci_read_config_word(dev, 0x4a, &reg4a);
+			pci_write_config_word(dev, 0x4a, reg4a|u_speed);
+		}
+	} else {
+		if (reg48 & u_flag)
+			pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
+		if (reg4a & a_speed)
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+	}
+
+	slc90e66_tune_drive(drive, slc90e66_dma_2_pio(speed));
+	return (ide_config_drive_speed(drive, speed));
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, slc90e66_ratemask(drive));
+
+	if (!(speed)) {
+		u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
+		speed = slc90e66_dma_2_pio(XFER_PIO_0 + tspeed);
+	}
+
+	(void) slc90e66_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = slc90e66_config_drive_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!slc90e66_config_drive_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!slc90e66_config_drive_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hwif->tuneproc(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+static unsigned int __init init_chipset_slc90e66 (struct pci_dev *dev, const char *name)
+{
+#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!slc90e66_proc) {
+		slc90e66_proc = 1;
+		bmide_dev = dev;
+		ide_pci_register_host_proc(&slc90e66_procs[0]);
+	}
+#endif /* DISPLAY_SLC90E66_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+static void __init init_hwif_slc90e66 (ide_hwif_t *hwif)
+{
+	u8 reg47 = 0;
+	u8 mask = hwif->channel ? 0x01 : 0x02;  /* bit0:Primary */
+
+	hwif->autodma = 0;
+
+	if (!hwif->irq)
+		hwif->irq = hwif->channel ? 15 : 14;
+
+	hwif->speedproc = &slc90e66_tune_chipset;
+	hwif->tuneproc = &slc90e66_tune_drive;
+
+	pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x1f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA 
+	if (!(hwif->udma_four))
+		/* bit[0(1)]: 0:80, 1:40 */
+		hwif->udma_four = (reg47 & mask) ? 0 : 1;
+
+	hwif->ide_dma_check = &slc90e66_config_drive_xfer_rate;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* !CONFIG_BLK_DEV_IDEDMA */
+}
+
+static void __init init_dma_slc90e66 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+
+static int __devinit slc90e66_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &slc90e66_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id slc90e66_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "SLC90e66 IDE",
+	.id_table	= slc90e66_pci_tbl,
+	.probe		= slc90e66_init_one,
+};
+
+static int slc90e66_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void slc90e66_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(slc90e66_ide_init);
+module_exit(slc90e66_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for SLC90E66 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/slc90e66.h linux-2.4.21/drivers/ide/pci/slc90e66.h
--- linux-2.4.20/drivers/ide/pci/slc90e66.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/slc90e66.h	2002-12-18 18:58:10.000000000 +0000
@@ -0,0 +1,56 @@
+#ifndef SLC90E66_H
+#define SLC90E66_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_SLC90E66_TIMINGS
+
+#define SLC90E66_DEBUG_DRIVE_INFO	0
+
+#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 slc90e66_proc;
+
+static int slc90e66_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t slc90e66_procs[] __initdata = {
+	{
+		.name		= "slc90e66",
+		.set		= 1,
+		.get_info	= slc90e66_get_info,
+		.parent		= NULL,
+	},
+};
+#endif	/* defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static unsigned int init_chipset_slc90e66(struct pci_dev *, const char *);
+static void init_hwif_slc90e66(ide_hwif_t *);
+static void init_dma_slc90e66(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t slc90e66_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_EFAR,
+		.device		= PCI_DEVICE_ID_EFAR_SLC90E66_1,
+		.name		= "SLC90E66",
+		.init_chipset	= init_chipset_slc90e66,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_slc90e66,
+		.init_dma	= init_dma_slc90e66,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* SLC90E66_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/trm290.c linux-2.4.21/drivers/ide/pci/trm290.c
--- linux-2.4.20/drivers/ide/pci/trm290.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/trm290.c	2002-12-18 18:58:04.000000000 +0000
@@ -0,0 +1,452 @@
+/*
+ *  linux/drivers/ide/trm290.c		Version 1.02	Mar. 18, 2000
+ *
+ *  Copyright (c) 1997-1998  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 Tekram TRM290 chip, used on a variety of PCI IDE add-on boards,
+ * including a "Precision Instruments" board.  The TRM290 pre-dates
+ * the sff-8038 standard (ide-dma.c) by a few months, and differs
+ * significantly enough to warrant separate routines for some functions,
+ * while re-using others from ide-dma.c.
+ *
+ * EXPERIMENTAL!  It works for me (a sample of one).
+ *
+ * Works reliably for me in DMA mode (READs only),
+ * DMA WRITEs are disabled by default (see #define below);
+ *
+ * DMA is not enabled automatically for this chipset,
+ * but can be turned on manually (with "hdparm -d1") at run time.
+ *
+ * I need volunteers with "spare" drives for further testing
+ * and development, and maybe to help figure out the peculiarities.
+ * Even knowing the registers (below), some things behave strangely.
+ */
+
+#define TRM290_NO_DMA_WRITES	/* DMA writes seem unreliable sometimes */
+
+/*
+ * TRM-290 PCI-IDE2 Bus Master Chip
+ * ================================
+ * The configuration registers are addressed in normal I/O port space
+ * and are used as follows:
+ *
+ * trm290_base depends on jumper settings, and is probed for by ide-dma.c
+ *
+ * trm290_base+2 when WRITTEN: chiptest register (byte, write-only)
+ *	bit7 must always be written as "1"
+ *	bits6-2 undefined
+ *	bit1 1=legacy_compatible_mode, 0=native_pci_mode
+ *	bit0 1=test_mode, 0=normal(default)
+ *
+ * trm290_base+2 when READ: status register (byte, read-only)
+ *	bits7-2 undefined
+ *	bit1 channel0 busmaster interrupt status 0=none, 1=asserted
+ *	bit0 channel0 interrupt status 0=none, 1=asserted
+ *
+ * trm290_base+3 Interrupt mask register
+ *	bits7-5 undefined
+ *	bit4 legacy_header: 1=present, 0=absent
+ *	bit3 channel1 busmaster interrupt status 0=none, 1=asserted (read only)
+ *	bit2 channel1 interrupt status 0=none, 1=asserted (read only)
+ *	bit1 channel1 interrupt mask: 1=masked, 0=unmasked(default)
+ *	bit0 channel0 interrupt mask: 1=masked, 0=unmasked(default)
+ *
+ * trm290_base+1 "CPR" Config Pointer Register (byte)
+ *	bit7 1=autoincrement CPR bits 2-0 after each access of CDR
+ *	bit6 1=min. 1 wait-state posted write cycle (default), 0=0 wait-state
+ *	bit5 0=enabled master burst access (default), 1=disable  (write only)
+ *	bit4 PCI DEVSEL# timing select: 1=medium(default), 0=fast
+ *	bit3 0=primary IDE channel, 1=secondary IDE channel
+ *	bits2-0 register index for accesses through CDR port
+ *
+ * trm290_base+0 "CDR" Config Data Register (word)
+ *	two sets of seven config registers,
+ *	selected by CPR bit 3 (channel) and CPR bits 2-0 (index 0 to 6),
+ *	each index defined below:
+ *
+ * Index-0 Base address register for command block (word)
+ *	defaults: 0x1f0 for primary, 0x170 for secondary
+ *
+ * Index-1 general config register (byte)
+ *	bit7 1=DMA enable, 0=DMA disable
+ *	bit6 1=activate IDE_RESET, 0=no action (default)
+ *	bit5 1=enable IORDY, 0=disable IORDY (default)
+ *	bit4 0=16-bit data port(default), 1=8-bit (XT) data port
+ *	bit3 interrupt polarity: 1=active_low, 0=active_high(default)
+ *	bit2 power-saving-mode(?): 1=enable, 0=disable(default) (write only)
+ *	bit1 bus_master_mode(?): 1=enable, 0=disable(default)
+ *	bit0 enable_io_ports: 1=enable(default), 0=disable
+ *
+ * Index-2 read-ahead counter preload bits 0-7 (byte, write only)
+ *	bits7-0 bits7-0 of readahead count
+ *
+ * Index-3 read-ahead config register (byte, write only)
+ *	bit7 1=enable_readahead, 0=disable_readahead(default)
+ *	bit6 1=clear_FIFO, 0=no_action
+ *	bit5 undefined
+ *	bit4 mode4 timing control: 1=enable, 0=disable(default)
+ *	bit3 undefined
+ *	bit2 undefined
+ *	bits1-0 bits9-8 of read-ahead count
+ *
+ * Index-4 base address register for control block (word)
+ *	defaults: 0x3f6 for primary, 0x376 for secondary
+ *
+ * Index-5 data port timings (shared by both drives) (byte)
+ *	standard PCI "clk" (clock) counts, default value = 0xf5
+ *
+ *	bits7-6 setup time:  00=1clk, 01=2clk, 10=3clk, 11=4clk
+ *	bits5-3 hold time:	000=1clk, 001=2clk, 010=3clk,
+ *				011=4clk, 100=5clk, 101=6clk,
+ *				110=8clk, 111=12clk
+ *	bits2-0 active time:	000=2clk, 001=3clk, 010=4clk,
+ *				011=5clk, 100=6clk, 101=8clk,
+ *				110=12clk, 111=16clk
+ *
+ * Index-6 command/control port timings (shared by both drives) (byte)
+ *	same layout as Index-5, default value = 0xde
+ *
+ * Suggested CDR programming for PIO mode0 (600ns):
+ *	0x01f0,0x21,0xff,0x80,0x03f6,0xf5,0xde	; primary
+ *	0x0170,0x21,0xff,0x80,0x0376,0xf5,0xde	; secondary
+ *
+ * Suggested CDR programming for PIO mode3 (180ns):
+ *	0x01f0,0x21,0xff,0x80,0x03f6,0x09,0xde	; primary
+ *	0x0170,0x21,0xff,0x80,0x0376,0x09,0xde	; secondary
+ *
+ * Suggested CDR programming for PIO mode4 (120ns):
+ *	0x01f0,0x21,0xff,0x80,0x03f6,0x00,0xde	; primary
+ *	0x0170,0x21,0xff,0x80,0x0376,0x00,0xde	; secondary
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#include "trm290.h"
+
+static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u16 reg = 0;
+	unsigned long flags;
+
+	/* select PIO or DMA */
+	reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82);
+
+	local_irq_save(flags);
+
+	if (reg != hwif->select_data) {
+		hwif->select_data = reg;
+		/* set PIO/DMA */
+		hwif->OUTB(0x51|(hwif->channel<<3), hwif->config_data+1);
+		hwif->OUTW(reg & 0xff, hwif->config_data);
+	}
+
+	/* enable IRQ if not probing */
+	if (drive->present) {
+		reg = hwif->INW(hwif->config_data + 3);
+		reg &= 0x13;
+		reg &= ~(1 << hwif->channel);
+		hwif->OUTW(reg, hwif->config_data+3);
+	}
+
+	local_irq_restore(flags);
+}
+
+static void trm290_selectproc (ide_drive_t *drive)
+{
+	trm290_prepare_drive(drive, drive->using_dma);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int trm290_ide_dma_write (ide_drive_t *drive /*, struct request *rq */)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= HWGROUP(drive)->rq;
+//	ide_task_t *args	= rq->special;
+	task_ioreg_t command	= WIN_NOP;
+	unsigned int count, reading = 2, writing = 0;
+
+	reading = 0;
+	writing = 1;
+#ifdef TRM290_NO_DMA_WRITES
+	/* always use PIO for writes */
+	trm290_prepare_drive(drive, 0);	/* select PIO xfer */
+	return 1;
+#endif
+	if (!(count = ide_build_dmatable(drive, rq, PCI_DMA_TODEVICE))) {
+		/* try PIO instead of DMA */
+		trm290_prepare_drive(drive, 0); /* select PIO xfer */
+		return 1;
+	}
+	/* select DMA xfer */
+	trm290_prepare_drive(drive, 1);
+	hwif->OUTL(hwif->dmatable_dma|reading|writing, hwif->dma_command);
+	drive->waiting_for_dma = 1;
+	/* start DMA */
+	hwif->OUTW((count * 2) - 1, hwif->dma_status);
+	if (drive->media != ide_disk)
+		return 0;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = /* (lba48) ? WIN_READDMA_EXT : */ WIN_READDMA;
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
+	return HWIF(drive)->ide_dma_count(drive);
+}
+
+static int trm290_ide_dma_read (ide_drive_t *drive  /*, struct request *rq */)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= HWGROUP(drive)->rq;
+//	ide_task_t *args	= rq->special;
+	task_ioreg_t command	= WIN_NOP;
+	unsigned int count, reading = 2, writing = 0;
+
+	if (!(count = ide_build_dmatable(drive, rq, PCI_DMA_FROMDEVICE))) {
+		/* try PIO instead of DMA */
+		trm290_prepare_drive(drive, 0); /* select PIO xfer */
+		return 1;
+	}
+	/* select DMA xfer */
+	trm290_prepare_drive(drive, 1);
+	hwif->OUTL(hwif->dmatable_dma|reading|writing, hwif->dma_command);
+	drive->waiting_for_dma = 1;
+	/* start DMA */
+	hwif->OUTW((count * 2) - 1, hwif->dma_status);
+	if (drive->media != ide_disk)
+		return 0;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = /* (lba48) ? WIN_WRITEDMA_EXT : */ WIN_WRITEDMA;
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
+	return HWIF(drive)->ide_dma_count(drive);
+}
+
+static int trm290_ide_dma_begin (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int trm290_ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u16 status = 0;;
+
+	drive->waiting_for_dma = 0;
+	/* purge DMA mappings */
+	ide_destroy_dmatable(drive);
+	status = hwif->INW(hwif->dma_status);
+	return (status != 0x00ff);
+}
+
+static int trm290_ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u16 status = 0;
+
+	status = hwif->INW(hwif->dma_status);
+	return (status == 0x00ff);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+/*
+ * Invoked from ide-dma.c at boot time.
+ */
+void __init init_hwif_trm290 (ide_hwif_t *hwif)
+{
+	unsigned int cfgbase = 0;
+	unsigned long flags;
+	u8 reg = 0;
+	struct pci_dev *dev = hwif->pci_dev;
+
+	hwif->addressing = 1;
+	hwif->chipset = ide_trm290;
+	cfgbase = pci_resource_start(dev, 4);
+	if ((dev->class & 5) && cfgbase) {
+		hwif->config_data = cfgbase;
+		printk(KERN_INFO "TRM290: chip config base at 0x%04lx\n",
+			hwif->config_data);
+	} else {
+		hwif->config_data = 0x3df0;
+		printk(KERN_INFO "TRM290: using default config base at 0x%04lx\n",
+			hwif->config_data);
+	}
+
+	local_irq_save(flags);
+	/* put config reg into first byte of hwif->select_data */
+	hwif->OUTB(0x51|(hwif->channel<<3), hwif->config_data+1);
+	/* select PIO as default */
+	hwif->select_data = 0x21;
+	hwif->OUTB(hwif->select_data, hwif->config_data);
+	/* get IRQ info */
+	reg = hwif->INB(hwif->config_data+3);
+	/* mask IRQs for both ports */
+	reg = (reg & 0x10) | 0x03;
+	hwif->OUTB(reg, hwif->config_data+3);
+	local_irq_restore(flags);
+
+	if ((reg & 0x10))
+		/* legacy mode */
+		hwif->irq = hwif->channel ? 15 : 14;
+	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+		/* sharing IRQ with mate */
+		hwif->irq = hwif->mate->irq;
+
+	ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->ide_dma_write = &trm290_ide_dma_write;
+	hwif->ide_dma_read = &trm290_ide_dma_read;
+	hwif->ide_dma_begin = &trm290_ide_dma_begin;
+	hwif->ide_dma_end = &trm290_ide_dma_end;
+	hwif->ide_dma_test_irq = &trm290_ide_dma_test_irq;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+	hwif->selectproc = &trm290_selectproc;
+	hwif->autodma = 0;		/* play it safe for now */
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#if 1
+	{
+	/*
+	 * My trm290-based card doesn't seem to work with all possible values
+	 * for the control basereg, so this kludge ensures that we use only
+	 * values that are known to work.  Ugh.		-ml
+	 */
+		u16 new, old, compat = hwif->channel ? 0x374 : 0x3f4;
+		static u16 next_offset = 0;
+		u8 old_mask;
+
+		hwif->OUTB(0x54|(hwif->channel<<3), hwif->config_data+1);
+		old = hwif->INW(hwif->config_data);
+		old &= ~1;
+		old_mask = hwif->INB(old+2);
+		if (old != compat && old_mask == 0xff) {
+			/* leave lower 10 bits untouched */
+			compat += (next_offset += 0x400);
+#  if 1
+			if (check_region(compat + 2, 1))
+				printk(KERN_ERR "%s: check_region failure at 0x%04x\n",
+					hwif->name, (compat + 2));
+			/*
+			 * The region check is not needed; however.........
+			 * Since this is the checked in ide-probe.c,
+			 * this is only an assignment.
+			 */
+#  endif
+			hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2;
+			hwif->OUTW(compat|1, hwif->config_data);
+			new = hwif->INW(hwif->config_data);
+			printk(KERN_INFO "%s: control basereg workaround: "
+				"old=0x%04x, new=0x%04x\n",
+				hwif->name, old, new & ~1);
+		}
+	}
+#endif
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit trm290_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &trm290_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	trm290_remove_one	-	called when an trm290 is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect a trm290 device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void trm290_remove_one(struct pci_dev *dev)
+{
+	printk("trm290 removal not yet supported.\n");
+}
+
+static struct pci_device_id trm290_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"TRM290 IDE",
+	id_table:	trm290_pci_tbl,
+	probe:		trm290_init_one,
+	remove:		__devexit_p(trm290_remove_one),
+};
+
+static int trm290_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void trm290_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(trm290_ide_init);
+module_exit(trm290_ide_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for Tekram TRM290 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/trm290.h linux-2.4.21/drivers/ide/pci/trm290.h
--- linux-2.4.20/drivers/ide/pci/trm290.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/trm290.h	2002-12-18 18:58:12.000000000 +0000
@@ -0,0 +1,32 @@
+#ifndef TRM290_H
+#define TRM290_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+extern void init_hwif_trm290(ide_hwif_t *);
+
+static ide_pci_device_t trm290_chipsets[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_TEKRAM,
+		device:		PCI_DEVICE_ID_TEKRAM_DC290,
+		name:		"TRM290",
+		init_chipset:	NULL,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_trm290,
+		init_dma:	NULL,
+		channels:	2,
+		autodma:	NOAUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* TRM290_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/via82cxxx.c linux-2.4.21/drivers/ide/pci/via82cxxx.c
--- linux-2.4.20/drivers/ide/pci/via82cxxx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/via82cxxx.c	2002-12-18 18:58:06.000000000 +0000
@@ -0,0 +1,671 @@
+/*
+ * $Id: via82cxxx.c,v 3.35-ac2 2002/09/111 Alan Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *	Michel Aubry
+ *	Jeff Garzik
+ *	Andre Hedrick
+ */
+
+/*
+ * Version 3.35
+ *
+ * VIA IDE driver for Linux. Supported southbridges:
+ *
+ *   vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
+ *   vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a,
+ *   vt8235
+ *
+ * Copyright (c) 2000-2002 Vojtech Pavlik
+ *
+ * Based on the work of:
+ *	Michel Aubry
+ *	Jeff Garzik
+ *	Andre Hedrick
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+
+#include "ide-timing.h"
+#include "via82cxxx.h"
+
+#define VIA_IDE_ENABLE		0x40
+#define VIA_IDE_CONFIG		0x41
+#define VIA_FIFO_CONFIG		0x43
+#define VIA_MISC_1		0x44
+#define VIA_MISC_2		0x45
+#define VIA_MISC_3		0x46
+#define VIA_DRIVE_TIMING	0x48
+#define VIA_8BIT_TIMING		0x4e
+#define VIA_ADDRESS_SETUP	0x4c
+#define VIA_UDMA_TIMING		0x50
+
+#define VIA_UDMA		0x007
+#define VIA_UDMA_NONE		0x000
+#define VIA_UDMA_33		0x001
+#define VIA_UDMA_66		0x002
+#define VIA_UDMA_100		0x003
+#define VIA_UDMA_133		0x004
+#define VIA_BAD_PREQ		0x010	/* Crashes if PREQ# till DDACK# set */
+#define VIA_BAD_CLK66		0x020	/* 66 MHz clock doesn't work correctly */
+#define VIA_SET_FIFO		0x040	/* Needs to have FIFO split set */
+#define VIA_NO_UNMASK		0x080	/* Doesn't work with IRQ unmasking on */
+#define VIA_BAD_ID		0x100	/* Has wrong vendor ID (0x1107) */
+
+/*
+ * VIA SouthBridge chips.
+ */
+
+static struct via_isa_bridge {
+	char *name;
+	u16 id;
+	u8 rev_min;
+	u8 rev_max;
+	u16 flags;
+} via_isa_bridges[] = {
+#ifdef FUTURE_BRIDGES
+	{ "vt8237",	PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_133 },
+#endif
+	{ "vt8235",	PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_133 },
+	{ "vt8233a",	PCI_DEVICE_ID_VIA_8233A,    0x00, 0x2f, VIA_UDMA_133 },
+	{ "vt8233c",	PCI_DEVICE_ID_VIA_8233C_0,  0x00, 0x2f, VIA_UDMA_100 },
+	{ "vt8233",	PCI_DEVICE_ID_VIA_8233_0,   0x00, 0x2f, VIA_UDMA_100 },
+	{ "vt8231",	PCI_DEVICE_ID_VIA_8231,     0x00, 0x2f, VIA_UDMA_100 },
+	{ "vt82c686b",	PCI_DEVICE_ID_VIA_82C686,   0x40, 0x4f, VIA_UDMA_100 },
+	{ "vt82c686a",	PCI_DEVICE_ID_VIA_82C686,   0x10, 0x2f, VIA_UDMA_66 },
+	{ "vt82c686",	PCI_DEVICE_ID_VIA_82C686,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
+	{ "vt82c596b",	PCI_DEVICE_ID_VIA_82C596,   0x10, 0x2f, VIA_UDMA_66 },
+	{ "vt82c596a",	PCI_DEVICE_ID_VIA_82C596,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
+	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO },
+	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ },
+	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO },
+	{ "vt82c586a",	PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
+	{ "vt82c586",	PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
+	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
+	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
+	{ NULL }
+};
+
+static struct via_isa_bridge *via_config;
+static unsigned char via_enabled;
+static unsigned int via_80w;
+static unsigned int via_clock;
+static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
+
+/*
+ * VIA /proc entry.
+ */
+
+#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
+
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 via_proc = 0;
+static unsigned long via_base;
+static struct pci_dev *bmide_dev, *isa_dev;
+
+static char *via_control3[] = { "No limit", "64", "128", "192" };
+
+#define via_print(format, arg...) p += sprintf(p, format "\n" , ## arg)
+#define via_print_drive(name, format, arg...)\
+	p += sprintf(p, name); for (i = 0; i < 4; i++) p += sprintf(p, format, ## arg); p += sprintf(p, "\n");
+
+
+/**
+ *	via_get_info		-	generate via /proc file 
+ *	@buffer: buffer for data
+ *	@addr: set to start of data to use
+ *	@offset: current file offset
+ *	@count: size of read
+ *
+ *	Fills in buffer with the debugging/configuration information for
+ *	the VIA chipset tuning and attached drives
+ */
+ 
+static int via_get_info(char *buffer, char **addr, off_t offset, int count)
+{
+	int speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
+		 uen[4], udma[4], umul[4], active8b[4], recover8b[4];
+	struct pci_dev *dev = bmide_dev;
+	unsigned int v, u, i;
+	u16 c, w;
+	u8 t, x;
+	char *p = buffer;
+
+	via_print("----------VIA BusMastering IDE Configuration"
+		"----------------");
+
+	via_print("Driver Version:                     3.35-ac");
+	via_print("South Bridge:                       VIA %s",
+		via_config->name);
+
+	pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t);
+	pci_read_config_byte(dev, PCI_REVISION_ID, &x);
+	via_print("Revision:                           ISA %#x IDE %#x", t, x);
+	via_print("Highest DMA rate:                   %s",
+		via_dma[via_config->flags & VIA_UDMA]);
+
+	via_print("BM-DMA base:                        %#lx", via_base);
+	via_print("PCI clock:                          %d.%dMHz",
+		via_clock / 1000, via_clock / 100 % 10);
+
+	pci_read_config_byte(dev, VIA_MISC_1, &t);
+	via_print("Master Read  Cycle IRDY:            %dws",
+		(t & 64) >> 6);
+	via_print("Master Write Cycle IRDY:            %dws",
+		(t & 32) >> 5);
+	via_print("BM IDE Status Register Read Retry:  %s",
+		(t & 8) ? "yes" : "no");
+
+	pci_read_config_byte(dev, VIA_MISC_3, &t);
+	via_print("Max DRDY Pulse Width:               %s%s",
+		via_control3[(t & 0x03)], (t & 0x03) ? " PCI clocks" : "");
+
+	via_print("-----------------------Primary IDE"
+		"-------Secondary IDE------");
+	via_print("Read DMA FIFO flush:   %10s%20s",
+		(t & 0x80) ? "yes" : "no", (t & 0x40) ? "yes" : "no");
+	via_print("End Sector FIFO flush: %10s%20s",
+		(t & 0x20) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
+
+	pci_read_config_byte(dev, VIA_IDE_CONFIG, &t);
+	via_print("Prefetch Buffer:       %10s%20s",
+		(t & 0x80) ? "yes" : "no", (t & 0x20) ? "yes" : "no");
+	via_print("Post Write Buffer:     %10s%20s",
+		(t & 0x40) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
+
+	pci_read_config_byte(dev, VIA_IDE_ENABLE, &t);
+	via_print("Enabled:               %10s%20s",
+		(t & 0x02) ? "yes" : "no", (t & 0x01) ? "yes" : "no");
+
+	c = inb(via_base + 0x02) | (inb(via_base + 0x0a) << 8);
+	via_print("Simplex only:          %10s%20s",
+		(c & 0x80) ? "yes" : "no", (c & 0x8000) ? "yes" : "no");
+
+	via_print("Cable Type:            %10s%20s",
+		(via_80w & 1) ? "80w" : "40w", (via_80w & 2) ? "80w" : "40w");
+
+	via_print("-------------------drive0----drive1"
+		"----drive2----drive3-----");
+
+	pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
+	pci_read_config_dword(dev, VIA_DRIVE_TIMING, &v);
+	pci_read_config_word(dev, VIA_8BIT_TIMING, &w);
+
+	if (via_config->flags & VIA_UDMA)
+		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+	else u = 0;
+
+	for (i = 0; i < 4; i++) {
+
+		setup[i]     = ((t >> ((3 - i) << 1)) & 0x3) + 1;
+		recover8b[i] = ((w >> ((1 - (i >> 1)) << 3)) & 0xf) + 1;
+		active8b[i]  = ((w >> (((1 - (i >> 1)) << 3) + 4)) & 0xf) + 1;
+		active[i]    = ((v >> (((3 - i) << 3) + 4)) & 0xf) + 1;
+		recover[i]   = ((v >> ((3 - i) << 3)) & 0xf) + 1;
+		udma[i]      = ((u >> ((3 - i) << 3)) & 0x7) + 2;
+		umul[i]      = ((u >> (((3 - i) & 2) << 3)) & 0x8) ? 1 : 2;
+		uen[i]       = ((u >> ((3 - i) << 3)) & 0x20);
+		den[i]       = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2));
+
+		speed[i] = 2 * via_clock / (active[i] + recover[i]);
+		cycle[i] = 1000000 * (active[i] + recover[i]) / via_clock;
+
+		if (!uen[i] || !den[i])
+			continue;
+
+		switch (via_config->flags & VIA_UDMA) {
+
+			case VIA_UDMA_33:
+				speed[i] = 2 * via_clock / udma[i];
+				cycle[i] = 1000000 * udma[i] / via_clock;
+				break;
+
+			case VIA_UDMA_66:
+				speed[i] = 4 * via_clock / (udma[i] * umul[i]);
+				cycle[i] = 500000 * (udma[i] * umul[i]) / via_clock;
+				break;
+
+			case VIA_UDMA_100:
+				speed[i] = 6 * via_clock / udma[i];
+				cycle[i] = 333333 * udma[i] / via_clock;
+				break;
+
+			case VIA_UDMA_133:
+				speed[i] = 8 * via_clock / udma[i];
+				cycle[i] = 250000 * udma[i] / via_clock;
+				break;
+		}
+	}
+
+	via_print_drive("Transfer Mode: ", "%10s",
+		den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO");
+
+	via_print_drive("Address Setup: ", "%8dns",
+		1000000 * setup[i] / via_clock);
+	via_print_drive("Cmd Active:    ", "%8dns",
+		1000000 * active8b[i] / via_clock);
+	via_print_drive("Cmd Recovery:  ", "%8dns",
+		1000000 * recover8b[i] / via_clock);
+	via_print_drive("Data Active:   ", "%8dns",
+		1000000 * active[i] / via_clock);
+	via_print_drive("Data Recovery: ", "%8dns",
+		1000000 * recover[i] / via_clock);
+	via_print_drive("Cycle Time:    ", "%8dns",
+		cycle[i]);
+	via_print_drive("Transfer Rate: ", "%4d.%dMB/s",
+		speed[i] / 1000, speed[i] / 100 % 10);
+
+	/* hoping it is less than 4K... */
+	return p - buffer;
+}
+
+#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS */
+
+/**
+ *	via_set_speed			-	write timing registers
+ *	@dev: PCI device
+ *	@dn: device
+ *	@timing: IDE timing data to use
+ *
+ *	via_set_speed writes timing values to the chipset registers
+ */
+
+static void via_set_speed(struct pci_dev *dev, u8 dn, struct ide_timing *timing)
+{
+	u8 t;
+
+	pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
+	t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
+	pci_write_config_byte(dev, VIA_ADDRESS_SETUP, t);
+
+	pci_write_config_byte(dev, VIA_8BIT_TIMING + (1 - (dn >> 1)),
+		((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1));
+
+	pci_write_config_byte(dev, VIA_DRIVE_TIMING + (3 - dn),
+		((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1));
+
+	switch (via_config->flags & VIA_UDMA) {
+		case VIA_UDMA_33:  t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
+		case VIA_UDMA_66:  t = timing->udma ? (0xe8 | (FIT(timing->udma, 2, 9) - 2)) : 0x0f; break;
+		case VIA_UDMA_100: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
+		case VIA_UDMA_133: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
+		default: return;
+	}
+
+	pci_write_config_byte(dev, VIA_UDMA_TIMING + (3 - dn), t);
+}
+
+/**
+ *	via_set_drive		-	configure transfer mode
+ *	@drive: Drive to set up
+ *	@speed: desired speed
+ *
+ *	via_set_drive() computes timing values configures the drive and
+ *	the chipset to a desired transfer mode. It also can be called
+ *	by upper layers.
+ */
+
+static int via_set_drive(ide_drive_t *drive, u8 speed)
+{
+	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+	struct ide_timing t, p;
+	unsigned int T, UT;
+
+	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
+		if (ide_config_drive_speed(drive, speed))
+			printk(KERN_WARNING "ide%d: Drive %d didn't "
+				"accept speed setting. Oh, well.\n",
+				drive->dn >> 1, drive->dn & 1);
+
+	T = 1000000000 / via_clock;
+
+	switch (via_config->flags & VIA_UDMA) {
+		case VIA_UDMA_33:   UT = T;   break;
+		case VIA_UDMA_66:   UT = T/2; break;
+		case VIA_UDMA_100:  UT = T/3; break;
+		case VIA_UDMA_133:  UT = T/4; break;
+		default: UT = T;
+	}
+
+	ide_timing_compute(drive, speed, &t, T, UT);
+
+	if (peer->present) {
+		ide_timing_compute(peer, peer->current_speed, &p, T, UT);
+		ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
+	}
+
+	via_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+	drive->current_speed = speed;
+
+	return 0;
+}
+
+/**
+ *	via82cxxx_tune_drive	-	PIO setup
+ *	@drive: drive to set up
+ *	@pio: mode to use (255 for 'best possible')
+ *
+ *	A callback from the upper layers for PIO-only tuning.
+ */
+
+static void via82cxxx_tune_drive(ide_drive_t *drive, u8 pio)
+{
+	if (!((via_enabled >> HWIF(drive)->channel) & 1))
+		return;
+
+	if (pio == 255) {
+		via_set_drive(drive,
+			ide_find_best_mode(drive, XFER_PIO | XFER_EPIO));
+		return;
+	}
+
+	via_set_drive(drive, XFER_PIO_0 + MIN(pio, 5));
+}
+
+/**
+ *	via82cxxx_ide_dma_check		-	set up for DMA if possible
+ *	@drive: IDE drive to set up
+ *
+ *	Set up the drive for the highest supported speed considering the
+ *	driver, controller and cable
+ */
+ 
+static int via82cxxx_ide_dma_check (ide_drive_t *drive)
+{
+	u16 w80 = HWIF(drive)->udma_four;
+
+	u16 speed = ide_find_best_mode(drive,
+		XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
+		(via_config->flags & VIA_UDMA ? XFER_UDMA : 0) |
+		(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) |
+		(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) |
+		(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0));
+
+	via_set_drive(drive, speed);
+
+	if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
+		return HWIF(drive)->ide_dma_on(drive);
+	return HWIF(drive)->ide_dma_off_quietly(drive);
+}
+
+/**
+ *	init_chipset_via82cxxx	-	initialization handler
+ *	@dev: PCI device
+ *	@name: Name of interface
+ *
+ *	The initialization callback. Here we determine the IDE chip type
+ *	and initialize its drive independent registers.
+ */
+
+static unsigned int __init init_chipset_via82cxxx(struct pci_dev *dev, const char *name)
+{
+	struct pci_dev *isa = NULL;
+	u8 t, v;
+	unsigned int u;
+	int i;
+
+	/*
+	 * Find the ISA bridge to see how good the IDE is.
+	 */
+
+	for (via_config = via_isa_bridges; via_config->id; via_config++)
+		if ((isa = pci_find_device(PCI_VENDOR_ID_VIA +
+			!!(via_config->flags & VIA_BAD_ID),
+			via_config->id, NULL))) {
+
+			pci_read_config_byte(isa, PCI_REVISION_ID, &t);
+			if (t >= via_config->rev_min &&
+			    t <= via_config->rev_max)
+				break;
+		}
+
+	if (!via_config->id) {
+		printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, disabling DMA.\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Check 80-wire cable presence and setup Clk66.
+	 */
+
+	switch (via_config->flags & VIA_UDMA) {
+
+		case VIA_UDMA_66:
+			/* Enable Clk66 */
+			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+			pci_write_config_dword(dev, VIA_UDMA_TIMING, u|0x80008);
+			for (i = 24; i >= 0; i -= 8)
+				if (((u >> (i & 16)) & 8) &&
+				    ((u >> i) & 0x20) &&
+				     (((u >> i) & 7) < 2)) {
+					/*
+					 * 2x PCI clock and
+					 * UDMA w/ < 3T/cycle
+					 */
+					via_80w |= (1 << (1 - (i >> 4)));
+				}
+			break;
+
+		case VIA_UDMA_100:
+			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+			for (i = 24; i >= 0; i -= 8)
+				if (((u >> i) & 0x10) ||
+				    (((u >> i) & 0x20) &&
+				     (((u >> i) & 7) < 4))) {
+					/* BIOS 80-wire bit or
+					 * UDMA w/ < 60ns/cycle
+					 */
+					via_80w |= (1 << (1 - (i >> 4)));
+				}
+			break;
+
+		case VIA_UDMA_133:
+			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+			for (i = 24; i >= 0; i -= 8)
+				if (((u >> i) & 0x10) ||
+				    (((u >> i) & 0x20) &&
+				     (((u >> i) & 7) < 8))) {
+					/* BIOS 80-wire bit or
+					 * UDMA w/ < 60ns/cycle
+					 */
+					via_80w |= (1 << (1 - (i >> 4)));
+				}
+			break;
+
+	}
+
+	/* Disable Clk66 */
+	if (via_config->flags & VIA_BAD_CLK66) {
+		/* Would cause trouble on 596a and 686 */
+		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+		pci_write_config_dword(dev, VIA_UDMA_TIMING, u & ~0x80008);
+	}
+
+	/*
+	 * Check whether interfaces are enabled.
+	 */
+
+	pci_read_config_byte(dev, VIA_IDE_ENABLE, &v);
+	via_enabled = ((v & 1) ? 2 : 0) | ((v & 2) ? 1 : 0);
+
+	/*
+	 * Set up FIFO sizes and thresholds.
+	 */
+
+	pci_read_config_byte(dev, VIA_FIFO_CONFIG, &t);
+
+	/* Disable PREQ# till DDACK# */
+	if (via_config->flags & VIA_BAD_PREQ) {
+		/* Would crash on 586b rev 41 */
+		t &= 0x7f;
+	}
+
+	/* Fix FIFO split between channels */
+	if (via_config->flags & VIA_SET_FIFO) {
+		t &= (t & 0x9f);
+		switch (via_enabled) {
+			case 1: t |= 0x00; break;	/* 16 on primary */
+			case 2: t |= 0x60; break;	/* 16 on secondary */
+			case 3: t |= 0x20; break;	/* 8 pri 8 sec */
+		}
+	}
+
+	pci_write_config_byte(dev, VIA_FIFO_CONFIG, t);
+
+	/*
+	 * Determine system bus clock.
+	 */
+
+	via_clock = system_bus_clock() * 1000;
+
+	switch (via_clock) {
+		case 33000: via_clock = 33333; break;
+		case 37000: via_clock = 37500; break;
+		case 41000: via_clock = 41666; break;
+	}
+
+	if (via_clock < 20000 || via_clock > 50000) {
+		printk(KERN_WARNING "VP_IDE: User given PCI clock speed "
+			"impossible (%d), using 33 MHz instead.\n", via_clock);
+		printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want "
+			"to assume 80-wire cable.\n");
+		via_clock = 33333;
+	}
+
+	/*
+	 * Print the boot message.
+	 */
+
+	pci_read_config_byte(isa, PCI_REVISION_ID, &t);
+	printk(KERN_INFO "VP_IDE: VIA %s (rev %02x) IDE %s "
+		"controller on pci%s\n",
+		via_config->name, t,
+		via_dma[via_config->flags & VIA_UDMA],
+		dev->slot_name);
+
+	/*
+	 * Setup /proc/ide/via entry.
+	 */
+
+#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!via_proc) {
+		via_base = pci_resource_start(dev, 4);
+		bmide_dev = dev;
+		isa_dev = isa;
+		ide_pci_register_host_proc(&via_procs[0]);
+		via_proc = 1;
+	}
+#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+static void __init init_hwif_via82cxxx(ide_hwif_t *hwif)
+{
+	int i;
+
+	hwif->autodma = 0;
+
+	hwif->tuneproc = &via82cxxx_tune_drive;
+	hwif->speedproc = &via_set_drive;
+
+	for (i = 0; i < 2; i++) {
+		hwif->drives[i].io_32bit = 1;
+		hwif->drives[i].unmask = (via_config->flags & VIA_NO_UNMASK) ? 0 : 1;
+		hwif->drives[i].autotune = 1;
+		hwif->drives[i].dn = hwif->channel * 2 + i;
+	}
+
+	if (!hwif->dma_base)
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (!(hwif->udma_four))
+		hwif->udma_four = ((via_enabled & via_80w) >> hwif->channel) & 1;
+	hwif->ide_dma_check = &via82cxxx_ide_dma_check;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+/**
+ *	init_dma_via82cxxx	-	set up for IDE DMA
+ *	@hwif: IDE interface
+ *	@dmabase: DMA base address
+ *
+ *	We allow the BM-DMA driver to only work on enabled interfaces.
+ */
+
+static void __init init_dma_via82cxxx(ide_hwif_t *hwif, unsigned long dmabase)
+{
+	if ((via_enabled >> hwif->channel) & 1)
+		ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &via82cxxx_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id via_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name 		= "VIA IDE",
+	.id_table 	= via_pci_tbl,
+	.probe 		= via_init_one,
+};
+
+static int via_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void via_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(via_ide_init);
+module_exit(via_ide_exit);
+
+MODULE_AUTHOR("Vojtech Pavlik, Michel Aubry, Jeff Garzik, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for VIA IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/via82cxxx.h linux-2.4.21/drivers/ide/pci/via82cxxx.h
--- linux-2.4.20/drivers/ide/pci/via82cxxx.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/pci/via82cxxx.h	2002-12-18 18:58:10.000000000 +0000
@@ -0,0 +1,67 @@
+#ifndef VIA82CXXX_H
+#define VIA82CXXX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_VIA_TIMINGS
+
+#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 via_proc;
+
+static int via_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t via_procs[] __initdata = {
+	{
+		.name		= "via",
+		.set		= 1,
+		.get_info	= via_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS */
+
+static unsigned int init_chipset_via82cxxx(struct pci_dev *, const char *);
+static void init_hwif_via82cxxx(ide_hwif_t *);
+static void init_dma_via82cxxx(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t via82cxxx_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_VIA,
+		.device		= PCI_DEVICE_ID_VIA_82C576_1,
+		.name		= "VP_IDE",
+		.init_chipset	= init_chipset_via82cxxx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_via82cxxx,
+		.init_dma	= init_dma_via82cxxx,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_VIA,
+		.device		= PCI_DEVICE_ID_VIA_82C586_1,
+		.name		= "VP_IDE",
+		.init_chipset	= init_chipset_via82cxxx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_via82cxxx,
+		.init_dma	= init_dma_via82cxxx,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* VIA82CXXX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pdc202xx.c linux-2.4.21/drivers/ide/pdc202xx.c
--- linux-2.4.20/drivers/ide/pdc202xx.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/pdc202xx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1188 +0,0 @@
-/*
- *  linux/drivers/ide/pdc202xx.c	Version 0.32	Feb. 27, 2002
- *
- *  Copyright (C) 1998-2000	Andre Hedrick <andre@linux-ide.org>
- *  May be copied or modified under the terms of the GNU General Public License
- *
- *  Promise Ultra66 cards with BIOS v1.11 this
- *  compiled into the kernel if you have more than one card installed.
- *
- *  Promise Ultra100 cards with BIOS v2.01 this
- *  compiled into the kernel if you have more than one card installed.
- *
- *  Promise Ultra100TX2 with BIOS v2.10 & Ultra133TX2 with BIOS v2.20
- *  support 8 hard drives on UDMA mode.
- *
- *  Linux kernel will misunderstand FastTrak ATA-RAID series as Ultra
- *  IDE Controller, UNLESS you enable "CONFIG_PDC202XX_FORCE"
- *  That's you can use FastTrak ATA-RAID controllers as IDE controllers.
- *
- *  History :
- *  05/22/01    v1.20 b1
- *           (1) support PDC20268
- *           (2) fix cable judge function
- *  08/22/01    v1.20 b2
- *           (1) support ATA-133 PDC20269/75
- *           (2) support UDMA Mode 6
- *           (3) fix proc report information
- *           (4) set ATA133 timing
- *           (5) fix ultra dma bit 14 selectable
- *           (6) support 32bit LBA
- *  09/11/01    v1.20 b3 
- *           (1) fix eighty_ninty_three()
- *           (2) fix offset address 0x1c~0x1f
- *  10/30/01    v1.20 b4
- *           (1) fix 48bit LBA HOB bit
- *           (2) force rescan drive under PIO modes if need
- *  11/02/01    v1.20.0.5
- *           (1) could be patched with ext3 filesystem code
- *  11/06/01    v1.20.0.6
- *           (1) fix LBA48 drive running without Promise controllers
- *           (2) fix LBA48 drive running under PIO modes
- *  01/28/02    v1.20.0.6
- *           (1) release for linux IDE Group kernel 2.4.18
- *           (2) add version and controller info to proc
- *  05/23/02    v1.20.0.7
- *           (1) disable PDC20262 running with 48bit
- *           (2) Add quirk drive lists for PDC20265/67
- *
- *  Copyright (C) 1999-2002 Promise Technology, Inc.
- *  Author: Frank Tiernan <frankt@promise.com>
- *          PROMISE pdc202xx IDE Controller driver MAINTAINERS
- *  Released under terms of General Public License
- */
- 
-#define VERSION	"1.20.0.7"
-#define VERDATE "2002-05-23"
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#define PDC202XX_DEBUG_DRIVE_INFO		0
-#define PDC202XX_DECODE_REGISTER_INFO		0
-
-#define DISPLAY_PDC202XX_TIMINGS
-
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-
-#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int pdc202xx_get_info(char *, char **, off_t, int);
-extern int (*pdc202xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-static struct hd_driveid *id[4];
-static int speed_rate[4];
-
-static char * pdc202xx_info (char *buf, struct pci_dev *dev)
-{
-	char *p = buf;
-
-	u32 bibma  = pci_resource_start(dev, 4);
-	u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
-	u16 reg50h = 0;
-	u16 word88 = 0;
-	int udmasel[4] = {0,0,0,0}, piosel[4] = {0,0,0,0};
-	int i = 0, hd = 0;
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-	u8 c0	= inb_p((unsigned short)bibma + 0x02);
-	u8 c1	= inb_p((unsigned short)bibma + 0x0a);
-
-	u8 sc11	= inb_p((unsigned short)bibma + 0x11);
-	u8 sc1a	= inb_p((unsigned short)bibma + 0x1a);
-	u8 sc1b	= inb_p((unsigned short)bibma + 0x1b);
-	/* u8 sc1c	= inb_p((unsigned short)bibma + 0x1c); 
-	u8 sc1d	= inb_p((unsigned short)bibma + 0x1d);
-	u8 sc1e	= inb_p((unsigned short)bibma + 0x1e);
-	u8 sc1f	= inb_p((unsigned short)bibma + 0x1f); */
-
-	pci_read_config_word(dev, 0x50, &reg50h);
-	pci_read_config_dword(dev, 0x60, &reg60h);
-	pci_read_config_dword(dev, 0x64, &reg64h);
-	pci_read_config_dword(dev, 0x68, &reg68h);
-	pci_read_config_dword(dev, 0x6c, &reg6ch);
-
-	p+=sprintf(p, "\nPROMISE Ultra series driver Ver %s %s Adapter: ", VERSION, VERDATE);
-	switch(dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20275:
-			p += sprintf(p, "MBUltra133\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20269:
-			p += sprintf(p, "Ultra133 TX2\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20268:
-			p += sprintf(p, "Ultra100 TX2\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20267:
-			p += sprintf(p, "Ultra100\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20265:
-			p += sprintf(p, "Ultra100 on M/B\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20262:
-			p += sprintf(p, "Ultra66\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20246:
-			p += sprintf(p, "Ultra33\n");
-			reg50h |= 0x0c00;
-			break;
-		default:
-			p += sprintf(p, "Ultra Series\n");
-			break;
-	}
-
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %s                         %s\n",
-		(c0&0x80)?"disabled":"enabled ",
-		(c1&0x80)?"disabled":"enabled ");
-	p += sprintf(p, "66 Clocking     %s                         %s\n",
-		(sc11&0x02)?"enabled ":"disabled",
-		(sc11&0x08)?"enabled ":"disabled");
-	p += sprintf(p, "Mode            %s                           %s\n",
-		(sc1a & 0x01) ? "MASTER" : "PCI   ",
-		(sc1b & 0x01) ? "MASTER" : "PCI   ");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-		(id[0]!=NULL && (c0&0x20))?"yes":"no ",(id[1]!=NULL && (c0&0x40))?"yes":"no ",
-		(id[2]!=NULL && (c1&0x20))?"yes":"no ",(id[3]!=NULL && (c1&0x40))?"yes":"no ");
-	for( hd = 0; hd < 4 ; hd++) {
-		if (id[hd] == NULL)
-			continue;
-		word88 = id[hd]->dma_ultra;
-		for ( i = 7 ; i >= 0 ; i--)
-			if (word88 >> (i+8)) {
-				udmasel[hd] = i;	/* get select UDMA mode */
-				break;
-			}
-		piosel[hd] = (id[hd]->eide_pio_modes >= 0x02) ? 4 : 3;
-        }
-	p += sprintf(p, "UDMA Mode:      %d                %d               %d                 %d\n",
-		udmasel[0], udmasel[1], udmasel[2], udmasel[3]);
-	p += sprintf(p, "PIO Mode:       %d                %d               %d                 %d\n",
-		piosel[0], piosel[1], piosel[2], piosel[3]);
-#if 0
-	p += sprintf(p, "--------------- Can ATAPI DMA ---------------\n");
-#endif
-	return (char *)p;
-}
-
-static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	
-	p = pdc202xx_info(buffer, bmide_dev);
-	return p-buffer;	/* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte pdc202xx_proc = 0;
-
-const char *pdc_quirk_drives[] = {
-	"QUANTUM FIREBALLlct08 08",
-	"QUANTUM FIREBALLP KA6.4",
-	"QUANTUM FIREBALLP KA9.1",
-	"QUANTUM FIREBALLP LM20.4",
-	"QUANTUM FIREBALLP KX13.6",
-	"QUANTUM FIREBALLP KX20.5",
-	"QUANTUM FIREBALLP KX27.3",
-	"QUANTUM FIREBALLP LM20.5",
-	NULL
-};
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/* A Register */
-#define	SYNC_ERRDY_EN	0xC0
-
-#define	SYNC_IN		0x80	/* control bit, different for master vs. slave drives */
-#define	ERRDY_EN	0x40	/* control bit, different for master vs. slave drives */
-#define	IORDY_EN	0x20	/* PIO: IOREADY */
-#define	PREFETCH_EN	0x10	/* PIO: PREFETCH */
-
-#define	PA3		0x08	/* PIO"A" timing */
-#define	PA2		0x04	/* PIO"A" timing */
-#define	PA1		0x02	/* PIO"A" timing */
-#define	PA0		0x01	/* PIO"A" timing */
-
-/* B Register */
-
-#define	MB2		0x80	/* DMA"B" timing */
-#define	MB1		0x40	/* DMA"B" timing */
-#define	MB0		0x20	/* DMA"B" timing */
-
-#define	PB4		0x10	/* PIO_FORCE 1:0 */
-
-#define	PB3		0x08	/* PIO"B" timing */	/* PIO flow Control mode */
-#define	PB2		0x04	/* PIO"B" timing */	/* PIO 4 */
-#define	PB1		0x02	/* PIO"B" timing */	/* PIO 3 half */
-#define	PB0		0x01	/* PIO"B" timing */	/* PIO 3 other half */
-
-/* C Register */
-#define	IORDYp_NO_SPEED	0x4F
-#define	SPEED_DIS	0x0F
-
-#define	DMARQp		0x80
-#define	IORDYp		0x40
-#define	DMAR_EN		0x20
-#define	DMAW_EN		0x10
-
-#define	MC3		0x08	/* DMA"C" timing */
-#define	MC2		0x04	/* DMA"C" timing */
-#define	MC1		0x02	/* DMA"C" timing */
-#define	MC0		0x01	/* DMA"C" timing */
-
-#if PDC202XX_DECODE_REGISTER_INFO
-
-#define REG_A		0x01
-#define REG_B		0x02
-#define REG_C		0x04
-#define REG_D		0x08
-
-static void decode_registers (byte registers, byte value)
-{
-	byte	bit = 0, bit1 = 0, bit2 = 0;
-
-	switch(registers) {
-		case REG_A:
-			bit2 = 0;
-			printk("A Register ");
-			if (value & 0x80) printk("SYNC_IN ");
-			if (value & 0x40) printk("ERRDY_EN ");
-			if (value & 0x20) printk("IORDY_EN ");
-			if (value & 0x10) printk("PREFETCH_EN ");
-			if (value & 0x08) { printk("PA3 ");bit2 |= 0x08; }
-			if (value & 0x04) { printk("PA2 ");bit2 |= 0x04; }
-			if (value & 0x02) { printk("PA1 ");bit2 |= 0x02; }
-			if (value & 0x01) { printk("PA0 ");bit2 |= 0x01; }
-			printk("PIO(A) = %d ", bit2);
-			break;
-		case REG_B:
-			bit1 = 0;bit2 = 0;
-			printk("B Register ");
-			if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; }
-			if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; }
-			if (value & 0x20) { printk("MB0 ");bit1 |= 0x20; }
-			printk("DMA(B) = %d ", bit1 >> 5);
-			if (value & 0x10) printk("PIO_FORCED/PB4 ");
-			if (value & 0x08) { printk("PB3 ");bit2 |= 0x08; }
-			if (value & 0x04) { printk("PB2 ");bit2 |= 0x04; }
-			if (value & 0x02) { printk("PB1 ");bit2 |= 0x02; }
-			if (value & 0x01) { printk("PB0 ");bit2 |= 0x01; }
-			printk("PIO(B) = %d ", bit2);
-			break;
-		case REG_C:
-			bit2 = 0;
-			printk("C Register ");
-			if (value & 0x80) printk("DMARQp ");
-			if (value & 0x40) printk("IORDYp ");
-			if (value & 0x20) printk("DMAR_EN ");
-			if (value & 0x10) printk("DMAW_EN ");
-
-			if (value & 0x08) { printk("MC3 ");bit2 |= 0x08; }
-			if (value & 0x04) { printk("MC2 ");bit2 |= 0x04; }
-			if (value & 0x02) { printk("MC1 ");bit2 |= 0x02; }
-			if (value & 0x01) { printk("MC0 ");bit2 |= 0x01; }
-			printk("DMA(C) = %d ", bit2);
-			break;
-		case REG_D:
-			printk("D Register ");
-			break;
-		default:
-			return;
-	}
-	printk("\n        %s ", (registers & REG_D) ? "DP" :
-				(registers & REG_C) ? "CP" :
-				(registers & REG_B) ? "BP" :
-				(registers & REG_A) ? "AP" : "ERROR");
-	for (bit=128;bit>0;bit/=2)
-		printk("%s", (value & bit) ? "1" : "0");
-	printk("\n");
-}
-
-#endif /* PDC202XX_DECODE_REGISTER_INFO */
-
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (pdc_quirk_drives == list) {
-		while (*list) {
-			if (strstr(id->model, *list++)) {
-				return 2;
-			}
-		}
-	} else {
-		while (*list) {
-			if (!strcmp(*list++,id->model)) {
-				return 1;
-			}
-		}
-	}
-	return 0;
-}
-
-static int pdc202xx_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	unsigned int		drive_conf;
-	int			err = 0, i = 0, j = hwif->channel ? 2 : 0 ;
-	byte			drive_pci, AP, BP, CP, DP;
-	byte			TA = 0, TB = 0, TC = 0;
-
-	switch (drive->dn) {
-		case 0: drive_pci = 0x60; break;
-		case 1: drive_pci = 0x64; break;
-		case 2: drive_pci = 0x68; break;
-		case 3: drive_pci = 0x6c; break;
-		default: return -1;
-	}
-
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))	return -1;
-
-	pci_read_config_dword(dev, drive_pci, &drive_conf);
-	pci_read_config_byte(dev, (drive_pci), &AP);
-	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (speed >= XFER_SW_DMA_0) {
-		if ((BP & 0xF0) && (CP & 0x0F)) {
-			/* clear DMA modes of upper 842 bits of B Register */
-			/* clear PIO forced mode upper 1 bit of B Register */
-			pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0xF0);
-			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-
-			/* clear DMA modes of lower 8421 bits of C Register */
-			pci_write_config_byte(dev, (drive_pci)|0x02, CP & ~0x0F);
-			pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-		}
-	} else {
-#else
-	{
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		if ((AP & 0x0F) || (BP & 0x07)) {
-			/* clear PIO modes of lower 8421 bits of A Register */
-			pci_write_config_byte(dev, (drive_pci), AP & ~0x0F);
-			pci_read_config_byte(dev, (drive_pci), &AP);
-
-			/* clear PIO modes of lower 421 bits of B Register */
-			pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0x07);
-			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-
-			pci_read_config_byte(dev, (drive_pci), &AP);
-			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-		}
-	}
-
-	pci_read_config_byte(dev, (drive_pci), &AP);
-	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-
-	for ( i = 0; i < 2; i++)
-		if (hwif->drives[i].present)
-	  		id[i+j] = hwif->drives[i].id;	/* get identify structs */
-
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		/* case XFER_UDMA_6: */
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:	TB = 0x20; TC = 0x01; break;	/* speed 8 == UDMA mode 4 */
-		case XFER_UDMA_3:	TB = 0x40; TC = 0x02; break;	/* speed 7 == UDMA mode 3 */
-		case XFER_UDMA_2:	TB = 0x20; TC = 0x01; break;	/* speed 6 == UDMA mode 2 */
-		case XFER_UDMA_1:	TB = 0x40; TC = 0x02; break;	/* speed 5 == UDMA mode 1 */
-		case XFER_UDMA_0:	TB = 0x60; TC = 0x03; break;	/* speed 4 == UDMA mode 0 */
-		case XFER_MW_DMA_2:	TB = 0x60; TC = 0x03; break;	/* speed 4 == MDMA mode 2 */
-		case XFER_MW_DMA_1:	TB = 0x60; TC = 0x04; break;	/* speed 3 == MDMA mode 1 */
-		case XFER_MW_DMA_0:	TB = 0x60; TC = 0x05; break;	/* speed 2 == MDMA mode 0 */
-		case XFER_SW_DMA_2:	TB = 0x60; TC = 0x05; break;	/* speed 0 == SDMA mode 2 */
-		case XFER_SW_DMA_1:	TB = 0x80; TC = 0x06; break;	/* speed 1 == SDMA mode 1 */
-		case XFER_SW_DMA_0:	TB = 0xC0; TC = 0x0B; break;	/* speed 0 == SDMA mode 0 */
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:	TA = 0x01; TB = 0x04; break;
-		case XFER_PIO_3:	TA = 0x02; TB = 0x06; break;
-		case XFER_PIO_2:	TA = 0x03; TB = 0x08; break;
-		case XFER_PIO_1:	TA = 0x05; TB = 0x0C; break;
-		case XFER_PIO_0:
-		default:		TA = 0x09; TB = 0x13; break;
-	}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-        if (speed >= XFER_SW_DMA_0) {
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
-		pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
-	} else {
-#else
-	{
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		pci_write_config_byte(dev, (drive_pci), AP|TA);
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
-	}
-
-#if PDC202XX_DECODE_REGISTER_INFO
-	pci_read_config_byte(dev, (drive_pci), &AP);
-	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
-
-	decode_registers(REG_A, AP);
-	decode_registers(REG_B, BP);
-	decode_registers(REG_C, CP);
-	decode_registers(REG_D, DP);
-#endif /* PDC202XX_DECODE_REGISTER_INFO */
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-
-#if PDC202XX_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d 0x%08x ",
-		drive->name, ide_xfer_verbose(speed),
-		drive->dn, drive_conf);
-		pci_read_config_dword(dev, drive_pci, &drive_conf);
-	printk("0x%08x\n", drive_conf);
-#endif /* PDC202XX_DEBUG_DRIVE_INFO */
-	return err;
-}
-
-static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	unsigned long indexreg	= (hwif->dma_base + 1);
-	unsigned long datareg	= (hwif->dma_base + 3);
-#else
-	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned long high_16	= pci_resource_start(dev, 4);
-	unsigned long indexreg	= high_16 + (hwif->channel ? 0x09 : 0x01);
-	unsigned long datareg	= (indexreg + 2);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	byte thold		= 0x10;
-	byte adj		= (drive->dn%2) ? 0x08 : 0x00;
-	int set_speed		= 0, i=0, j=hwif->channel ? 2:0;
-	int                     err;
-
-	/* Setting tHOLD bit to 0 if using UDMA mode 2 */
-	if (speed == XFER_UDMA_2) {
-		OUT_BYTE((thold + adj), indexreg);
-		OUT_BYTE((IN_BYTE(datareg) & 0x7f), datareg);
-	}
-	
-	/* We need to set ATA133 timing if ATA133 drives exist */
-	if (speed>=XFER_UDMA_6)
-		set_speed=1;
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-#if PDC202XX_DEBUG_DRIVE_INFO
-	printk("%s: Before set_feature = %s, word88 = %#x\n",
-		drive->name, ide_xfer_verbose(speed), drive->id->dma_ultra );
-#endif /* PDC202XX_DEBUG_DRIVE_INFO */
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;	
-	for ( i = 0 ; i < 2 ; i++)
-		if (hwif->drives[i].present) {
-	  		id[i+j] = hwif->drives[i].id;	/* get identify structs */
-	 		speed_rate[i+j] = speed;	/* get current speed */
-	 	}
-	if (set_speed) {
-		for (i=0; i<4; i++) {
-			if (id[i]==NULL)
-				continue;
-			switch(speed_rate[i]) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-				case XFER_UDMA_6:
-					OUT_BYTE((0x10 + adj), indexreg);
-					OUT_BYTE(0x1a, datareg);
-					OUT_BYTE((0x11 + adj), indexreg);
-					OUT_BYTE(0x01, datareg);
-					OUT_BYTE((0x12 + adj), indexreg);
-					OUT_BYTE(0xcb, datareg);
-					break;
-				case XFER_UDMA_5:
-					OUT_BYTE((0x10 + adj), indexreg);
-					OUT_BYTE(0x1a, datareg);
-					OUT_BYTE((0x11 + adj), indexreg);
-					OUT_BYTE(0x02, datareg);
-					OUT_BYTE((0x12 + adj), indexreg);
-					OUT_BYTE(0xcb, datareg);
-					break;
-				case XFER_UDMA_4:
-					OUT_BYTE((0x10 + adj), indexreg);
-					OUT_BYTE(0x1a, datareg);
-					OUT_BYTE((0x11 + adj), indexreg);
-					OUT_BYTE(0x03, datareg);
-					OUT_BYTE((0x12 + adj), indexreg);
-					OUT_BYTE(0xcd, datareg);
-					break;
-				case XFER_UDMA_3:
-					OUT_BYTE((0x10 + adj), indexreg);
-					OUT_BYTE(0x1a, datareg);
-					OUT_BYTE((0x11 + adj), indexreg);
-					OUT_BYTE(0x05, datareg);
-					OUT_BYTE((0x12 + adj), indexreg);
-					OUT_BYTE(0xcd, datareg);
-					break;
-				case XFER_UDMA_2:
-					OUT_BYTE((0x10 + adj), indexreg);
-					OUT_BYTE(0x2a, datareg);
-					OUT_BYTE((0x11 + adj), indexreg);
-					OUT_BYTE(0x07, datareg);
-					OUT_BYTE((0x12 + adj), indexreg);
-					OUT_BYTE(0xcd, datareg);
-					break;
-				case XFER_UDMA_1:
-					OUT_BYTE((0x10 + adj), indexreg);
-					OUT_BYTE(0x3a, datareg);
-					OUT_BYTE((0x11 + adj), indexreg);
-					OUT_BYTE(0x0a, datareg);
-					OUT_BYTE((0x12 + adj), indexreg);
-					OUT_BYTE(0xd0, datareg);
-					break;
-				case XFER_UDMA_0:
-					OUT_BYTE((0x10 + adj), indexreg);
-					OUT_BYTE(0x4a, datareg);
-					OUT_BYTE((0x11 + adj), indexreg);
-					OUT_BYTE(0x0f, datareg);
-					OUT_BYTE((0x12 + adj), indexreg);
-					OUT_BYTE(0xd5, datareg);
-					break;
-				case XFER_MW_DMA_2:
-					OUT_BYTE((0x0e + adj), indexreg);
-					OUT_BYTE(0x69, datareg);
-					OUT_BYTE((0x0f + adj), indexreg);
-					OUT_BYTE(0x25, datareg);
-					break;
-				case XFER_MW_DMA_1:
-					OUT_BYTE((0x0e + adj), indexreg);
-					OUT_BYTE(0x6b, datareg);
-					OUT_BYTE((0x0f+ adj), indexreg);
-					OUT_BYTE(0x27, datareg);
-					break;
-				case XFER_MW_DMA_0:
-					OUT_BYTE((0x0e + adj), indexreg);
-					OUT_BYTE(0xdf, datareg);
-					OUT_BYTE((0x0f + adj), indexreg);
-					OUT_BYTE(0x5f, datareg);
-					break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-				case XFER_PIO_4:
-					OUT_BYTE((0x0c + adj), indexreg);
-					OUT_BYTE(0x23, datareg);
-					OUT_BYTE((0x0d + adj), indexreg);
-					OUT_BYTE(0x09, datareg);
-					OUT_BYTE((0x13 + adj), indexreg);
-					OUT_BYTE(0x25, datareg);
-					break;
-				case XFER_PIO_3:
-					OUT_BYTE((0x0c + adj), indexreg);
-					OUT_BYTE(0x27, datareg);
-					OUT_BYTE((0x0d + adj), indexreg);
-					OUT_BYTE(0x0d, datareg);
-					OUT_BYTE((0x13 + adj), indexreg);
-					OUT_BYTE(0x35, datareg);
-					break;
-				case XFER_PIO_2:
-					OUT_BYTE((0x0c + adj), indexreg);
-					OUT_BYTE(0x23, datareg);
-					OUT_BYTE((0x0d + adj), indexreg);
-					OUT_BYTE(0x26, datareg);
-					OUT_BYTE((0x13 + adj), indexreg);
-					OUT_BYTE(0x64, datareg);
-					break;
-				case XFER_PIO_1:
-					OUT_BYTE((0x0c + adj), indexreg);
-					OUT_BYTE(0x46, datareg);
-					OUT_BYTE((0x0d + adj), indexreg);
-					OUT_BYTE(0x29, datareg);
-					OUT_BYTE((0x13 + adj), indexreg);
-					OUT_BYTE(0xa4, datareg);
-					break;
-				case XFER_PIO_0:
-					OUT_BYTE((0x0c + adj), indexreg);
-					OUT_BYTE(0xfb, datareg);
-					OUT_BYTE((0x0d + adj), indexreg);
-					OUT_BYTE(0x2b, datareg);
-					OUT_BYTE((0x13 + adj), indexreg);
-					OUT_BYTE(0xac, datareg);
-					break;
-				default:
-			}
-		}
-	}
-	return err;
-}
-
-/*   0    1    2    3    4    5    6   7   8
- * 960, 480, 390, 300, 240, 180, 120, 90, 60
- *           180, 150, 120,  90,  60
- * DMA_Speed
- * 180, 120,  90,  90,  90,  60,  30
- *  11,   5,   4,   3,   2,   1,   0
- */
-static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
-{
-	byte speed = 0x00;
-
-	pio = (pio == 5) ? 4 : pio;
-	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
-        
-	return ((int) pdc202xx_tune_chipset(drive, speed));
-}
-
-static void pdc202xx_tune_drive (ide_drive_t *drive, byte pio)
-{
-	(void) config_chipset_for_pio(drive, pio);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned long high_16   = pci_resource_start(dev, 4);
-	unsigned long dma_base  = hwif->dma_base;
-	unsigned long indexreg	= dma_base + 1;
-	unsigned long datareg	= dma_base + 3;
-	byte iordy		= 0x13;
-	byte adj		= (drive->dn%2) ? 0x08 : 0x00;
-	byte cable		= 0;
-	byte new_chip		= 0;
-	byte unit		= (drive->select.b.unit & 0x01);
-	unsigned int		drive_conf;
-	byte			drive_pci = 0;
-	byte			test1, test2, speed = -1;
-	byte			AP;
-	unsigned short		EP;
-	byte CLKSPD		= 0;
-	byte clockreg		= high_16 + 0x11;
-	byte udma_33		= ultra;
-	byte udma_66		= ((eighty_ninty_three(drive)) && udma_33) ? 1 : 0;
-	byte udma_100		= 0;
-	byte udma_133		= 0;
-	byte mask			= hwif->channel ? 0x08 : 0x02;
-	unsigned short c_mask	= hwif->channel ? (1<<11) : (1<<10);
-
-	byte ultra_66		= ((id->dma_ultra & 0x0010) ||
-				   (id->dma_ultra & 0x0008)) ? 1 : 0;
-	byte ultra_100		= ((id->dma_ultra & 0x0020) ||
-				   (ultra_66)) ? 1 : 0;
-	byte ultra_133		= ((id->dma_ultra & 0x0040) ||
-				   (ultra_100)) ? 1 : 0;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20269:
-			udma_133 = (udma_66) ? 1 : 0;
-			udma_100 = (udma_66) ? 1 : 0;
-			OUT_BYTE(0x0b, (hwif->dma_base + 1));
-			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
-			new_chip = 1;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20270:
-			udma_100 = (udma_66) ? 1 : 0;
-			OUT_BYTE(0x0b, (hwif->dma_base + 1));
-			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
-			new_chip = 1;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20265:
-			udma_100 = (udma_66) ? 1 : 0;
-			pci_read_config_word(dev, 0x50, &EP);
-			cable = (EP & c_mask);
-			new_chip = 0;
-			CLKSPD = IN_BYTE(clockreg);
-			break;
-		case PCI_DEVICE_ID_PROMISE_20262:
-			pci_read_config_word(dev, 0x50, &EP);
-			cable = (EP & c_mask);
-			new_chip = 0;
-			CLKSPD = IN_BYTE(clockreg);
-			break;
-		default:
-			udma_100 = 0; udma_133 = 0; cable = 0; new_chip = 1;
-			break;
-	}
-
-	/*
-	 * Set the control register to use the 66Mhz system
-	 * clock for UDMA 3/4 mode operation. If one drive on
-	 * a channel is U66 capable but the other isn't we
-	 * fall back to U33 mode. The BIOS INT 13 hooks turn
-	 * the clock on then off for each read/write issued. I don't
-	 * do that here because it would require modifying the
-	 * kernel, seperating the fop routines from the kernel or
-	 * somehow hooking the fops calls. It may also be possible to
-	 * leave the 66Mhz clock on and readjust the timing
-	 * parameters.
-	 */
-
-	if (((ultra_66) || (ultra_100) || (ultra_133)) && (cable)) {
-#ifdef DEBUG
-		printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->channel ? "Secondary" : "Primary");
-		printk("         Switching to Ultra33 mode.\n");
-#endif /* DEBUG */
-		/* Primary   : zero out second bit */
-		/* Secondary : zero out fourth bit */
-		//if (!new_chip)
-		OUT_BYTE(CLKSPD & ~mask, clockreg);
-		printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
-		printk("%s reduced to Ultra33 mode.\n", drive->name);
-		udma_66 = 0; udma_100 = 0; udma_133 = 0;
-	} else {
-		if ((ultra_66) || (ultra_100) || (ultra_133)) {
-			/*
-			 * check to make sure drive on same channel
-			 * is u66 capable
-			 */
-			if (hwif->drives[!(drive->dn%2)].id) {
-				if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0040) ||
-				    (hwif->drives[!(drive->dn%2)].id->dma_ultra
-& 0x0020) ||
-				    (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0010) ||
-				    (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0008)) {
-					OUT_BYTE(CLKSPD | mask, clockreg);
-				} else {
-					OUT_BYTE(CLKSPD & ~mask, clockreg);
-				}
-			} else { /* udma4 drive by itself */
-				OUT_BYTE(CLKSPD | mask, clockreg);
-			}
-		}
-	}
-
-	if (new_chip)	goto chipset_is_set;
-
-	switch(drive->dn) {
-		case 0:	drive_pci = 0x60;
-			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
-			pci_read_config_byte(dev, (drive_pci), &test1);
-			if (!(test1 & SYNC_ERRDY_EN))
-				pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN);
-			break;
-		case 1:	drive_pci = 0x64;
-			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
-			pci_read_config_byte(dev, 0x60, &test1);
-			pci_read_config_byte(dev, (drive_pci), &test2);
-			if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
-				pci_write_config_byte(dev, (drive_pci), test2|SYNC_ERRDY_EN);
-			break;
-		case 2:	drive_pci = 0x68;
-			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
-			pci_read_config_byte(dev, (drive_pci), &test1);
-			if (!(test1 & SYNC_ERRDY_EN))
-				pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN);
-			break;
-		case 3:	drive_pci = 0x6c;
-			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
-			pci_read_config_byte(dev, 0x68, &test1);
-			pci_read_config_byte(dev, (drive_pci), &test2);
-			if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
-				pci_write_config_byte(dev, (drive_pci), test2|SYNC_ERRDY_EN);
-			break;
-		default:
-			return ide_dma_off;
-	}
-
-chipset_is_set:
-
-	if (drive->media != ide_disk)
-		return ide_dma_off_quietly;
-	
-	if (new_chip) {
-		if (id->capability & 4) {	/* IORDY_EN & PREFETCH_EN */
-			OUT_BYTE((iordy + adj), indexreg);
-			OUT_BYTE((IN_BYTE(datareg)|0x03), datareg);
-		}
-	}
-	else {
-		pci_read_config_byte(dev, (drive_pci), &AP);
-		if (id->capability & 4)	/* IORDY_EN */
-			pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN);
-		pci_read_config_byte(dev, (drive_pci), &AP);
-		if (drive->media == ide_disk)	/* PREFETCH_EN */
-			pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
-	}
-
-	if ((id->dma_ultra & 0x0040)&&(udma_133))	speed = XFER_UDMA_6;
-	else if ((id->dma_ultra & 0x0020)&&(udma_100))	speed = XFER_UDMA_5;
-	else if ((id->dma_ultra & 0x0010)&&(udma_66))	speed = XFER_UDMA_4;
-	else if ((id->dma_ultra & 0x0008)&&(udma_66))	speed = XFER_UDMA_3;
-	else if ((id->dma_ultra & 0x0004)&&(udma_33))	speed = XFER_UDMA_2;
-	else if ((id->dma_ultra & 0x0002)&&(udma_33))	speed = XFER_UDMA_1;
-	else if ((id->dma_ultra & 0x0001)&&(udma_33))	speed = XFER_UDMA_0;
-	else if (id->dma_mword & 0x0004)		speed = XFER_MW_DMA_2;
-	else if (id->dma_mword & 0x0002)		speed = XFER_MW_DMA_1;
-	else if (id->dma_mword & 0x0001)		speed = XFER_MW_DMA_0;
-	else if ((id->dma_1word & 0x0004)&&(!new_chip))	speed = XFER_SW_DMA_2;
-	else if ((id->dma_1word & 0x0002)&&(!new_chip))	speed = XFER_SW_DMA_1;
-	else if ((id->dma_1word & 0x0001)&&(!new_chip))	speed = XFER_SW_DMA_0;
-	else {
-		/* restore original pci-config space */
-		if (!new_chip)
-			pci_write_config_dword(dev, drive_pci, drive_conf);
-		return ide_dma_off_quietly;
-	}
-
-	outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	(void) hwif->speedproc(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 14) & 3) ? ide_dma_on :
-			((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on : 
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_hwif_t *hwif = HWIF(drive);
-	ide_dma_action_t dma_func = ide_dma_off_quietly;
-
-	if (id && (id->capability & 1) && hwif->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x007F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive, 1);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive, 0);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive, 0);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		(void) config_chipset_for_pio(drive, 5);
-	}
-
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-int pdc202xx_quirkproc (ide_drive_t *drive)
-{
-	return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
-}
-
-/*
- * pdc202xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- */
-int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	byte dma_stat		= 0;
-	byte sc1d		= 0;
-	byte newchip		= 0;
-	byte clock		= 0;
-	byte hardware48fix	= 0;
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned long high_16	= pci_resource_start(dev, 4);
-	unsigned long dma_base	= hwif->dma_base;
-	unsigned long atapi_port= hwif->channel ? high_16+0x24 : high_16+0x20;
-
-	switch (dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20270:
-			newchip = 1;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20265:
-			hardware48fix = 1;
-			clock = IN_BYTE(high_16 + 0x11);
-		default:
-			break;
-	}
-
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_begin:
-			/* Note that this is done *after* the cmd has
-			 * been issued to the drive, as per the BM-IDE spec.
-			 * The Promise Ultra33 doesn't work correctly when
-			 * we do this part before issuing the drive cmd.
-			 */
-			/* Enable ATAPI UDMA port for 48bit data on PDC20267 */
-			if ((drive->addressing) && (hardware48fix)) {
-				struct request *rq = HWGROUP(drive)->rq;
-				unsigned long word_count = 0;
-				unsigned long hankval = 0;
-				byte	clockreg = high_16 + 0x11;
-				
-				OUT_BYTE(clock|(hwif->channel ? 0x08:0x02), clockreg);
-				word_count = (rq->nr_sectors << 8);
-				hankval = (rq->cmd == READ) ? 0x05<<24 : 0x06<<24;
-				hankval = hankval | word_count ;
-				outl(hankval, atapi_port);
-			}  
-			break;
-		case ide_dma_end:
-			/* Disable ATAPI UDMA port for 48bit data on PDC20267 */
-			if ((drive->addressing) && (hardware48fix)) {
-				unsigned long hankval = 0;
-				byte	clockreg = high_16 + 0x11;
-				
-			    	outl(hankval, atapi_port);	/* zero out extra */
-				clock = IN_BYTE(clockreg);
-				OUT_BYTE(clock & ~(hwif->channel ? 0x08:0x02), clockreg);
-			}
-			break;
-		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = IN_BYTE(dma_base+2);
-			if (newchip)
-				return (dma_stat & 4) == 4;
-
-			sc1d = IN_BYTE(high_16 + 0x001d);
-			if (HWIF(drive)->channel) {
-				if ((sc1d & 0x50) == 0x50) goto somebody_else;
-				else if ((sc1d & 0x40) == 0x40)
-					return (dma_stat & 4) == 4;
-			} else {
-				if ((sc1d & 0x05) == 0x05) goto somebody_else;
-				else if ((sc1d & 0x04) == 0x04)
-					return (dma_stat & 4) == 4;
-			}
-somebody_else:
-			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-		case ide_dma_lostirq:
-		case ide_dma_timeout:
-			if (HWIF(drive)->resetproc != NULL)
-				HWIF(drive)->resetproc(drive);
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-void pdc202xx_reset (ide_drive_t *drive)
-{
-	OUT_BYTE(0x04,IDE_CONTROL_REG);
-	mdelay(1000);
-	OUT_BYTE(0x00,IDE_CONTROL_REG);
-	mdelay(1000);
-	printk("PDC202XX: %s channel reset.\n",
-		HWIF(drive)->channel ? "Secondary" : "Primary");
-}
-
-/*
- * Since SUN Cobalt is attempting to do this operation, I should disclose
- * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
- * HOTSWAP ATA Infrastructure.
- */
-static int pdc202xx_tristate (ide_drive_t * drive, int state)
-{
-#if 0
-	ide_hwif_t *hwif	= HWIF(drive);
-	unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
-	byte sc1f		= inb(high_16 + 0x001f);
-
-	if (!hwif)
-		return -EINVAL;
-
-//	hwif->bus_state = state;
-
-	if (state) {
-		outb(sc1f | 0x08, high_16 + 0x001f);
-	} else {
-		outb(sc1f & ~0x08, high_16 + 0x001f);
-	}
-#endif
-	return 0;
-}
-
-unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
-{
-	unsigned long high_16	= pci_resource_start(dev, 4);
-	byte udma_speed_flag	= IN_BYTE(high_16 + 0x001f);
-	byte primary_mode	= IN_BYTE(high_16 + 0x001a);
-	byte secondary_mode	= IN_BYTE(high_16 + 0x001b);
-
-	OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
-	mdelay(100);
-	OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
-	mdelay(2000);	/* 2 seconds ?! */
-
-	if (dev->resource[PCI_ROM_RESOURCE].start) {
-		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
-	}
-	
-	printk("%s: (U)DMA Burst Bit %sABLED " \
-		"Primary %s Mode " \
-		"Secondary %s Mode.\n",
-		name,
-		(udma_speed_flag & 1) ? "EN" : "DIS",
-		(primary_mode & 1) ? "MASTER" : "PCI",
-		(secondary_mode & 1) ? "MASTER" : "PCI" );
-
-#ifdef CONFIG_PDC202XX_BURST
-	if (!(udma_speed_flag & 1)) {
-		printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1));
-		OUT_BYTE(udma_speed_flag|1, high_16 + 0x001f);
-		printk("%sCTIVE\n", (IN_BYTE(high_16 + 0x001f) & 1) ? "A" : "INA");
-	}
-#endif /* CONFIG_PDC202XX_BURST */
-
-#ifdef CONFIG_PDC202XX_MASTER
-	if (!(primary_mode & 1)) {
-		printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ",
-			name, primary_mode, (primary_mode|1));
-		OUT_BYTE(primary_mode|1, high_16 + 0x001a);
-		printk("%s\n", (IN_BYTE(high_16 + 0x001a) & 1) ? "MASTER" : "PCI");
-	}
-
-	if (!(secondary_mode & 1)) {
-		printk("%s: FORCING SECONDARY MODE BIT 0x%02x -> 0x%02x ",
-			name, secondary_mode, (secondary_mode|1));
-		OUT_BYTE(secondary_mode|1, high_16 + 0x001b);
-		printk("%s\n", (IN_BYTE(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
-	}
-#endif /* CONFIG_PDC202XX_MASTER */
-
-#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!pdc202xx_proc) {
-		pdc202xx_proc = 1;
-		bmide_dev = dev;
-		pdc202xx_display_info = &pdc202xx_get_info;
-	}
-#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
-	return dev->irq;
-}
-
-unsigned int __init ata66_pdc202xx (ide_hwif_t *hwif)
-{
-	unsigned short mask = (hwif->channel) ? (1<<11) : (1<<10);
-	unsigned short CIS;
-
-        	switch(hwif->pci_dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20270:
-			OUT_BYTE(0x0b, (hwif->dma_base + 1));
-			return (!(IN_BYTE((hwif->dma_base + 3)) & 0x04));
-			/* check 80pin cable */
-		default:
-			pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
-			return (!(CIS & mask));
-			/* check 80pin cable */
-	}
-}
-
-void __init ide_init_pdc202xx (ide_hwif_t *hwif)
-{
-	hwif->tuneproc  = &pdc202xx_tune_drive;
-	hwif->quirkproc = &pdc202xx_quirkproc;
-	hwif->resetproc = &pdc202xx_reset;
-
-        switch(hwif->pci_dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20270:
-			hwif->speedproc = &pdc202xx_new_tune_chipset;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20265:
-		case PCI_DEVICE_ID_PROMISE_20262:
-			hwif->busproc   = &pdc202xx_tristate;
-		case PCI_DEVICE_ID_PROMISE_20246:
-			hwif->speedproc = &pdc202xx_tune_chipset;
-		default:
-			break;
-	}
-
-#undef CONFIG_PDC202XX_32_UNMASK
-#ifdef CONFIG_PDC202XX_32_UNMASK
-	hwif->drives[0].io_32bit = 1;
-	hwif->drives[1].io_32bit = 1;
-	hwif->drives[0].unmask = 1;
-	hwif->drives[1].unmask = 1;
-#endif /* CONFIG_PDC202XX_32_UNMASK */
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		hwif->dmaproc = &pdc202xx_dmaproc;
-		if (!noautodma)
-			hwif->autodma = 1;
-	} else {
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-		hwif->autodma = 0;
-	}
-#else /* !CONFIG_BLK_DEV_IDEDMA */
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pdc4030.c linux-2.4.21/drivers/ide/pdc4030.c
--- linux-2.4.20/drivers/ide/pdc4030.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/pdc4030.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,578 +0,0 @@
-/*  -*- linux-c -*-
- *  linux/drivers/ide/pdc4030.c		Version 0.90  May 27, 1999
- *
- *  Copyright (C) 1995-1999  Linus Torvalds & authors (see below)
- */
-
-/*
- *  Principal Author/Maintainer:  peterd@pnd-pc.demon.co.uk
- *
- *  This file provides support for the second port and cache of Promise
- *  IDE interfaces, e.g. DC4030VL, DC4030VL-1 and DC4030VL-2.
- *
- *  Thanks are due to Mark Lord for advice and patiently answering stupid
- *  questions, and all those mugs^H^H^H^Hbrave souls who've tested this,
- *  especially Andre Hedrick.
- *
- *  Version 0.01	Initial version, #include'd in ide.c rather than
- *                      compiled separately.
- *                      Reads use Promise commands, writes as before. Drives
- *                      on second channel are read-only.
- *  Version 0.02        Writes working on second channel, reads on both
- *                      channels. Writes fail under high load. Suspect
- *			transfers of >127 sectors don't work.
- *  Version 0.03        Brought into line with ide.c version 5.27.
- *                      Other minor changes.
- *  Version 0.04        Updated for ide.c version 5.30
- *                      Changed initialization strategy
- *  Version 0.05	Kernel integration.  -ml
- *  Version 0.06	Ooops. Add hwgroup to direct call of ide_intr() -ml
- *  Version 0.07	Added support for DC4030 variants
- *			Secondary interface autodetection
- *  Version 0.08	Renamed to pdc4030.c
- *  Version 0.09	Obsolete - never released - did manual write request
- *			splitting before max_sectors[major][minor] available.
- *  Version 0.10	Updated for 2.1 series of kernels
- *  Version 0.11	Updated for 2.3 series of kernels
- *			Autodetection code added.
- *
- *  Version 0.90	Transition to BETA code. No lost/unexpected interrupts
- */
-
-/*
- * Once you've compiled it in, you'll have to also enable the interface
- * setup routine from the kernel command line, as in 
- *
- *	'linux ide0=dc4030' or 'linux ide1=dc4030'
- *
- * It should now work as a second controller also ('ide1=dc4030') but only
- * if you DON'T have BIOS V4.44, which has a bug. If you have this version
- * and EPROM programming facilities, you need to fix 4 bytes:
- * 	2496:	81	81
- *	2497:	3E	3E
- *	2498:	22	98	*
- *	2499:	06	05	*
- *	249A:	F0	F0
- *	249B:	01	01
- *	...
- *	24A7:	81	81
- *	24A8:	3E	3E
- *	24A9:	22	98	*
- *	24AA:	06	05	*
- *	24AB:	70	70
- *	24AC:	01	01
- *
- * As of January 1999, Promise Technology Inc. have finally supplied me with
- * some technical information which has shed a glimmer of light on some of the
- * problems I was having, especially with writes. 
- *
- * There are still problems with the robustness and efficiency of this driver
- * because I still don't understand what the card is doing with interrupts.
- */
-
-#define DEBUG_READ
-#define DEBUG_WRITE
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "pdc4030.h"
-
-#ifdef CONFIG_IDE_TASKFILE_IO
-#  define __TASKFILE__IO
-#else /* CONFIG_IDE_TASKFILE_IO */
-#  undef __TASKFILE__IO
-#endif /* CONFIG_IDE_TASKFILE_IO */
-
-/*
- * promise_selectproc() is invoked by ide.c
- * in preparation for access to the specified drive.
- */
-static void promise_selectproc (ide_drive_t *drive)
-{
-	unsigned int number;
-
-	number = (HWIF(drive)->channel << 1) + drive->select.b.unit;
-	OUT_BYTE(number,IDE_FEATURE_REG);
-}
-
-/*
- * pdc4030_cmd handles the set of vendor specific commands that are initiated
- * by command F0. They all have the same success/failure notification -
- * 'P' (=0x50) on success, 'p' (=0x70) on failure.
- */
-int pdc4030_cmd(ide_drive_t *drive, byte cmd)
-{
-	unsigned long timeout, timer;
-	byte status_val;
-
-	promise_selectproc(drive);	/* redundant? */
-	OUT_BYTE(0xF3,IDE_SECTOR_REG);
-	OUT_BYTE(cmd,IDE_SELECT_REG);
-	OUT_BYTE(PROMISE_EXTENDED_COMMAND,IDE_COMMAND_REG);
-	timeout = HZ * 10;
-	timeout += jiffies;
-	do {
-		if(time_after(jiffies, timeout)) {
-			return 2; /* device timed out */
-		}
-		/* This is out of delay_10ms() */
-		/* Delays at least 10ms to give interface a chance */
-		timer = jiffies + (HZ + 99)/100 + 1;
-		while (time_after(timer, jiffies));
-		status_val = IN_BYTE(IDE_SECTOR_REG);
-	} while (status_val != 0x50 && status_val != 0x70);
-
-	if(status_val == 0x50)
-		return 0; /* device returned success */
-	else
-		return 1; /* device returned failure */
-}
-
-/*
- * pdc4030_identify sends a vendor-specific IDENTIFY command to the drive
- */
-int pdc4030_identify(ide_drive_t *drive)
-{
-	return pdc4030_cmd(drive, PROMISE_IDENTIFY);
-}
-
-int enable_promise_support = 0;
-
-void __init init_pdc4030 (void)
-{
-	enable_promise_support = 1;
-}
-
-/*
- * setup_pdc4030()
- * Completes the setup of a Promise DC4030 controller card, once found.
- */
-int __init setup_pdc4030 (ide_hwif_t *hwif)
-{
-        ide_drive_t *drive;
-	ide_hwif_t *hwif2;
-	struct dc_ident ident;
-	int i;
-	ide_startstop_t startstop;
-	
-	if (!hwif) return 0;
-
-	drive = &hwif->drives[0];
-	hwif2 = &ide_hwifs[hwif->index+1];
-	if (hwif->chipset == ide_pdc4030) /* we've already been found ! */
-		return 1;
-
-	if (IN_BYTE(IDE_NSECTOR_REG) == 0xFF || IN_BYTE(IDE_SECTOR_REG) == 0xFF) {
-		return 0;
-	}
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(0x08,IDE_CONTROL_REG);
-	if (pdc4030_cmd(drive,PROMISE_GET_CONFIG)) {
-		return 0;
-	}
-	if (ide_wait_stat(&startstop, drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) {
-		printk(KERN_INFO
-			"%s: Failed Promise read config!\n",hwif->name);
-		return 0;
-	}
-	ide_input_data(drive,&ident,SECTOR_WORDS);
-	if (ident.id[1] != 'P' || ident.id[0] != 'T') {
-		return 0;
-	}
-	printk(KERN_INFO "%s: Promise caching controller, ",hwif->name);
-	switch(ident.type) {
-		case 0x43:	printk("DC4030VL-2, "); break;
-		case 0x41:	printk("DC4030VL-1, "); break;
-		case 0x40:	printk("DC4030VL, "); break;
-		default:
-			printk("unknown - type 0x%02x - please report!\n"
-			       ,ident.type);
-			printk("Please e-mail the following data to "
-			       "promise@pnd-pc.demon.co.uk along with\n"
-			       "a description of your card and drives:\n");
-			for (i=0; i < 0x90; i++) {
-				printk("%02x ", ((unsigned char *)&ident)[i]);
-				if ((i & 0x0f) == 0x0f) printk("\n");
-			}
-			return 0;
-	}
-	printk("%dKB cache, ",(int)ident.cache_mem);
-	switch(ident.irq) {
-            case 0x00: hwif->irq = 14; break;
-            case 0x01: hwif->irq = 12; break;
-            default:   hwif->irq = 15; break;
-	}
-	printk("on IRQ %d\n",hwif->irq);
-
-	/*
-	 * Once found and identified, we set up the next hwif in the array
-	 * (hwif2 = ide_hwifs[hwif->index+1]) with the same io ports, irq
-	 * and other settings as the main hwif. This gives us two "mated"
-	 * hwifs pointing to the Promise card.
-	 *
-	 * We also have to shift the default values for the remaining
-	 * interfaces "up by one" to make room for the second interface on the
-	 * same set of values.
-	 */
-
-	hwif->chipset	= hwif2->chipset = ide_pdc4030;
-	hwif->mate	= hwif2;
-	hwif2->mate	= hwif;
-	hwif2->channel	= 1;
-	hwif->selectproc = hwif2->selectproc = &promise_selectproc;
-	hwif->serialized = hwif2->serialized = 1;
-
-/* Shift the remaining interfaces down by one */
-	for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) {
-		ide_hwif_t *h = &ide_hwifs[i];
-
-#ifdef DEBUG
-		printk(KERN_DEBUG "Shifting i/f %d values to i/f %d\n",i-1,i);
-#endif
-		ide_init_hwif_ports(&h->hw, (h-1)->io_ports[IDE_DATA_OFFSET], 0, NULL);
-		memcpy(h->io_ports, h->hw.io_ports, sizeof(h->io_ports));
-		h->noprobe = (h-1)->noprobe;
-	}
-	ide_init_hwif_ports(&hwif2->hw, hwif->io_ports[IDE_DATA_OFFSET], 0, NULL);
-	memcpy(hwif2->io_ports, hwif->hw.io_ports, sizeof(hwif2->io_ports));
-	hwif2->irq = hwif->irq;
-	hwif2->hw.irq = hwif->hw.irq = hwif->irq;
-	for (i=0; i<2 ; i++) {
-		hwif->drives[i].io_32bit = 3;
-		hwif2->drives[i].io_32bit = 3;
-		hwif->drives[i].keep_settings = 1;
-		hwif2->drives[i].keep_settings = 1;
-		if (!ident.current_tm[i].cyl)
-			hwif->drives[i].noprobe = 1;
-		if (!ident.current_tm[i+2].cyl)
-			hwif2->drives[i].noprobe = 1;
-	}
-        return 1;
-}
-
-/*
- * detect_pdc4030()
- * Tests for the presence of a DC4030 Promise card on this interface
- * Returns: 1 if found, 0 if not found
- */
-int __init detect_pdc4030(ide_hwif_t *hwif)
-{
-	ide_drive_t *drive = &hwif->drives[0];
-
-	if (IDE_DATA_REG == 0) { /* Skip test for non-existent interface */
-		return 0;
-	}
-	OUT_BYTE(0xF3, IDE_SECTOR_REG);
-	OUT_BYTE(0x14, IDE_SELECT_REG);
-	OUT_BYTE(PROMISE_EXTENDED_COMMAND, IDE_COMMAND_REG);
-	
-	ide_delay_50ms();
-
-	if (IN_BYTE(IDE_ERROR_REG) == 'P' &&
-	    IN_BYTE(IDE_NSECTOR_REG) == 'T' &&
-	    IN_BYTE(IDE_SECTOR_REG) == 'I') {
-		return 1;
-	} else {
-		return 0;
-	}
-}
-
-void __init ide_probe_for_pdc4030(void)
-{
-	unsigned int	index;
-	ide_hwif_t	*hwif;
-
-	if (enable_promise_support == 0)
-		return;
-	for (index = 0; index < MAX_HWIFS; index++) {
-		hwif = &ide_hwifs[index];
-		if (hwif->chipset == ide_unknown && detect_pdc4030(hwif)) {
-			setup_pdc4030(hwif);
-		}
-	}
-}
-
-/*
- * promise_read_intr() is the handler for disk read/multread interrupts
- */
-static ide_startstop_t promise_read_intr (ide_drive_t *drive)
-{
-	byte stat;
-	int total_remaining;
-	unsigned int sectors_left, sectors_avail, nsect;
-	struct request *rq;
-
-	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
-		return ide_error(drive, "promise_read_intr", stat);
-	}
-
-read_again:
-	do {
-		sectors_left = IN_BYTE(IDE_NSECTOR_REG);
-		IN_BYTE(IDE_SECTOR_REG);
-	} while (IN_BYTE(IDE_NSECTOR_REG) != sectors_left);
-	rq = HWGROUP(drive)->rq;
-	sectors_avail = rq->nr_sectors - sectors_left;
-	if (!sectors_avail)
-		goto read_again;
-
-read_next:
-	rq = HWGROUP(drive)->rq;
-	nsect = rq->current_nr_sectors;
-	if (nsect > sectors_avail)
-		nsect = sectors_avail;
-	sectors_avail -= nsect;
-	ide_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
-#ifdef DEBUG_READ
-	printk(KERN_DEBUG "%s:  promise_read: sectors(%ld-%ld), "
-	       "buf=0x%08lx, rem=%ld\n", drive->name, rq->sector,
-	       rq->sector+nsect-1, (unsigned long) rq->buffer,
-	       rq->nr_sectors-nsect);
-#endif
-	rq->sector += nsect;
-	rq->buffer += nsect<<9;
-	rq->errors = 0;
-	rq->nr_sectors -= nsect;
-	total_remaining = rq->nr_sectors;
-	if ((rq->current_nr_sectors -= nsect) <= 0) {
-		ide_end_request(1, HWGROUP(drive));
-	}
-/*
- * Now the data has been read in, do the following:
- * 
- * if there are still sectors left in the request, 
- *   if we know there are still sectors available from the interface,
- *     go back and read the next bit of the request.
- *   else if DRQ is asserted, there are more sectors available, so
- *     go back and find out how many, then read them in.
- *   else if BUSY is asserted, we are going to get an interrupt, so
- *     set the handler for the interrupt and just return
- */
-	if (total_remaining > 0) {
-		if (sectors_avail)
-			goto read_next;
-		stat = GET_STAT();
-		if (stat & DRQ_STAT)
-			goto read_again;
-		if (stat & BUSY_STAT) {
-			ide_set_handler (drive, &promise_read_intr, WAIT_CMD, NULL);
-#ifdef DEBUG_READ
-			printk(KERN_DEBUG "%s: promise_read: waiting for"
-			       "interrupt\n", drive->name);
-#endif
-			return ide_started;
-		}
-		printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left "
-		       "!DRQ !BUSY\n", drive->name);
-		return ide_error(drive, "promise read intr", stat);
-	}
-	return ide_stopped;
-}
-
-/*
- * promise_complete_pollfunc()
- * This is the polling function for waiting (nicely!) until drive stops
- * being busy. It is invoked at the end of a write, after the previous poll
- * has finished.
- *
- * Once not busy, the end request is called.
- */
-static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = hwgroup->rq;
-	int i;
-
-	if (GET_STAT() & BUSY_STAT) {
-		if (time_before(jiffies, hwgroup->poll_timeout)) {
-			ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
-			return ide_started; /* continue polling... */
-		}
-		hwgroup->poll_timeout = 0;
-		printk(KERN_ERR "%s: completion timeout - still busy!\n",
-		       drive->name);
-		return ide_error(drive, "busy timeout", GET_STAT());
-	}
-
-	hwgroup->poll_timeout = 0;
-#ifdef DEBUG_WRITE
-	printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name);
-#endif
-	for (i = rq->nr_sectors; i > 0; ) {
-		i -= rq->current_nr_sectors;
-		ide_end_request(1, hwgroup);
-	}
-	return ide_stopped;
-}
-
-/*
- * promise_write_pollfunc() is the handler for disk write completion polling.
- */
-static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-
-	if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
-		if (time_before(jiffies, hwgroup->poll_timeout)) {
-			ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
-			return ide_started; /* continue polling... */
-		}
-		hwgroup->poll_timeout = 0;
-		printk(KERN_ERR "%s: write timed-out!\n",drive->name);
-		return ide_error (drive, "write timeout", GET_STAT());
-	}
-
-	/*
-	 * Now write out last 4 sectors and poll for not BUSY
-	 */
-	ide_multwrite(drive, 4);
-	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-	ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
-#ifdef DEBUG_WRITE
-	printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
-		drive->name, GET_STAT());
-#endif
-	return ide_started;
-}
-
-/*
- * promise_write() transfers a block of one or more sectors of data to a
- * drive as part of a disk write operation. All but 4 sectors are transferred
- * in the first attempt, then the interface is polled (nicely!) for completion
- * before the final 4 sectors are transferred. There is no interrupt generated
- * on writes (at least on the DC4030VL-2), we just have to poll for NOT BUSY.
- */
-static ide_startstop_t promise_write (ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = &hwgroup->wrq;
-
-#ifdef DEBUG_WRITE
-	printk(KERN_DEBUG "%s: promise_write: sectors(%ld-%ld), "
-	       "buffer=%p\n", drive->name, rq->sector,
-	       rq->sector + rq->nr_sectors - 1, rq->buffer);
-#endif
-
-	/*
-	 * If there are more than 4 sectors to transfer, do n-4 then go into
-	 * the polling strategy as defined above.
-	 */
-	if (rq->nr_sectors > 4) {
-		if (ide_multwrite(drive, rq->nr_sectors - 4))
-			return ide_stopped;
-		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
-		return ide_started;
-	} else {
-	/*
-	 * There are 4 or fewer sectors to transfer, do them all in one go
-	 * and wait for NOT BUSY.
-	 */
-		if (ide_multwrite(drive, rq->nr_sectors))
-			return ide_stopped;
-		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
-#ifdef DEBUG_WRITE
-		printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
-			"status = %02x\n", drive->name, GET_STAT());
-#endif
-		return ide_started;
-	}
-}
-
-/*
- * do_pdc4030_io() is called from do_rw_disk, having had the block number
- * already set up. It issues a READ or WRITE command to the Promise
- * controller, assuming LBA has been used to set up the block number.
- */
-ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq)
-{
-	ide_startstop_t startstop;
-	unsigned long timeout;
-	byte stat;
-
-	switch(rq->cmd) {
-		case READ:
-#ifndef __TASKFILE__IO
-			OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG);
-#endif
-/*
- * The card's behaviour is odd at this point. If the data is
- * available, DRQ will be true, and no interrupt will be
- * generated by the card. If this is the case, we need to call the 
- * "interrupt" handler (promise_read_intr) directly. Otherwise, if
- * an interrupt is going to occur, bit0 of the SELECT register will
- * be high, so we can set the handler the just return and be interrupted.
- * If neither of these is the case, we wait for up to 50ms (badly I'm
- * afraid!) until one of them is.
- */
-			timeout = jiffies + HZ/20; /* 50ms wait */
-			do {
-				stat=GET_STAT();
-				if (stat & DRQ_STAT) {
-					udelay(1);
-					return promise_read_intr(drive);
-				}
-				if (IN_BYTE(IDE_SELECT_REG) & 0x01) {
-#ifdef DEBUG_READ
-	printk(KERN_DEBUG "%s: read: waiting for interrupt\n", drive->name);
-#endif
-					ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL);
-					return ide_started;
-				}
-				udelay(1);
-			} while (time_before(jiffies, timeout));
-
-			printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n", drive->name);
-			return ide_stopped;
-		case WRITE:
-#ifndef __TASKFILE__IO
-			OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
-#endif
-			if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
-				printk(KERN_ERR "%s: no DRQ after issuing PROMISE_WRITE\n", drive->name);
-				return startstop;
-		    	}
-			if (!drive->unmask)
-				__cli();	/* local CPU only */
-			HWGROUP(drive)->wrq = *rq; /* scratchpad */
-			return promise_write(drive);
-		default:
-			printk("KERN_WARNING %s: bad command: %d\n", drive->name, rq->cmd);
-			ide_end_request(0, HWGROUP(drive));
-			return ide_stopped;
-	}
-}
-
-#ifdef __TASKFILE__IO
-
-ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
-{
-	struct hd_drive_task_hdr taskfile;
-
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-
-	taskfile.sector_count	= rq->nr_sectors;
-	taskfile.sector_number	= block;
-	taskfile.low_cylinder	= (block>>=8);
-	taskfile.high_cylinder	= (block>>=8);
-	taskfile.device_head	= ((block>>8)&0x0f)|drive->select.all;
-	taskfile.command	= (rq->cmd==READ)?PROMISE_READ:PROMISE_WRITE;
-
-	do_taskfile(drive, &taskfile, NULL, NULL);
-	return do_pdc4030_io(drive, rq);
-}
-#endif
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pdc4030.h linux-2.4.21/drivers/ide/pdc4030.h
--- linux-2.4.20/drivers/ide/pdc4030.h	2001-07-18 01:53:55.000000000 +0000
+++ linux-2.4.21/drivers/ide/pdc4030.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,44 +0,0 @@
-/*
- *  linux/drivers/ide/pdc4030.h
- *
- *  Copyright (C) 1995-1998  Linus Torvalds & authors
- */
-
-/*
- * Principal author: Peter Denison <peterd@pnd-pc.demon.co.uk>
- */
-
-#ifndef IDE_PROMISE_H
-#define IDE_PROMISE_H
-
-#define	PROMISE_EXTENDED_COMMAND	0xF0
-#define	PROMISE_READ			0xF2
-#define	PROMISE_WRITE			0xF3
-/* Extended commands - main command code = 0xf0 */
-#define	PROMISE_GET_CONFIG		0x10
-#define	PROMISE_IDENTIFY		0x20
-
-struct translation_mode {
-	u16	cyl;
-	u8	head;
-	u8	sect;
-};
-
-struct dc_ident {
-	u8	type;
-	u8	unknown1;
-	u8	hw_revision;
-	u8	firmware_major;
-	u8	firmware_minor;
-	u8	bios_address;
-	u8	irq;
-	u8	unknown2;
-	u16	cache_mem;
-	u16	unknown3;
-	u8	id[2];
-	u16	info;
-	struct translation_mode current_tm[4];
-	u8	pad[SECTOR_WORDS*4 - 32];
-};
-
-#endif /* IDE_PROMISE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pdcraid.c linux-2.4.21/drivers/ide/pdcraid.c
--- linux-2.4.20/drivers/ide/pdcraid.c	2001-11-13 17:19:41.000000000 +0000
+++ linux-2.4.21/drivers/ide/pdcraid.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,646 +0,0 @@
-/*
-   pdcraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
-
-   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, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-   
-   Authors: 	Arjan van de Ven <arjanv@redhat.com>
-   		
-   Based on work done by Søren Schmidt for FreeBSD  
-
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/ioctl.h>
-
-#include <linux/ide.h>
-#include <asm/uaccess.h>
-
-#include "ataraid.h"
-
-static int pdcraid_open(struct inode * inode, struct file * filp);
-static int pdcraid_release(struct inode * inode, struct file * filp);
-static int pdcraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int pdcraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
-static int pdcraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
-
-struct disk_dev {
-	int major;
-	int minor;
-	int device;
-};
-
-static struct disk_dev devlist[]= {
-	{IDE0_MAJOR,  0,  -1 },
-	{IDE0_MAJOR, 64,  -1 },
-	{IDE1_MAJOR,  0,  -1 },
-	{IDE1_MAJOR, 64,  -1 },
-	{IDE2_MAJOR,  0,  -1 },
-	{IDE2_MAJOR, 64,  -1 },
-	{IDE3_MAJOR,  0,  -1 },
-	{IDE3_MAJOR, 64,  -1 },
-	{IDE4_MAJOR,  0,  -1 },
-	{IDE4_MAJOR, 64,  -1 },
-	{IDE5_MAJOR,  0,  -1 },
-	{IDE5_MAJOR, 64,  -1 },
-	{IDE6_MAJOR,  0,  -1 },
-	{IDE6_MAJOR, 64,  -1 },
-};
-
-
-struct pdcdisk {
-	kdev_t	device;
-	unsigned long sectors;
-	struct block_device *bdev;
-	unsigned long last_pos;
-};
-
-struct pdcraid {
-	unsigned int stride;
-	unsigned int disks;
-	unsigned long sectors;
-	struct geom geom;
-	
-	struct pdcdisk disk[8];
-	
-	unsigned long cutoff[8];
-	unsigned int cutoff_disks[8];
-};
-
-static struct raid_device_operations pdcraid0_ops = {
-        open:                   pdcraid_open,
-	release:                pdcraid_release,
-	ioctl:			pdcraid_ioctl,
-	make_request:		pdcraid0_make_request
-};
-
-static struct raid_device_operations pdcraid1_ops = {
-        open:                   pdcraid_open,
-	release:                pdcraid_release,
-	ioctl:			pdcraid_ioctl,
-	make_request:		pdcraid1_make_request
-};
-
-static struct pdcraid raid[16];
-
-
-static int pdcraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	unsigned int minor;
-   	unsigned long sectors;
-
-	if (!inode || !inode->i_rdev) 
-		return -EINVAL;
-
-	minor = MINOR(inode->i_rdev)>>SHIFT;
-	
-	switch (cmd) {
-
-         	case BLKGETSIZE:   /* Return device size */
- 			if (!arg)  return -EINVAL;
-			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
-			if (MINOR(inode->i_rdev)&15)
-				return put_user(sectors, (unsigned long *) arg);
-			return put_user(raid[minor].sectors , (unsigned long *) arg);
-			break;
-			
-
-		case HDIO_GETGEO:
-		{
-			struct hd_geometry *loc = (struct hd_geometry *) arg;
-			unsigned short bios_cyl = raid[minor].geom.cylinders; /* truncate */
-			
-			if (!loc) return -EINVAL;
-			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
-			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
-				(unsigned long *) &loc->start)) return -EFAULT;
-			return 0;
-		}
-
-		case HDIO_GETGEO_BIG:
-		{
-			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
-			if (!loc) return -EINVAL;
-			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
-			if (put_user(raid[minor].geom.cylinders, (unsigned int *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
-				(unsigned long *) &loc->start)) return -EFAULT;
-			return 0;
-		}
-
-			
-		case BLKROSET:
-		case BLKROGET:
-		case BLKSSZGET:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
-
-		default:
-			printk("Invalid ioctl \n");
-			return -EINVAL;
-	};
-
-	return 0;
-}
-
-
-unsigned long partition_map_normal(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
-{
-	return block + partition_off;
-}
-
-unsigned long partition_map_linux(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
-{
-	unsigned long newblock;
-	
-	newblock = stride - (partition_off%stride); if (newblock == stride) newblock = 0;
-	newblock += block;
-	newblock = newblock % partition_size;
-	newblock += partition_off;
-	
-	return newblock;
-}
-
-static int funky_remap[8] = { 0, 1,  2, 3, 4, 5, 6, 7 };
-
-unsigned long partition_map_linux_raid0_4disk(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
-{
-	unsigned long newblock,temp,temp2;
-	
-	newblock = stride - (partition_off%stride); if (newblock == stride) newblock = 0;
-
-	if (block < (partition_size / (8*stride))*8*stride ) {
-		temp = block % stride;
-		temp2 = block / stride;
-		temp2 = ((temp2>>3)<<3)|(funky_remap[temp2&7]);
-		block = temp2*stride+temp;
-	}
-
-	
-	newblock += block;
-	newblock = newblock % partition_size;
-	newblock += partition_off;
-	
-	return newblock;
-}
-
-
-
-static int pdcraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	unsigned long rsect;
-	unsigned long rsect_left,rsect_accum = 0;
-	unsigned long block;
-	unsigned int disk=0,real_disk=0;
-	int i;
-	int device;
-	struct pdcraid *thisraid;
-
-	rsect = bh->b_rsector;
-	
-	/* Ok. We need to modify this sector number to a new disk + new sector number. 
-	 * If there are disks of different sizes, this gets tricky. 
-	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
-	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
-	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
-	 * and the last 1Gb is disk 3 only.
-	 *
-	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
-	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
-	 * point, we have to divide by one less.
-	 */
-	
-	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
-	thisraid = &raid[device];
-	if (thisraid->stride==0)
-		thisraid->stride=1;
-
-	/* Partitions need adding of the start sector of the partition to the requested sector */
-	
-	rsect = partition_map_normal(rsect, ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect, ataraid_gendisk.part[MINOR(bh->b_rdev)].nr_sects, thisraid->stride);
-
-	/* Woops we need to split the request to avoid crossing a stride barrier */
-	if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
-		return -1;  
-	}
-	
-	rsect_left = rsect;
-	
-	for (i=0;i<8;i++) {
-		if (thisraid->cutoff_disks[i]==0)
-			break;
-		if (rsect > thisraid->cutoff[i]) {
-			/* we're in the wrong area so far */
-			rsect_left -= thisraid->cutoff[i];
-			rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
-		} else {
-			block = rsect_left / thisraid->stride;
-			disk = block % thisraid->cutoff_disks[i];
-			block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
-			rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
-			break;
-		}
-	}
-	
-	for (i=0;i<8;i++) {
-		if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
-			real_disk = i;
-			break;
-		}
-		if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
-			disk--;
-		}
-		
-	}
-	disk = real_disk;
-		
-	
-	/*
-	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
-	 * is the only IO operation happening on this bh.
-	 */
-	bh->b_rdev = thisraid->disk[disk].device;
-	bh->b_rsector = rsect;
-
-	/*
-	 * Let the main block layer submit the IO and resolve recursion:
-	 */
-	return 1;
-}
-
-static int pdcraid1_write_request(request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	struct buffer_head *bh1;
-	struct ataraid_bh_private *private;
-	int device;
-	int i;
-
-	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
-	private = ataraid_get_private();
-	if (private==NULL)
-		BUG();
-
-	private->parent = bh;
-	
-	atomic_set(&private->count,raid[device].disks);
-
-
-	for (i = 0; i< raid[device].disks; i++) { 
-		bh1=ataraid_get_bhead();
-		/* If this ever fails we're doomed */
-		if (!bh1)
-			BUG();
-	
-		/* dupe the bufferhead and update the parts that need to be different */
-		memcpy(bh1, bh, sizeof(*bh));
-		
-		bh1->b_end_io = ataraid_end_request;
-		bh1->b_private = private;
-		bh1->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect; /* partition offset */
-		bh1->b_rdev = raid[device].disk[i].device;
-
-		/* update the last known head position for the drive */
-		raid[device].disk[i].last_pos = bh1->b_rsector+(bh1->b_size>>9);
-
-		generic_make_request(rw,bh1);
-	}
-	return 0;
-}
-
-static int pdcraid1_read_request (request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	int device;
-	int dist;
-	int bestsofar,bestdist,i;
-	static int previous;
-
-	/* Reads are simple in principle. Pick a disk and go. 
-	   Initially I cheat by just picking the one which the last known
-	   head position is closest by.
-	   Later on, online/offline checking and performance needs adding */
-	
-	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
-	bh->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
-
-	bestsofar = 0; 
-	bestdist = raid[device].disk[0].last_pos - bh->b_rsector;
-	if (bestdist<0) 
-		bestdist=-bestdist;
-	if (bestdist>4095)
-		bestdist=4095;
-
-	for (i=1 ; i<raid[device].disks; i++) {
-		dist = raid[device].disk[i].last_pos - bh->b_rsector;
-		if (dist<0) 
-			dist = -dist;
-		if (dist>4095)
-			dist=4095;
-		
-		if (bestdist==dist) {  /* it's a tie; try to do some read balancing */
-			if ((previous>bestsofar)&&(previous<=i))  
-				bestsofar = i;
-			previous = (previous + 1) % raid[device].disks;
-		} else if (bestdist>dist) {
-			bestdist = dist;
-			bestsofar = i;
-		}
-	
-	}
-	
-	bh->b_rdev = raid[device].disk[bestsofar].device; 
-	raid[device].disk[bestsofar].last_pos = bh->b_rsector+(bh->b_size>>9);
-
-	/*
-	 * Let the main block layer submit the IO and resolve recursion:
-	 */
-                          	
-	return 1;
-}
-
-
-static int pdcraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	/* Read and Write are totally different cases; split them totally here */
-	if (rw==READA)
-		rw = READ;
-	
-	if (rw==READ)
-		return pdcraid1_read_request(q,rw,bh);
-	else
-		return pdcraid1_write_request(q,rw,bh);
-}
-
-#include "pdcraid.h"
-
-static unsigned long calc_pdcblock_offset (int major,int minor)
-{
-	unsigned long lba = 0;
-	kdev_t dev;
-	ide_drive_t *ideinfo;
-	
-	dev = MKDEV(major,minor);
-	ideinfo = get_info_ptr (dev);
-	if (ideinfo==NULL)
-		return 0;
-	
-	
-	/* first sector of the last cluster */
-	if (ideinfo->head==0) 
-		return 0;
-	if (ideinfo->sect==0)
-		return 0;
-	lba = (ideinfo->capacity / (ideinfo->head*ideinfo->sect));
-	lba = lba * (ideinfo->head*ideinfo->sect);
-	lba = lba - ideinfo->sect;
-
-	return lba;
-}
-
-
-static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
-{
-	int ret = -EINVAL;
-	struct buffer_head *bh = NULL;
-	kdev_t dev = MKDEV(major,minor);
-	unsigned long sb_offset;
-
-	if (blksize_size[major]==NULL)   /* device doesn't exist */
-		return -EINVAL;
-                       
-	
-	/*
-	 * Calculate the position of the superblock,
-	 * it's at first sector of the last cylinder
-	 */
-	sb_offset = calc_pdcblock_offset(major,minor)/8;
-	/* The /8 transforms sectors into 4Kb blocks */
-
-	if (sb_offset==0)
-		return -1;	
-	
-	set_blocksize (dev, 4096);
-
-	bh = bread (dev, sb_offset, 4096);
-	
-	if (bh) {
-		memcpy (buffer, bh->b_data, bufsize);
-	} else {
-		printk(KERN_ERR "pdcraid: Error reading superblock.\n");
-		goto abort;
-	}
-	ret = 0;
-abort:
-	if (bh)
-		brelse (bh);
-	return ret;
-}
-
-static unsigned int calc_sb_csum (unsigned int* ptr)
-{	
-	unsigned int sum;
-	int count;
-	
-	sum = 0;
-	for (count=0;count<511;count++)
-		sum += *ptr++;
-	
-	return sum;
-}
-
-static int cookie = 0;
-
-static void __init probedisk(int devindex,int device, int raidlevel)
-{
-	int i;
-	int major, minor;
-        struct promise_raid_conf *prom;
-	static unsigned char block[4096];
-	struct block_device *bdev;
-
-	if (devlist[devindex].device!=-1) /* already assigned to another array */
-		return;
-	
-	major = devlist[devindex].major;
-	minor = devlist[devindex].minor; 
-
-        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
-        	return;
-                                                                                                                 
-        prom = (struct promise_raid_conf*)&block[512];
-
-        /* the checksums must match */
-	if (prom->checksum != calc_sb_csum((unsigned int*)prom))
-		return;
-	if (prom->raid.type!=raidlevel) /* different raidlevel */
-		return;
-
-	if ((cookie!=0) && (cookie != prom->raid.magic_1)) /* different array */
-		return;
-	
-	cookie = prom->raid.magic_1;
-
-	/* This looks evil. But basically, we have to search for our adapternumber
-	   in the arraydefinition, both of which are in the superblock */	
-        for (i=0;(i<prom->raid.total_disks)&&(i<8);i++) {
-        	if ( (prom->raid.disk[i].channel== prom->raid.channel) &&
-        	     (prom->raid.disk[i].device == prom->raid.device) ) {
-
-        	        bdev = bdget(MKDEV(major,minor));
-        	        if (bdev && blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW) == 0) {
-				raid[device].disk[i].bdev = bdev;
-			}
-			raid[device].disk[i].device = MKDEV(major,minor);
-			raid[device].disk[i].sectors = prom->raid.disk_secs;
-			raid[device].stride = (1<<prom->raid.raid0_shift);
-			raid[device].disks = prom->raid.total_disks;
-			raid[device].sectors = prom->raid.total_secs;
-			raid[device].geom.heads = prom->raid.heads+1;
-			raid[device].geom.sectors = prom->raid.sectors;
-			raid[device].geom.cylinders = prom->raid.cylinders+1;
-			devlist[devindex].device=device;
-        	     }
-        }
-	               
-}
-
-static void __init fill_cutoff(int device)
-{
-	int i,j;
-	unsigned long smallest;
-	unsigned long bar;
-	int count;
-	
-	bar = 0;
-	for (i=0;i<8;i++) {
-		smallest = ~0;
-		for (j=0;j<8;j++) 
-			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
-				smallest = raid[device].disk[j].sectors;
-		count = 0;
-		for (j=0;j<8;j++) 
-			if (raid[device].disk[j].sectors >= smallest)
-				count++;
-				
-		smallest = smallest * count;
-		bar = smallest;
-		raid[device].cutoff[i] = smallest;
-		raid[device].cutoff_disks[i] = count;
-	}
-}
-			   
-static __init int pdcraid_init_one(int device,int raidlevel)
-{
-	int i, count;
-
-	for (i=0; i<14; i++)
-		probedisk(i, device, raidlevel);
-	
-	if (raidlevel==0)
-		fill_cutoff(device);
-	
-	/* Initialize the gendisk structure */
-	
-	ataraid_register_disk(device,raid[device].sectors);        
-		
-	count=0;
-	
-	for (i=0;i<8;i++) {
-		if (raid[device].disk[i].device!=0) {
-			printk(KERN_INFO "Drive %i is %li Mb (%i / %i) \n",
-				i,raid[device].disk[i].sectors/2048,MAJOR(raid[device].disk[i].device),MINOR(raid[device].disk[i].device));
-			count++;
-		}
-	}
-	if (count) {
-		printk(KERN_INFO "Raid%i array consists of %i drives. \n",raidlevel,count);
-		return 0;
-	} else {
-		return -ENODEV;
-	}
-}
-
-static __init int pdcraid_init(void)
-{
-	int retval, device, count = 0;
-
-	do {
-		cookie = 0;
-		device=ataraid_get_device(&pdcraid0_ops);
-		if (device<0)
-			break;
-		retval = pdcraid_init_one(device,0);
-		if (retval) {
-			ataraid_release_device(device);
-			break;
-		} else {
-			count++;
-		}
-	} while (1);
-
-	do {
-	
-		cookie = 0;
-		device=ataraid_get_device(&pdcraid1_ops);
-		if (device<0)
-			break;
-		retval = pdcraid_init_one(device,1);
-		if (retval) {
-			ataraid_release_device(device);
-			break;
-		} else {
-			count++;
-		}
-	} while (1);
-
-	if (count) {
-		printk(KERN_INFO "Promise Fasttrak(tm) Softwareraid driver for linux version 0.03beta\n");
-		return 0;
-	}
-	printk(KERN_DEBUG "Promise Fasttrak(tm) Softwareraid driver 0.03beta: No raid array found\n");
-	return -ENODEV;
-}
-
-static void __exit pdcraid_exit (void)
-{
-	int i,device;
-	for (device = 0; device<16; device++) {
-		for (i=0;i<8;i++) {
-			struct block_device *bdev = raid[device].disk[i].bdev;
-			raid[device].disk[i].bdev = NULL;
-			if (bdev)
-				blkdev_put(bdev, BDEV_RAW);
-		}	
-		if (raid[device].sectors)
-			ataraid_release_device(device);
-	}
-}
-
-static int pdcraid_open(struct inode * inode, struct file * filp) 
-{
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-static int pdcraid_release(struct inode * inode, struct file * filp)
-{	
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-module_init(pdcraid_init);
-module_exit(pdcraid_exit);
-MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pdcraid.h linux-2.4.21/drivers/ide/pdcraid.h
--- linux-2.4.20/drivers/ide/pdcraid.h	2001-09-18 06:23:40.000000000 +0000
+++ linux-2.4.21/drivers/ide/pdcraid.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,47 +0,0 @@
-struct promise_raid_conf {
-    char                promise_id[24];
-
-    u32             dummy_0;
-    u32             magic_0;
-    u32             dummy_1;
-    u32             magic_1;
-    u16             dummy_2;
-    u8              filler1[470];
-    struct {
-        u32 flags;                          /* 0x200 */
-        u8          dummy_0;
-        u8          disk_number;
-        u8          channel;
-        u8          device;
-        u32         magic_0;
-        u32         dummy_1;
-        u32         dummy_2;                /* 0x210 */
-        u32         disk_secs;
-        u32         dummy_3;
-        u16         dummy_4;
-        u8          status;
-        u8          type;
-        u8        total_disks;            /* 0x220 */
-        u8        raid0_shift;
-        u8        raid0_disks;
-        u8        array_number;
-        u32       total_secs;
-        u16       cylinders;
-        u8        heads;
-        u8        sectors;
-        u32         magic_1;
-        u32         dummy_5;                /* 0x230 */
-        struct {
-            u16     dummy_0;
-            u8      channel;
-            u8      device;
-            u32     magic_0;
-            u32     disk_number;
-        } disk[8];
-    } raid;
-    u32             filler2[346];
-    u32            checksum;
-};
-
-#define PR_MAGIC        "Promise Technology, Inc."
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/piix.c linux-2.4.21/drivers/ide/piix.c
--- linux-2.4.20/drivers/ide/piix.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/piix.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,542 +0,0 @@
-/*
- *  linux/drivers/ide/piix.c		Version 0.32	June 9, 2000
- *
- *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
- *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
- *  May be copied or modified under the terms of the GNU General Public License
- *
- *  PIO mode setting function for Intel chipsets.  
- *  For use instead of BIOS settings.
- *
- * 40-41
- * 42-43
- * 
- *                 41
- *                 43
- *
- * | PIO 0       | c0 | 80 | 0 | 	piix_tune_drive(drive, 0);
- * | PIO 2 | SW2 | d0 | 90 | 4 | 	piix_tune_drive(drive, 2);
- * | PIO 3 | MW1 | e1 | a1 | 9 | 	piix_tune_drive(drive, 3);
- * | PIO 4 | MW2 | e3 | a3 | b | 	piix_tune_drive(drive, 4);
- * 
- * sitre = word40 & 0x4000; primary
- * sitre = word42 & 0x4000; secondary
- *
- * 44 8421|8421    hdd|hdb
- * 
- * 48 8421         hdd|hdc|hdb|hda udma enabled
- *
- *    0001         hda
- *    0010         hdb
- *    0100         hdc
- *    1000         hdd
- *
- * 4a 84|21        hdb|hda
- * 4b 84|21        hdd|hdc
- *
- *    ata-33/82371AB
- *    ata-33/82371EB
- *    ata-33/82801AB            ata-66/82801AA
- *    00|00 udma 0              00|00 reserved
- *    01|01 udma 1              01|01 udma 3
- *    10|10 udma 2              10|10 udma 4
- *    11|11 reserved            11|11 reserved
- *
- * 54 8421|8421    ata66 drive|ata66 enable
- *
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &reg40);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, &reg42);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, &reg44);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, &reg48);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, &reg4a);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, &reg54);
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#define PIIX_DEBUG_DRIVE_INFO		0
-
-#define DISPLAY_PIIX_TIMINGS
-
-#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int piix_get_info(char *, char **, off_t, int);
-extern int (*piix_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-
-static int piix_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-        u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
-	u8  c0 = 0, c1 = 0;
-	u8  reg44 = 0, reg48 = 0, reg4a = 0, reg4b = 0, reg54 = 0, reg55 = 0;
-
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_INTEL_82801BA_8:
-		case PCI_DEVICE_ID_INTEL_82801BA_9:
-	        case PCI_DEVICE_ID_INTEL_82801CA_10:
-	        case PCI_DEVICE_ID_INTEL_82801CA_11:
-	        case PCI_DEVICE_ID_INTEL_82801DB_11:
-	        case PCI_DEVICE_ID_INTEL_82801E_11:
-			p += sprintf(p, "\n                                Intel PIIX4 Ultra 100 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_INTEL_82372FB_1:
-		case PCI_DEVICE_ID_INTEL_82801AA_1:
-			p += sprintf(p, "\n                                Intel PIIX4 Ultra 66 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_INTEL_82451NX:
-		case PCI_DEVICE_ID_INTEL_82801AB_1:
-		case PCI_DEVICE_ID_INTEL_82443MX_1:
-		case PCI_DEVICE_ID_INTEL_82371AB:
-			p += sprintf(p, "\n                                Intel PIIX4 Ultra 33 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_INTEL_82371SB_1:
-			p += sprintf(p, "\n                                Intel PIIX3 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_INTEL_82371MX:
-			p += sprintf(p, "\n                                Intel MPIIX Chipset.\n");
-			return p-buffer;	/* => must be less than 4k! */
-		case PCI_DEVICE_ID_INTEL_82371FB_1:
-		case PCI_DEVICE_ID_INTEL_82371FB_0:
-		default:
-			p += sprintf(p, "\n                                Intel PIIX Chipset.\n");
-			break;
-	}
-
-	pci_read_config_word(bmide_dev, 0x40, &reg40);
-	pci_read_config_word(bmide_dev, 0x42, &reg42);
-	pci_read_config_byte(bmide_dev, 0x44, &reg44);
-	pci_read_config_byte(bmide_dev, 0x48, &reg48);
-	pci_read_config_byte(bmide_dev, 0x4a, &reg4a);
-	pci_read_config_byte(bmide_dev, 0x4b, &reg4b);
-	pci_read_config_byte(bmide_dev, 0x54, &reg54);
-	pci_read_config_byte(bmide_dev, 0x55, &reg55);
-
-	psitre = (reg40 & 0x4000) ? 1 : 0;
-	ssitre = (reg42 & 0x4000) ? 1 : 0;
-
-	/*
-	 * at that point bibma+0x2 et bibma+0xa are byte registers
-	 * to investigate:
-	 */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %sabled                         %sabled\n",
-			(c0&0x80) ? "dis" : " en",
-			(c1&0x80) ? "dis" : " en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	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 " );
-	p += sprintf(p, "UDMA enabled:   %s              %s             %s               %s\n",
-			(reg48&0x01) ? "yes" : "no ",
-			(reg48&0x02) ? "yes" : "no ",
-			(reg48&0x04) ? "yes" : "no ",
-			(reg48&0x08) ? "yes" : "no " );
-	p += sprintf(p, "UDMA enabled:   %s                %s               %s                 %s\n",
-			((reg54&0x11) && (reg55&0x10) && (reg4a&0x01)) ? "5" :
-			((reg54&0x11) && (reg4a&0x02)) ? "4" :
-			((reg54&0x11) && (reg4a&0x01)) ? "3" :
-			(reg4a&0x02) ? "2" :
-			(reg4a&0x01) ? "1" :
-			(reg4a&0x00) ? "0" : "X",
-			((reg54&0x22) && (reg55&0x20) && (reg4a&0x10)) ? "5" :
-			((reg54&0x22) && (reg4a&0x20)) ? "4" :
-			((reg54&0x22) && (reg4a&0x10)) ? "3" :
-			(reg4a&0x20) ? "2" :
-			(reg4a&0x10) ? "1" :
-			(reg4a&0x00) ? "0" : "X",
-			((reg54&0x44) && (reg55&0x40) && (reg4b&0x03)) ? "5" :
-			((reg54&0x44) && (reg4b&0x02)) ? "4" :
-			((reg54&0x44) && (reg4b&0x01)) ? "3" :
-			(reg4b&0x02) ? "2" :
-			(reg4b&0x01) ? "1" :
-			(reg4b&0x00) ? "0" : "X",
-			((reg54&0x88) && (reg55&0x80) && (reg4b&0x30)) ? "5" :
-			((reg54&0x88) && (reg4b&0x20)) ? "4" :
-			((reg54&0x88) && (reg4b&0x10)) ? "3" :
-			(reg4b&0x20) ? "2" :
-			(reg4b&0x10) ? "1" :
-			(reg4b&0x00) ? "0" : "X");
-
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "DMA\n");
-	p += sprintf(p, "PIO\n");
-
-/*
- *	FIXME.... Add configuration junk data....blah blah......
- */
-
-	return p-buffer;	 /* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-/*
- *  Used to set Fifo configuration via kernel command line:
- */
-
-byte piix_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_PIIX_TUNING)
-/*
- *
- */
-static byte piix_dma_2_pio (byte xfer_rate) {
-	switch(xfer_rate) {
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-		case XFER_MW_DMA_2:
-		case XFER_PIO_4:
-			return 4;
-		case XFER_MW_DMA_1:
-		case XFER_PIO_3:
-			return 3;
-		case XFER_SW_DMA_2:
-		case XFER_PIO_2:
-			return 2;
-		case XFER_MW_DMA_0:
-		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-		case XFER_PIO_SLOW:
-		default:
-			return 0;
-	}
-}
-#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_PIIX_TUNING) */
-
-/*
- *  Based on settings done by AMI BIOS
- *  (might be useful if drive is not registered in CMOS for any reason).
- */
-static void piix_tune_drive (ide_drive_t *drive, byte pio)
-{
-	unsigned long flags;
-	u16 master_data;
-	byte slave_data;
-	int is_slave		= (&HWIF(drive)->drives[1] == drive);
-	int master_port		= HWIF(drive)->index ? 0x42 : 0x40;
-	int slave_port		= 0x44;
-				 /* ISP  RTC */
-	byte timings[][2]	= { { 0, 0 },
-				    { 0, 0 },
-				    { 1, 0 },
-				    { 2, 1 },
-				    { 2, 3 }, };
-
-	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
-	pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data);
-	if (is_slave) {
-		master_data = master_data | 0x4000;
-		if (pio > 1)
-			/* enable PPE, IE and TIME */
-			master_data = master_data | 0x0070;
-		pci_read_config_byte(HWIF(drive)->pci_dev, slave_port, &slave_data);
-		slave_data = slave_data & (HWIF(drive)->index ? 0x0f : 0xf0);
-		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1])
-					   << (HWIF(drive)->index ? 4 : 0));
-	} else {
-		master_data = master_data & 0xccf8;
-		if (pio > 1)
-			/* enable PPE, IE and TIME */
-			master_data = master_data | 0x0007;
-		master_data = master_data | (timings[pio][0] << 12) |
-			      (timings[pio][1] << 8);
-	}
-	save_flags(flags);
-	cli();
-	pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data);
-	if (is_slave)
-		pci_write_config_byte(HWIF(drive)->pci_dev, slave_port, slave_data);
-	restore_flags(flags);
-}
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_PIIX_TUNING)
-static int piix_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte maslave		= hwif->channel ? 0x42 : 0x40;
-	int a_speed		= 3 << (drive->dn * 4);
-	int u_flag		= 1 << drive->dn;
-	int v_flag		= 0x01 << drive->dn;
-	int w_flag		= 0x10 << drive->dn;
-	int u_speed		= 0;
-	int err			= 0;
-	int			sitre;
-	short			reg4042, reg44, reg48, reg4a, reg54;
-	byte			reg55;
-
-	pci_read_config_word(dev, maslave, &reg4042);
-	sitre = (reg4042 & 0x4000) ? 1 : 0;
-	pci_read_config_word(dev, 0x44, &reg44);
-	pci_read_config_word(dev, 0x48, &reg48);
-	pci_read_config_word(dev, 0x4a, &reg4a);
-	pci_read_config_word(dev, 0x54, &reg54);
-	pci_read_config_byte(dev, 0x55, &reg55);
-
-	switch(speed) {
-		case XFER_UDMA_4:
-		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
-		case XFER_UDMA_5:
-		case XFER_UDMA_3:
-		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
-		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_SW_DMA_2:	break;
-		default:		return -1;
-	}
-
-	if (speed >= XFER_UDMA_0) {
-		if (!(reg48 & u_flag))
-			pci_write_config_word(dev, 0x48, reg48|u_flag);
-		if (speed == XFER_UDMA_5) {
-			pci_write_config_byte(dev, 0x55, (byte) reg55|w_flag);
-		} else {
-			pci_write_config_byte(dev, 0x55, (byte) reg55 & ~w_flag);
-		}
-		if (!(reg4a & u_speed)) {
-			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-			pci_write_config_word(dev, 0x4a, reg4a|u_speed);
-		}
-		if (speed > XFER_UDMA_2) {
-			if (!(reg54 & v_flag)) {
-				pci_write_config_word(dev, 0x54, reg54|v_flag);
-			}
-		} else {
-			pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
-		}
-	}
-	if (speed < XFER_UDMA_0) {
-		if (reg48 & u_flag)
-			pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
-		if (reg4a & a_speed)
-			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-		if (reg54 & v_flag)
-			pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
-		if (reg55 & w_flag)
-			pci_write_config_byte(dev, 0x55, (byte) reg55 & ~w_flag);
-	}
-
-	piix_tune_drive(drive, piix_dma_2_pio(speed));
-
-#if PIIX_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* PIIX_DEBUG_DRIVE_INFO */
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return err;
-}
-
-static int piix_config_drive_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte			speed;
-
-	byte udma_66		= eighty_ninty_three(drive);
-	int ultra100		= ((dev->device == PCI_DEVICE_ID_INTEL_82801BA_8) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801BA_9) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801CA_10) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801CA_11) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801DB_11) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801E_11)) ? 1 : 0;
-	int ultra66		= ((ultra100) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82372FB_1)) ? 1 : 0;
-	int ultra		= ((ultra66) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82371AB) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82443MX_1) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82451NX) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801AB_1)) ? 1 : 0;
-
-	if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) {
-		speed = XFER_UDMA_5;
-	} else if ((id->dma_ultra & 0x0010) && (ultra)) {
-		speed = ((udma_66) && (ultra66)) ? XFER_UDMA_4 : XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0008) && (ultra)) {
-		speed = ((udma_66) && (ultra66)) ? XFER_UDMA_3 : XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0004) && (ultra)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-        } else {
-		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-	}
-
-	(void) piix_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-	piix_tune_drive(drive, ide_get_best_pio_mode(drive, 255, 5, NULL));
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				dma_func = piix_config_drive_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = piix_config_drive_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = piix_config_drive_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		config_chipset_for_pio(drive);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		default :
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_PIIX_TUNING) */
-
-unsigned int __init pci_init_piix (struct pci_dev *dev, const char *name)
-{
-#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!piix_proc) {
-		piix_proc = 1;
-		bmide_dev = dev;
-		piix_display_info = &piix_get_info;
-	}
-#endif /* DISPLAY_PIIX_TIMINGS && CONFIG_PROC_FS */
-	return 0;
-}
-
-/*
- * Sheesh, someone at Intel needs to go read the ATA-4/5 T13 standards.
- * It does not specify device detection, but channel!!!
- * You determine later if bit 13 of word93 is set...
- */
-unsigned int __init ata66_piix (ide_hwif_t *hwif)
-{
-	byte reg54h = 0, reg55h = 0, ata66 = 0;
-	byte mask = hwif->channel ? 0xc0 : 0x30;
-
-	pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
-	pci_read_config_byte(hwif->pci_dev, 0x55, &reg55h);
-
-	ata66 = (reg54h & mask) ? 1 : 0;
-
-	return ata66;
-}
-
-void __init ide_init_piix (ide_hwif_t *hwif)
-{
-#ifndef CONFIG_IA64
-	if (!hwif->irq)
-		hwif->irq = hwif->channel ? 15 : 14;
-#endif /* CONFIG_IA64 */
-
-	if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_82371MX) {
-		/* This is a painful system best to let it self tune for now */
-		return;
-	}
-
-	hwif->tuneproc = &piix_tune_drive;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-
-	if (!hwif->dma_base)
-		return;
-
-#ifndef CONFIG_BLK_DEV_IDEDMA
-	hwif->autodma = 0;
-#else /* CONFIG_BLK_DEV_IDEDMA */
-#ifdef CONFIG_PIIX_TUNING
-	if (!noautodma)
-		hwif->autodma = 1;
-	hwif->dmaproc = &piix_dmaproc;
-	hwif->speedproc = &piix_tune_chipset;
-#endif /* CONFIG_PIIX_TUNING */
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ppc/Makefile linux-2.4.21/drivers/ide/ppc/Makefile
--- linux-2.4.20/drivers/ide/ppc/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/ppc/Makefile	2002-12-18 18:58:11.000000000 +0000
@@ -0,0 +1,13 @@
+
+O_TARGET := idedriver-ppc.o
+
+obj-y		:=
+obj-m		:=
+
+obj-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= mpc8xx.o
+obj-$(CONFIG_BLK_DEV_IDE_PMAC)		+= pmac.o
+obj-$(CONFIG_BLK_DEV_IDE_SWARM)		+= swarm.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ppc/mpc8xx.c linux-2.4.21/drivers/ide/ppc/mpc8xx.c
--- linux-2.4.20/drivers/ide/ppc/mpc8xx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/ppc/mpc8xx.c	2002-12-18 18:58:07.000000000 +0000
@@ -0,0 +1,857 @@
+/*
+ *  linux/drivers/ide/ide-m8xx.c
+ *
+ *  Copyright (C) 2000, 2001 Wolfgang Denk, wd@denx.de
+ *  Modified for direct IDE interface
+ *	by Thomas Lange, thomas@corelatus.com
+ *  Modified for direct IDE interface on 8xx without using the PCMCIA
+ *  controller
+ *	by Steven.Scholz@imc-berlin.de
+ *  Moved out of arch/ppc/kernel/m8xx_setup.c, other minor cleanups
+ *	by Mathew Locke <mattl@mvista.com>
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
+#include <linux/ide.h>
+#include <linux/bootmem.h>
+
+#include <asm/mpc8xx.h>
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/ide.h>
+#include <asm/8xx_immap.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+static int identify  (volatile u8 *p);
+static void print_fixed (volatile u8 *p);
+static void print_funcid (int func);
+static int check_ide_device (unsigned long base);
+
+static void ide_interrupt_ack (void *dev);
+static void m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio);
+
+typedef	struct ide_ioport_desc {
+	unsigned long	base_off;		/* Offset to PCMCIA memory	*/
+	ide_ioreg_t	reg_off[IDE_NR_PORTS];	/* controller register offsets	*/
+	int		irq;			/* IRQ				*/
+} ide_ioport_desc_t;
+
+ide_ioport_desc_t ioport_dsc[MAX_HWIFS] = {
+#ifdef IDE0_BASE_OFFSET
+	{ IDE0_BASE_OFFSET,
+	    {
+		IDE0_DATA_REG_OFFSET,
+		IDE0_ERROR_REG_OFFSET,
+		IDE0_NSECTOR_REG_OFFSET,
+		IDE0_SECTOR_REG_OFFSET,
+		IDE0_LCYL_REG_OFFSET,
+		IDE0_HCYL_REG_OFFSET,
+		IDE0_SELECT_REG_OFFSET,
+		IDE0_STATUS_REG_OFFSET,
+		IDE0_CONTROL_REG_OFFSET,
+		IDE0_IRQ_REG_OFFSET,
+	    },
+	    IDE0_INTERRUPT,
+	},
+#ifdef IDE1_BASE_OFFSET
+	{ IDE1_BASE_OFFSET,
+	    {
+		IDE1_DATA_REG_OFFSET,
+		IDE1_ERROR_REG_OFFSET,
+		IDE1_NSECTOR_REG_OFFSET,
+		IDE1_SECTOR_REG_OFFSET,
+		IDE1_LCYL_REG_OFFSET,
+		IDE1_HCYL_REG_OFFSET,
+		IDE1_SELECT_REG_OFFSET,
+		IDE1_STATUS_REG_OFFSET,
+		IDE1_CONTROL_REG_OFFSET,
+		IDE1_IRQ_REG_OFFSET,
+	    },
+	    IDE1_INTERRUPT,
+	},
+#endif /* IDE1_BASE_OFFSET */
+#endif	/* IDE0_BASE_OFFSET */
+};
+
+ide_pio_timings_t ide_pio_clocks[6];
+int hold_time[6] =  {30, 20, 15, 10, 10, 10 };   /* PIO Mode 5 with IORDY (nonstandard) */
+
+/*
+ * Warning: only 1 (ONE) PCMCIA slot supported here,
+ * which must be correctly initialized by the firmware (PPCBoot).
+ */
+static int _slot_ = -1;			/* will be read from PCMCIA registers   */
+
+/* Make clock cycles and always round up */
+#define PCMCIA_MK_CLKS( t, T ) (( (t) * ((T)/1000000) + 999U ) / 1000U )
+
+
+
+/*
+ * IDE stuff.
+ */
+static int
+m8xx_ide_default_irq(ide_ioreg_t base)
+{
+#ifdef CONFIG_BLK_DEV_MPC8xx_IDE
+	if (base >= MAX_HWIFS)
+		return 0;
+
+	printk("[%d] m8xx_ide_default_irq %d\n",__LINE__,ioport_dsc[base].irq);
+	
+	return (ioport_dsc[base].irq);
+#else
+        return 9;
+#endif
+}
+
+static ide_ioreg_t
+m8xx_ide_default_io_base(int index)
+{
+        return index;
+}
+
+#define M8XX_PCMCIA_CD2(slot)      (0x10000000 >> (slot << 4))
+#define M8XX_PCMCIA_CD1(slot)      (0x08000000 >> (slot << 4))
+
+/*
+ * The TQM850L hardware has two pins swapped! Grrrrgh!
+ */
+#ifdef	CONFIG_TQM850L
+#define __MY_PCMCIA_GCRX_CXRESET	PCMCIA_GCRX_CXOE
+#define __MY_PCMCIA_GCRX_CXOE		PCMCIA_GCRX_CXRESET
+#else
+#define __MY_PCMCIA_GCRX_CXRESET	PCMCIA_GCRX_CXRESET
+#define __MY_PCMCIA_GCRX_CXOE		PCMCIA_GCRX_CXOE
+#endif
+
+#if defined(CONFIG_BLK_DEV_MPC8xx_IDE) && defined(CONFIG_IDE_8xx_PCCARD)
+#define PCMCIA_SCHLVL IDE0_INTERRUPT	/* Status Change Interrupt Level	*/
+static int pcmcia_schlvl = PCMCIA_SCHLVL;
+#endif
+
+/*
+ * See include/linux/ide.h for definition of hw_regs_t (p, base)
+ */
+
+/*
+ * m8xx_ide_init_hwif_ports for a direct IDE interface _using_
+ */
+#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
+static void
+m8xx_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, 
+		ide_ioreg_t ctrl_port, int *irq)
+{
+	ide_ioreg_t *p = hw->io_ports;
+	int i;
+
+	typedef struct {
+		ulong br;
+		ulong or;
+	} pcmcia_win_t;
+	volatile pcmcia_win_t *win;
+	volatile pcmconf8xx_t *pcmp;
+
+	uint *pgcrx;
+	u32 pcmcia_phy_base;
+	u32 pcmcia_phy_end;
+	static unsigned long pcmcia_base = 0;
+	unsigned long base;
+
+	*p = 0;
+	if (irq)
+		*irq = 0;
+
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
+
+	if (!pcmcia_base) {
+                /*
+                 * Read out PCMCIA registers. Since the reset values
+                 * are undefined, we sure hope that they have been
+                 * set up by firmware
+		 */
+
+		/* Scan all registers for valid settings */
+		pcmcia_phy_base = 0xFFFFFFFF;
+		pcmcia_phy_end = 0;
+		/* br0 is start of brX and orX regs */
+		win = (pcmcia_win_t *) \
+			(&(((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0));
+		for (i = 0; i < 8; i++) {
+			if (win->or & 1) {	/* This bank is marked as valid */
+				if (win->br < pcmcia_phy_base) {
+					pcmcia_phy_base = win->br;
+				}
+				if ((win->br + PCMCIA_MEM_SIZE) > pcmcia_phy_end) {
+					pcmcia_phy_end  = win->br + PCMCIA_MEM_SIZE;
+				}
+				/* Check which slot that has been defined */
+				_slot_ = (win->or >> 2) & 1;
+
+			}					/* Valid bank */
+			win++;
+		}						/* for */
+
+		printk ("PCMCIA slot %c: phys mem %08x...%08x (size %08x)\n",
+			'A' + _slot_,
+			pcmcia_phy_base, pcmcia_phy_end,
+			pcmcia_phy_end - pcmcia_phy_base);
+
+		pcmcia_base=(unsigned long)ioremap(pcmcia_phy_base,
+						   pcmcia_phy_end-pcmcia_phy_base);
+
+#ifdef DEBUG
+		printk ("PCMCIA virt base: %08lx\n", pcmcia_base);
+#endif
+		/* Compute clock cycles for PIO timings */
+		for (i=0; i<6; ++i) {
+			bd_t	*binfo = (bd_t *)__res;
+
+			hold_time[i]   =
+				PCMCIA_MK_CLKS (hold_time[i],
+						binfo->bi_busfreq);
+			ide_pio_clocks[i].setup_time  =
+				PCMCIA_MK_CLKS (ide_pio_timings[i].setup_time,
+						binfo->bi_busfreq);
+			ide_pio_clocks[i].active_time =
+				PCMCIA_MK_CLKS (ide_pio_timings[i].active_time,
+						binfo->bi_busfreq);
+			ide_pio_clocks[i].cycle_time  =
+				PCMCIA_MK_CLKS (ide_pio_timings[i].cycle_time,
+						binfo->bi_busfreq);
+#if 0
+			printk ("PIO mode %d timings: %d/%d/%d => %d/%d/%d\n",
+				i,
+				ide_pio_clocks[i].setup_time,
+				ide_pio_clocks[i].active_time,
+				ide_pio_clocks[i].hold_time,
+				ide_pio_clocks[i].cycle_time,
+				ide_pio_timings[i].setup_time,
+				ide_pio_timings[i].active_time,
+				ide_pio_timings[i].hold_time,
+				ide_pio_timings[i].cycle_time);
+#endif
+		}
+	}
+
+	if (data_port >= MAX_HWIFS)
+		return;
+
+	if (_slot_ == -1) {
+		printk ("PCMCIA slot has not been defined! Using A as default\n");
+		_slot_ = 0;
+	}
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+
+#ifdef DEBUG
+	printk ("PIPR = 0x%08X  slot %c ==> mask = 0x%X\n",
+		pcmp->pcmc_pipr,
+		'A' + _slot_,
+		M8XX_PCMCIA_CD1(_slot_) | M8XX_PCMCIA_CD2(_slot_) );
+#endif /* DEBUG */
+
+	if (pcmp->pcmc_pipr & (M8XX_PCMCIA_CD1(_slot_)|M8XX_PCMCIA_CD2(_slot_))) {
+		printk ("No card in slot %c: PIPR=%08x\n",
+			'A' + _slot_, (u32) pcmp->pcmc_pipr);
+		return;		/* No card in slot */
+	}
+
+	check_ide_device (pcmcia_base);
+
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+
+	base = pcmcia_base + ioport_dsc[data_port].base_off;
+#ifdef DEBUG
+	printk ("base: %08x + %08x = %08x\n",
+			pcmcia_base, ioport_dsc[data_port].base_off, base);
+#endif
+
+	for (i = 0; i < IDE_NR_PORTS; ++i) {
+#ifdef DEBUG
+		printk ("port[%d]: %08x + %08x = %08x\n",
+			i,
+			base,
+			ioport_dsc[data_port].reg_off[i],
+			i, base + ioport_dsc[data_port].reg_off[i]);
+#endif
+	 	*p++ = base + ioport_dsc[data_port].reg_off[i];
+	}
+
+	if (irq) {
+#ifdef CONFIG_IDE_8xx_PCCARD
+		unsigned int reg;
+
+		*irq = ioport_dsc[data_port].irq;
+		if (_slot_)
+			pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcrb;
+		else
+			pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcra;
+
+		reg = *pgcrx;
+		reg |= mk_int_int_mask (pcmcia_schlvl) << 24;
+		reg |= mk_int_int_mask (pcmcia_schlvl) << 16;
+		*pgcrx = reg;
+#else	/* direct connected IDE drive, i.e. external IRQ, not the PCMCIA irq */
+		*irq = ioport_dsc[data_port].irq;
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+	}
+
+	/* register routine to tune PIO mode */
+	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
+
+	hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
+	/* Enable Harddisk Interrupt,
+	 * and make it edge sensitive
+	 */
+	/* (11-18) Set edge detect for irq, no wakeup from low power mode */
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |=
+					(0x80000000 >> ioport_dsc[data_port].irq);
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+	/* Make sure we dont get garbage irq */
+	((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pscr = 0xFFFF;
+
+	/* Enable falling edge irq */
+	pcmp->pcmc_per = 0x100000 >> (16 * _slot_);
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+}	/* m8xx_ide_init_hwif_ports() using 8xx internal PCMCIA interface */
+#endif /* CONFIG_IDE_8xx_PCCARD || CONFIG_IDE_8xx_DIRECT */
+
+/*
+ * m8xx_ide_init_hwif_ports for a direct IDE interface _not_ using
+ * MPC8xx's internal PCMCIA interface
+ */
+#if defined(CONFIG_IDE_EXT_DIRECT)
+void m8xx_ide_init_hwif_ports (hw_regs_t *hw,
+	ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+{
+	ide_ioreg_t *p = hw->io_ports;
+	int i;
+
+	u32 ide_phy_base;
+	u32 ide_phy_end;
+	static unsigned long ide_base = 0;
+	unsigned long base;
+
+	*p = 0;
+	if (irq)
+		*irq = 0;
+
+	if (!ide_base) {
+
+		/* TODO:
+		 * - add code to read ORx, BRx
+		 */
+		ide_phy_base = CFG_ATA_BASE_ADDR;
+		ide_phy_end  = CFG_ATA_BASE_ADDR + 0x200;
+
+		printk ("IDE phys mem : %08x...%08x (size %08x)\n",
+			ide_phy_base, ide_phy_end,
+			ide_phy_end - ide_phy_base);
+		
+		ide_base=(unsigned long)ioremap(ide_phy_base,
+						ide_phy_end-ide_phy_base);
+
+#ifdef DEBUG
+		printk ("IDE virt base: %08lx\n", ide_base);
+#endif
+	}
+
+	if (data_port >= MAX_HWIFS)
+		return;
+
+	base = ide_base + ioport_dsc[data_port].base_off;
+#ifdef DEBUG
+	printk ("base: %08x + %08x = %08x\n",
+		ide_base, ioport_dsc[data_port].base_off, base);
+#endif
+
+	for (i = 0; i < IDE_NR_PORTS; ++i) {
+#ifdef DEBUG
+		printk ("port[%d]: %08x + %08x = %08x\n",
+			i,
+			base,
+			ioport_dsc[data_port].reg_off[i],
+			i, base + ioport_dsc[data_port].reg_off[i]);
+#endif
+	 	*p++ = base + ioport_dsc[data_port].reg_off[i];
+	}
+
+	if (irq) {
+		/* direct connected IDE drive, i.e. external IRQ */
+		*irq = ioport_dsc[data_port].irq;
+	}
+
+	/* register routine to tune PIO mode */
+	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
+
+	hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
+	/* Enable Harddisk Interrupt,
+	 * and make it edge sensitive
+	 */
+	/* (11-18) Set edge detect for irq, no wakeup from low power mode */
+	((immap_t *) IMAP_ADDR)->im_siu_conf.sc_siel |=
+			(0x80000000 >> ioport_dsc[data_port].irq);
+}	/* m8xx_ide_init_hwif_ports() for CONFIG_IDE_8xx_DIRECT */ 
+
+#endif	/* CONFIG_IDE_8xx_DIRECT */
+
+
+/* -------------------------------------------------------------------- */
+
+
+/* PCMCIA Timing */
+#ifndef	PCMCIA_SHT
+#define PCMCIA_SHT(t)	((t & 0x0F)<<16)	/* Strobe Hold  Time 	*/
+#define PCMCIA_SST(t)	((t & 0x0F)<<12)	/* Strobe Setup Time	*/
+#define PCMCIA_SL(t) ((t==32) ? 0 : ((t & 0x1F)<<7)) /* Strobe Length	*/
+#endif
+
+
+/* Calculate PIO timings */
+static void
+m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio)
+{
+	ide_pio_data_t d;
+#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
+	volatile pcmconf8xx_t	*pcmp;
+	ulong timing, mask, reg;
+#endif
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+
+#if 1
+	printk("%s[%d] %s: best PIO mode: %d\n",
+		__FILE__,__LINE__,__FUNCTION__, pio);
+#endif
+
+#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
+
+	mask = ~(PCMCIA_SHT(0xFF) | PCMCIA_SST(0xFF) | PCMCIA_SL(0xFF));
+
+	timing  = PCMCIA_SHT(hold_time[pio]  )
+		| PCMCIA_SST(ide_pio_clocks[pio].setup_time )
+		| PCMCIA_SL (ide_pio_clocks[pio].active_time)
+		;
+
+#if 1
+	printk ("Setting timing bits 0x%08lx in PCMCIA controller\n", timing);
+#endif
+	if ((reg = pcmp->pcmc_por0 & mask) != 0)
+		pcmp->pcmc_por0 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por1 & mask) != 0)
+		pcmp->pcmc_por1 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por2 & mask) != 0)
+		pcmp->pcmc_por2 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por3 & mask) != 0)
+		pcmp->pcmc_por3 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por4 & mask) != 0)
+		pcmp->pcmc_por4 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por5 & mask) != 0)
+		pcmp->pcmc_por5 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por6 & mask) != 0)
+		pcmp->pcmc_por6 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por7 & mask) != 0)
+		pcmp->pcmc_por7 = reg | timing;
+
+#elif defined(CONFIG_IDE_EXT_DIRECT)
+
+	printk("%s[%d] %s: not implemented yet!\n",
+		__FILE__,__LINE__,__FUNCTION__);
+#endif /* defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_PCMCIA */
+}
+
+static void
+ide_interrupt_ack (void *dev)
+{
+#ifdef CONFIG_IDE_8xx_PCCARD
+	u_int pscr, pipr;
+
+#if (PCMCIA_SOCKETS_NO == 2)
+	u_int _slot_;
+#endif
+
+	/* get interrupt sources */
+
+	pscr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr;
+	pipr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr;
+
+	/*
+	 * report only if both card detect signals are the same
+	 * not too nice done,
+	 * we depend on that CD2 is the bit to the left of CD1...
+	 */
+
+	if(_slot_==-1){
+	  printk("PCMCIA slot has not been defined! Using A as default\n");
+	  _slot_=0;
+	}
+
+	if(((pipr & M8XX_PCMCIA_CD2(_slot_)) >> 1) ^
+	   (pipr & M8XX_PCMCIA_CD1(_slot_))         ) {
+	  printk ("card detect interrupt\n");
+	}
+	/* clear the interrupt sources */
+	((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = pscr;
+
+#else /* ! CONFIG_IDE_8xx_PCCARD */
+	/*
+	 * Only CONFIG_IDE_8xx_PCCARD is using the interrupt of the
+	 * MPC8xx's PCMCIA controller, so there is nothing to be done here
+	 * for CONFIG_IDE_8xx_DIRECT and CONFIG_IDE_EXT_DIRECT.
+	 * The interrupt is handled somewhere else.	-- Steven
+	 */
+#endif /* CONFIG_IDE_8xx_PCCARD */
+}
+
+
+
+/*
+ * CIS Tupel codes
+ */
+#define CISTPL_NULL		0x00
+#define CISTPL_DEVICE		0x01
+#define CISTPL_LONGLINK_CB	0x02
+#define CISTPL_INDIRECT		0x03
+#define CISTPL_CONFIG_CB	0x04
+#define CISTPL_CFTABLE_ENTRY_CB 0x05
+#define CISTPL_LONGLINK_MFC	0x06
+#define CISTPL_BAR		0x07
+#define CISTPL_PWR_MGMNT	0x08
+#define CISTPL_EXTDEVICE	0x09
+#define CISTPL_CHECKSUM		0x10
+#define CISTPL_LONGLINK_A	0x11
+#define CISTPL_LONGLINK_C	0x12
+#define CISTPL_LINKTARGET	0x13
+#define CISTPL_NO_LINK		0x14
+#define CISTPL_VERS_1		0x15
+#define CISTPL_ALTSTR		0x16
+#define CISTPL_DEVICE_A		0x17
+#define CISTPL_JEDEC_C		0x18
+#define CISTPL_JEDEC_A		0x19
+#define CISTPL_CONFIG		0x1a
+#define CISTPL_CFTABLE_ENTRY	0x1b
+#define CISTPL_DEVICE_OC	0x1c
+#define CISTPL_DEVICE_OA	0x1d
+#define CISTPL_DEVICE_GEO	0x1e
+#define CISTPL_DEVICE_GEO_A	0x1f
+#define CISTPL_MANFID		0x20
+#define CISTPL_FUNCID		0x21
+#define CISTPL_FUNCE		0x22
+#define CISTPL_SWIL		0x23
+#define CISTPL_END		0xff
+
+/*
+ * CIS Function ID codes
+ */
+#define CISTPL_FUNCID_MULTI	0x00
+#define CISTPL_FUNCID_MEMORY	0x01
+#define CISTPL_FUNCID_SERIAL	0x02
+#define CISTPL_FUNCID_PARALLEL	0x03
+#define CISTPL_FUNCID_FIXED	0x04
+#define CISTPL_FUNCID_VIDEO	0x05
+#define CISTPL_FUNCID_NETWORK	0x06
+#define CISTPL_FUNCID_AIMS	0x07
+#define CISTPL_FUNCID_SCSI	0x08
+
+/*
+ * Fixed Disk FUNCE codes
+ */
+#define CISTPL_IDE_INTERFACE	0x01
+
+#define CISTPL_FUNCE_IDE_IFACE	0x01
+#define CISTPL_FUNCE_IDE_MASTER	0x02
+#define CISTPL_FUNCE_IDE_SLAVE	0x03
+
+/* First feature byte */
+#define CISTPL_IDE_SILICON	0x04
+#define CISTPL_IDE_UNIQUE	0x08
+#define CISTPL_IDE_DUAL		0x10
+
+/* Second feature byte */
+#define CISTPL_IDE_HAS_SLEEP	0x01
+#define CISTPL_IDE_HAS_STANDBY	0x02
+#define CISTPL_IDE_HAS_IDLE	0x04
+#define CISTPL_IDE_LOW_POWER	0x08
+#define CISTPL_IDE_REG_INHIBIT	0x10
+#define CISTPL_IDE_HAS_INDEX	0x20
+#define CISTPL_IDE_IOIS16	0x40
+
+
+/* -------------------------------------------------------------------- */
+
+
+#define	MAX_TUPEL_SZ	512
+#define MAX_FEATURES	4
+
+static int check_ide_device (unsigned long base)
+{
+	volatile u8 *ident = NULL;
+	volatile u8 *feature_p[MAX_FEATURES];
+	volatile u8 *p, *start;
+	int n_features = 0;
+	u8 func_id = ~0;
+	u8 code, len;
+	unsigned short config_base = 0;
+	int found = 0;
+	int i;
+
+#ifdef DEBUG
+	printk ("PCMCIA MEM: %08lX\n", base);
+#endif
+	start = p = (volatile u8 *) base;
+
+	while ((p - start) < MAX_TUPEL_SZ) {
+
+		code = *p; p += 2;
+
+		if (code == 0xFF) { /* End of chain */
+			break;
+		}
+
+		len = *p; p += 2;
+#ifdef	DEBUG_PCMCIA
+		{ volatile u8 *q = p;
+			printk ("\nTuple code %02x  length %d\n\tData:",
+				code, len);
+
+			for (i = 0; i < len; ++i) {
+				printk (" %02x", *q);
+				q+= 2;
+			}
+		}
+#endif	/* DEBUG_PCMCIA */
+		switch (code) {
+		case CISTPL_VERS_1:
+			ident = p + 4;
+			break;
+		case CISTPL_FUNCID:
+			func_id = *p;
+			break;
+		case CISTPL_FUNCE:
+			if (n_features < MAX_FEATURES)
+				feature_p[n_features++] = p;
+			break;
+		case CISTPL_CONFIG:
+			config_base = (*(p+6) << 8) + (*(p+4));
+		default:
+			break;
+		}
+		p += 2 * len;
+	}
+
+	found = identify (ident);
+
+	if (func_id != ((u8)~0)) {
+		print_funcid (func_id);
+
+		if (func_id == CISTPL_FUNCID_FIXED)
+			found = 1;
+		else
+			return (1);	/* no disk drive */
+	}
+
+	for (i=0; i<n_features; ++i) {
+		print_fixed (feature_p[i]);
+	}
+
+	if (!found) {
+		printk ("unknown card type\n");
+		return (1);
+	}
+
+	/* set level mode irq and I/O mapped device in config reg*/
+	*((u8 *)(base + config_base)) = 0x41;
+
+	return (0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void print_funcid (int func)
+{
+	switch (func) {
+	case CISTPL_FUNCID_MULTI:
+		printk (" Multi-Function");
+		break;
+	case CISTPL_FUNCID_MEMORY:
+		printk (" Memory");
+		break;
+	case CISTPL_FUNCID_SERIAL:
+		printk (" Serial Port");
+		break;
+	case CISTPL_FUNCID_PARALLEL:
+		printk (" Parallel Port");
+		break;
+	case CISTPL_FUNCID_FIXED:
+		printk (" Fixed Disk");
+		break;
+	case CISTPL_FUNCID_VIDEO:
+		printk (" Video Adapter");
+		break;
+	case CISTPL_FUNCID_NETWORK:
+		printk (" Network Adapter");
+		break;
+	case CISTPL_FUNCID_AIMS:
+		printk (" AIMS Card");
+		break;
+	case CISTPL_FUNCID_SCSI:
+		printk (" SCSI Adapter");
+		break;
+	default:
+		printk (" Unknown");
+		break;
+	}
+	printk (" Card\n");
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void print_fixed (volatile u8 *p)
+{
+	if (p == NULL)
+		return;
+
+	switch (*p) {
+	case CISTPL_FUNCE_IDE_IFACE:
+	    {   u8 iface = *(p+2);
+
+		printk ((iface == CISTPL_IDE_INTERFACE) ? " IDE" : " unknown");
+		printk (" interface ");
+		break;
+	    }
+	case CISTPL_FUNCE_IDE_MASTER:
+	case CISTPL_FUNCE_IDE_SLAVE:
+	    {   u8 f1 = *(p+2);
+		u8 f2 = *(p+4);
+
+		printk ((f1 & CISTPL_IDE_SILICON) ? " [silicon]" : " [rotating]");
+
+		if (f1 & CISTPL_IDE_UNIQUE)
+			printk (" [unique]");
+
+		printk ((f1 & CISTPL_IDE_DUAL) ? " [dual]" : " [single]");
+
+		if (f2 & CISTPL_IDE_HAS_SLEEP)
+			printk (" [sleep]");
+
+		if (f2 & CISTPL_IDE_HAS_STANDBY)
+			printk (" [standby]");
+
+		if (f2 & CISTPL_IDE_HAS_IDLE)
+			printk (" [idle]");
+
+		if (f2 & CISTPL_IDE_LOW_POWER)
+			printk (" [low power]");
+
+		if (f2 & CISTPL_IDE_REG_INHIBIT)
+			printk (" [reg inhibit]");
+
+		if (f2 & CISTPL_IDE_HAS_INDEX)
+			printk (" [index]");
+
+		if (f2 & CISTPL_IDE_IOIS16)
+			printk (" [IOis16]");
+
+		break;
+	    }
+	}
+	printk ("\n");
+}
+
+/* ------------------------------------------------------------------------- */
+
+
+#define MAX_IDENT_CHARS		64
+#define	MAX_IDENT_FIELDS	4
+
+static u8 *known_cards[] = {
+	"ARGOSY PnPIDE D5",
+	NULL
+};
+
+static int identify  (volatile u8 *p)
+{
+	u8 id_str[MAX_IDENT_CHARS];
+	u8 data;
+	u8 *t;
+	u8 **card;
+	int i, done;
+
+	if (p == NULL)
+		return (0);	/* Don't know */
+
+	t = id_str;
+	done =0;
+
+	for (i=0; i<=4 && !done; ++i, p+=2) {
+		while ((data = *p) != '\0') {
+			if (data == 0xFF) {
+				done = 1;
+				break;
+			}
+			*t++ = data;
+			if (t == &id_str[MAX_IDENT_CHARS-1]) {
+				done = 1;
+				break;
+			}
+			p += 2;
+		}
+		if (!done)
+			*t++ = ' ';
+	}
+	*t = '\0';
+	while (--t > id_str) {
+		if (*t == ' ')
+			*t = '\0';
+		else
+			break;
+	}
+	printk ("Card ID: %s\n", id_str);
+
+	for (card=known_cards; *card; ++card) {
+		if (strcmp(*card, id_str) == 0) {	/* found! */
+			return (1);
+		}
+	}
+
+	return (0);	/* don't know */
+}
+
+void m8xx_ide_init(void)
+{
+	ppc_ide_md.default_irq          = m8xx_ide_default_irq;
+	ppc_ide_md.default_io_base      = m8xx_ide_default_io_base;
+	ppc_ide_md.ide_init_hwif        = m8xx_ide_init_hwif_ports;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ppc/pmac.c linux-2.4.21/drivers/ide/ppc/pmac.c
--- linux-2.4.20/drivers/ide/ppc/pmac.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/ppc/pmac.c	2002-12-18 18:58:10.000000000 +0000
@@ -0,0 +1,1786 @@
+/*
+ * linux/drivers/ide/ide-pmac.c
+ *
+ * Support for IDE interfaces on PowerMacs.
+ * These IDE interfaces are memory-mapped and have a DBDMA channel
+ * for doing DMA.
+ *
+ *  Copyright (C) 1998-2001 Paul Mackerras & Ben. Herrenschmidt
+ *
+ *  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.
+ *
+ * Some code taken from drivers/ide/ide-dma.c:
+ *
+ *  Copyright (c) 1995-1998  Mark Lord
+ *
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/dbdma.h>
+#include <asm/ide.h>
+#include <asm/mediabay.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/sections.h>
+#include <asm/irq.h>
+#ifdef CONFIG_PMAC_PBOOK
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#endif
+#include "ide_modes.h"
+
+extern void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq);
+
+#define IDE_PMAC_DEBUG
+
+#define DMA_WAIT_TIMEOUT	500
+
+typedef struct pmac_ide_hwif {
+	ide_ioreg_t			regbase;
+	int				irq;
+	int				kind;
+	int				aapl_bus_id;
+	struct device_node*		node;
+	u32				timings[2];
+	int				index;
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+	/* Those fields are duplicating what is in hwif. We currently
+	 * can't use the hwif ones because of some assumptions that are
+	 * beeing done by the generic code about the kind of dma controller
+	 * and format of the dma table. This will have to be fixed though.
+	 */
+	volatile struct dbdma_regs*	dma_regs;
+	struct dbdma_cmd*		dma_table_cpu;
+	dma_addr_t			dma_table_dma;
+	struct scatterlist*		sg_table;
+	int				sg_nents;
+	int				sg_dma_direction;
+#endif
+	
+} pmac_ide_hwif_t;
+
+static pmac_ide_hwif_t pmac_ide[MAX_HWIFS] __pmacdata;
+static int pmac_ide_count;
+
+enum {
+	controller_ohare,	/* OHare based */
+	controller_heathrow,	/* Heathrow/Paddington */
+	controller_kl_ata3,	/* KeyLargo ATA-3 */
+	controller_kl_ata4,	/* KeyLargo ATA-4 */
+	controller_kl_ata4_80	/* KeyLargo ATA-4 with 80 conductor cable */
+};
+
+/*
+ * Extra registers, both 32-bit little-endian
+ */
+#define IDE_TIMING_CONFIG	0x200
+#define IDE_INTERRUPT		0x300
+
+/*
+ * Timing configuration register definitions
+ */
+
+/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
+#define SYSCLK_TICKS(t)		(((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS)
+#define SYSCLK_TICKS_66(t)	(((t) + IDE_SYSCLK_66_NS - 1) / IDE_SYSCLK_66_NS)
+#define IDE_SYSCLK_NS		30	/* 33Mhz cell */
+#define IDE_SYSCLK_66_NS	15	/* 66Mhz cell */
+
+/* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on
+ * 40 connector cable and to 4 on 80 connector one.
+ * Clock unit is 15ns (66Mhz)
+ * 
+ * 3 Values can be programmed:
+ *  - Write data setup, which appears to match the cycle time. They
+ *    also call it DIOW setup.
+ *  - Ready to pause time (from spec)
+ *  - Address setup. That one is weird. I don't see where exactly
+ *    it fits in UDMA cycles, I got it's name from an obscure piece
+ *    of commented out code in Darwin. They leave it to 0, we do as
+ *    well, despite a comment that would lead to think it has a
+ *    min value of 45ns.
+ * Apple also add 60ns to the write data setup (or cycle time ?) on
+ * reads. I can't explain that, I tried it and it broke everything
+ * here.
+ */
+#define TR_66_UDMA_MASK			0xfff00000
+#define TR_66_UDMA_EN			0x00100000 /* Enable Ultra mode for DMA */
+#define TR_66_UDMA_ADDRSETUP_MASK	0xe0000000 /* Address setup */
+#define TR_66_UDMA_ADDRSETUP_SHIFT	29
+#define TR_66_UDMA_RDY2PAUS_MASK	0x1e000000 /* Ready 2 pause time */
+#define TR_66_UDMA_RDY2PAUS_SHIFT	25
+#define TR_66_UDMA_WRDATASETUP_MASK	0x01e00000 /* Write data setup time */
+#define TR_66_UDMA_WRDATASETUP_SHIFT	21
+#define TR_66_MDMA_MASK			0x000ffc00
+#define TR_66_MDMA_RECOVERY_MASK	0x000f8000
+#define TR_66_MDMA_RECOVERY_SHIFT	15
+#define TR_66_MDMA_ACCESS_MASK		0x00007c00
+#define TR_66_MDMA_ACCESS_SHIFT		10
+#define TR_66_PIO_MASK			0x000003ff
+#define TR_66_PIO_RECOVERY_MASK		0x000003e0
+#define TR_66_PIO_RECOVERY_SHIFT	5
+#define TR_66_PIO_ACCESS_MASK		0x0000001f
+#define TR_66_PIO_ACCESS_SHIFT		0
+
+/* 33Mhz cell, found in OHare, Heathrow (& Paddington) and KeyLargo
+ * Can do pio & mdma modes, clock unit is 30ns (33Mhz)
+ * 
+ * The access time and recovery time can be programmed. Some older
+ * Darwin code base limit OHare to 150ns cycle time. I decided to do
+ * the same here fore safety against broken old hardware ;)
+ * The HalfTick bit, when set, adds half a clock (15ns) to the access
+ * time and removes one from recovery. It's not supported on KeyLargo
+ * implementation afaik. The E bit appears to be set for PIO mode 0 and
+ * is used to reach long timings used in this mode.
+ */
+#define TR_33_MDMA_MASK			0x003ff800
+#define TR_33_MDMA_RECOVERY_MASK	0x001f0000
+#define TR_33_MDMA_RECOVERY_SHIFT	16
+#define TR_33_MDMA_ACCESS_MASK		0x0000f800
+#define TR_33_MDMA_ACCESS_SHIFT		11
+#define TR_33_MDMA_HALFTICK		0x00200000
+#define TR_33_PIO_MASK			0x000007ff
+#define TR_33_PIO_E			0x00000400
+#define TR_33_PIO_RECOVERY_MASK		0x000003e0
+#define TR_33_PIO_RECOVERY_SHIFT	5
+#define TR_33_PIO_ACCESS_MASK		0x0000001f
+#define TR_33_PIO_ACCESS_SHIFT		0
+
+/*
+ * Interrupt register definitions
+ */
+#define IDE_INTR_DMA			0x80000000
+#define IDE_INTR_DEVICE			0x40000000
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+
+/* Rounded Multiword DMA timings
+ * 
+ * I gave up finding a generic formula for all controller
+ * types and instead, built tables based on timing values
+ * used by Apple in Darwin's implementation.
+ */
+struct mdma_timings_t {
+	int	accessTime;
+	int	recoveryTime;
+	int	cycleTime;
+};
+
+struct mdma_timings_t mdma_timings_33[] __pmacdata =
+{
+    { 240, 240, 480 },
+    { 180, 180, 360 },
+    { 135, 135, 270 },
+    { 120, 120, 240 },
+    { 105, 105, 210 },
+    {  90,  90, 180 },
+    {  75,  75, 150 },
+    {  75,  45, 120 },
+    {   0,   0,   0 }
+};
+
+struct mdma_timings_t mdma_timings_33k[] __pmacdata =
+{
+    { 240, 240, 480 },
+    { 180, 180, 360 },
+    { 150, 150, 300 },
+    { 120, 120, 240 },
+    {  90, 120, 210 },
+    {  90,  90, 180 },
+    {  90,  60, 150 },
+    {  90,  30, 120 },
+    {   0,   0,   0 }
+};
+
+struct mdma_timings_t mdma_timings_66[] __pmacdata =
+{
+    { 240, 240, 480 },
+    { 180, 180, 360 },
+    { 135, 135, 270 },
+    { 120, 120, 240 },
+    { 105, 105, 210 },
+    {  90,  90, 180 },
+    {  90,  75, 165 },
+    {  75,  45, 120 },
+    {   0,   0,   0 }
+};
+
+/* Ultra DMA timings (rounded) */
+struct {
+	int	addrSetup; /* ??? */
+	int	rdy2pause;
+	int	wrDataSetup;
+} udma_timings[] __pmacdata =
+{
+    {   0, 180,  120 },	/* Mode 0 */
+    {   0, 150,  90 },	/*      1 */
+    {   0, 120,  60 },	/*      2 */
+    {   0, 90,   45 },	/*      3 */
+    {   0, 90,   30 }	/*      4 */
+};
+
+/* allow up to 256 DBDMA commands per xfer */
+#define MAX_DCMDS		256
+
+/* Wait 2s for disk to answer on IDE bus after
+ * enable operation.
+ * NOTE: There is at least one case I know of a disk that needs about 10sec
+ *       before anwering on the bus. I beleive we could add a kernel command
+ *       line arg to override this delay for such cases.
+ */
+#define IDE_WAKEUP_DELAY_MS	2000
+
+static void pmac_ide_setup_dma(struct device_node *np, int ix);
+static int pmac_ide_build_dmatable(ide_drive_t *drive, int wr);
+static int pmac_ide_tune_chipset(ide_drive_t *drive, u8 speed);
+static void pmac_ide_tuneproc(ide_drive_t *drive, u8 pio);
+static void pmac_ide_selectproc(ide_drive_t *drive);
+static int pmac_ide_dma_begin (ide_drive_t *drive);
+
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+#ifdef CONFIG_PMAC_PBOOK
+static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when);
+struct pmu_sleep_notifier idepmac_sleep_notifier = {
+	idepmac_notify_sleep, SLEEP_LEVEL_BLOCK,
+};
+#endif /* CONFIG_PMAC_PBOOK */
+
+/*
+ * N.B. this can't be an initfunc, because the media-bay task can
+ * call ide_[un]register at any time.
+ */
+void __pmac
+pmac_ide_init_hwif_ports(hw_regs_t *hw,
+			      ide_ioreg_t data_port, ide_ioreg_t ctrl_port,
+			      int *irq)
+{
+	int i, ix;
+
+	if (data_port == 0)
+		return;
+
+	for (ix = 0; ix < MAX_HWIFS; ++ix)
+		if (data_port == pmac_ide[ix].regbase)
+			break;
+
+	if (ix >= MAX_HWIFS) {
+		/* Probably a PCI interface... */
+		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
+			hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET;
+		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+		return;
+	}
+
+	for (i = 0; i < 8; ++i)
+		hw->io_ports[i] = data_port + i * 0x10;
+	hw->io_ports[8] = data_port + 0x160;
+
+	if (irq != NULL)
+		*irq = pmac_ide[ix].irq;
+}
+
+/* Setup timings for the selected drive (master/slave). I still need to verify if this
+ * is enough, I beleive selectproc will be called whenever an IDE command is started,
+ * but... */
+static void __pmac
+pmac_ide_selectproc(ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+
+	if (pmif == NULL)
+		return;
+
+	if (drive->select.b.unit & 0x01)
+		writel(pmif->timings[1],
+			(unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
+	else
+		writel(pmif->timings[0],
+			(unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
+	(void)readl((unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
+}
+
+
+static int __pmac
+pmac_ide_do_setfeature(ide_drive_t *drive, u8 command)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	int result = 1;
+	
+	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
+	udelay(1);
+	SELECT_DRIVE(drive);
+	SELECT_MASK(drive, 0);
+	udelay(1);
+	/* Get rid of pending error state */
+	(void) hwif->INB(IDE_STATUS_REG);
+	/* Timeout bumped for some powerbooks */
+	if (wait_for_ready(drive, 2000)) {
+		/* Timeout bumped for some powerbooks */
+		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready "
+			"before SET_FEATURE!\n");
+		goto out;
+	}
+	udelay(10);
+	hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
+	hwif->OUTB(command, IDE_NSECTOR_REG);
+	hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
+	hwif->OUTB(WIN_SETFEATURES, IDE_COMMAND_REG);
+	udelay(1);
+	/* Timeout bumped for some powerbooks */
+	result = wait_for_ready(drive, 2000);
+	hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	if (result)
+		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready "
+			"after SET_FEATURE !\n");
+out:
+	SELECT_MASK(drive, 0);
+	if (result == 0) {
+		drive->id->dma_ultra &= ~0xFF00;
+		drive->id->dma_mword &= ~0x0F00;
+		drive->id->dma_1word &= ~0x0F00;
+		switch(command) {
+			case XFER_UDMA_7:
+				drive->id->dma_ultra |= 0x8080; break;
+			case XFER_UDMA_6:
+				drive->id->dma_ultra |= 0x4040; break;
+			case XFER_UDMA_5:
+				drive->id->dma_ultra |= 0x2020; break;
+			case XFER_UDMA_4:
+				drive->id->dma_ultra |= 0x1010; break;
+			case XFER_UDMA_3:
+				drive->id->dma_ultra |= 0x0808; break;
+			case XFER_UDMA_2:
+				drive->id->dma_ultra |= 0x0404; break;
+			case XFER_UDMA_1:
+				drive->id->dma_ultra |= 0x0202; break;
+			case XFER_UDMA_0:
+				drive->id->dma_ultra |= 0x0101; break;
+			case XFER_MW_DMA_2:
+				drive->id->dma_mword |= 0x0404; break;
+			case XFER_MW_DMA_1:
+				drive->id->dma_mword |= 0x0202; break;
+			case XFER_MW_DMA_0:
+				drive->id->dma_mword |= 0x0101; break;
+			case XFER_SW_DMA_2:
+				drive->id->dma_1word |= 0x0404; break;
+			case XFER_SW_DMA_1:
+				drive->id->dma_1word |= 0x0202; break;
+			case XFER_SW_DMA_0:
+				drive->id->dma_1word |= 0x0101; break;
+			default: break;
+		}
+	}
+	enable_irq(hwif->irq);
+	return result;
+}
+
+/* Calculate PIO timings */
+static void __pmac
+pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
+{
+	ide_pio_data_t d;
+	u32 *timings;
+	unsigned accessTicks, recTicks;
+	unsigned accessTime, recTime;
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	
+	if (pmif == NULL)
+		return;
+		
+	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+	accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time);
+	if (drive->select.b.unit & 0x01)
+		timings = &pmif->timings[1];
+	else
+		timings = &pmif->timings[0];
+
+	recTime = d.cycle_time - ide_pio_timings[pio].active_time
+			- ide_pio_timings[pio].setup_time;
+	recTime = max(recTime, 150U);
+	accessTime = ide_pio_timings[pio].active_time;
+	accessTime = max(accessTime, 150U);
+	if (pmif->kind == controller_kl_ata4 ||
+		pmif->kind == controller_kl_ata4_80) {
+		/* 66Mhz cell */
+		accessTicks = SYSCLK_TICKS_66(accessTime);
+		accessTicks = min(accessTicks, 0x1fU);
+		recTicks = SYSCLK_TICKS_66(recTime);
+		recTicks = min(recTicks, 0x1fU);
+		*timings = ((*timings) & ~TR_66_PIO_MASK) |
+				(accessTicks << TR_66_PIO_ACCESS_SHIFT) |
+				(recTicks << TR_66_PIO_RECOVERY_SHIFT);
+	} else {
+		/* 33Mhz cell */
+		int ebit = 0;
+		accessTicks = SYSCLK_TICKS(accessTime);
+		accessTicks = min(accessTicks, 0x1fU);
+		accessTicks = max(accessTicks, 4U);
+		recTicks = SYSCLK_TICKS(recTime);
+		recTicks = min(recTicks, 0x1fU);
+		recTicks = max(recTicks, 5U) - 4;
+		if (recTicks > 9) {
+			recTicks--; /* guess, but it's only for PIO0, so... */
+			ebit = 1;
+		}
+		*timings = ((*timings) & ~TR_33_PIO_MASK) |
+				(accessTicks << TR_33_PIO_ACCESS_SHIFT) |
+				(recTicks << TR_33_PIO_RECOVERY_SHIFT);
+		if (ebit)
+			*timings |= TR_33_PIO_E;
+	}
+
+#ifdef IDE_PMAC_DEBUG
+	printk(KERN_ERR "ide_pmac: Set PIO timing for mode %d, reg: 0x%08x\n",
+		pio,  *timings);
+#endif	
+
+	if (drive->select.all == HWIF(drive)->INB(IDE_SELECT_REG))
+		pmac_ide_selectproc(drive);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+static int __pmac
+set_timings_udma(u32 *timings, u8 speed)
+{
+	unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks;
+
+	rdyToPauseTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].rdy2pause);
+	wrDataSetupTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].wrDataSetup);
+	addrTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].addrSetup);
+
+	*timings = ((*timings) & ~(TR_66_UDMA_MASK | TR_66_MDMA_MASK)) |
+			(wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) | 
+			(rdyToPauseTicks << TR_66_UDMA_RDY2PAUS_SHIFT) |
+			(addrTicks <<TR_66_UDMA_ADDRSETUP_SHIFT) |
+			TR_66_UDMA_EN;
+#ifdef IDE_PMAC_DEBUG
+	printk(KERN_ERR "ide_pmac: Set UDMA timing for mode %d, reg: 0x%08x\n",
+		speed & 0xf,  *timings);
+#endif	
+
+	return 0;
+}
+
+static int __pmac
+set_timings_mdma(int intf_type, u32 *timings, u8 speed, int drive_cycle_time)
+{
+	int cycleTime, accessTime, recTime;
+	unsigned accessTicks, recTicks;
+	struct mdma_timings_t* tm;
+	int i;
+
+	/* Get default cycle time for mode */
+	switch(speed & 0xf) {
+		case 0: cycleTime = 480; break;
+		case 1: cycleTime = 150; break;
+		case 2: cycleTime = 120; break;
+		default:
+			return -1;
+	}
+	/* Adjust for drive */
+	if (drive_cycle_time && drive_cycle_time > cycleTime)
+		cycleTime = drive_cycle_time;
+	/* OHare limits according to some old Apple sources */	
+	if ((intf_type == controller_ohare) && (cycleTime < 150))
+		cycleTime = 150;
+	/* Get the proper timing array for this controller */
+	switch(intf_type) {
+		case controller_kl_ata4:
+		case controller_kl_ata4_80:
+			tm = mdma_timings_66;
+			break;
+		case controller_kl_ata3:
+			tm = mdma_timings_33k;
+			break;
+		default:
+			tm = mdma_timings_33;
+			break;
+	}
+	/* Lookup matching access & recovery times */
+	i = -1;
+	for (;;) {
+		if (tm[i+1].cycleTime < cycleTime)
+			break;
+		i++;
+	}
+	if (i < 0)
+		return -1;
+	cycleTime = tm[i].cycleTime;
+	accessTime = tm[i].accessTime;
+	recTime = tm[i].recoveryTime;
+
+#ifdef IDE_PMAC_DEBUG
+	printk(KERN_ERR "ide_pmac: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n",
+		cycleTime, accessTime, recTime);
+#endif	
+	if (intf_type == controller_kl_ata4 || intf_type == controller_kl_ata4_80) {
+		/* 66Mhz cell */
+		accessTicks = SYSCLK_TICKS_66(accessTime);
+		accessTicks = min(accessTicks, 0x1fU);
+		accessTicks = max(accessTicks, 0x1U);
+		recTicks = SYSCLK_TICKS_66(recTime);
+		recTicks = min(recTicks, 0x1fU);
+		recTicks = max(recTicks, 0x3U);
+		/* Clear out mdma bits and disable udma */
+		*timings = ((*timings) & ~(TR_66_MDMA_MASK | TR_66_UDMA_MASK)) |
+			(accessTicks << TR_66_MDMA_ACCESS_SHIFT) |
+			(recTicks << TR_66_MDMA_RECOVERY_SHIFT);
+	} else if (intf_type == controller_kl_ata3) {
+		/* 33Mhz cell on KeyLargo */
+		accessTicks = SYSCLK_TICKS(accessTime);
+		accessTicks = max(accessTicks, 1U);
+		accessTicks = min(accessTicks, 0x1fU);
+		accessTime = accessTicks * IDE_SYSCLK_NS;
+		recTicks = SYSCLK_TICKS(recTime);
+		recTicks = max(recTicks, 1U);
+		recTicks = min(recTicks, 0x1fU);
+		*timings = ((*timings) & ~TR_33_MDMA_MASK) |
+				(accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
+				(recTicks << TR_33_MDMA_RECOVERY_SHIFT);
+	} else {
+		/* 33Mhz cell on others */
+		int halfTick = 0;
+		int origAccessTime = accessTime;
+		int origRecTime = recTime;
+		
+		accessTicks = SYSCLK_TICKS(accessTime);
+		accessTicks = max(accessTicks, 1U);
+		accessTicks = min(accessTicks, 0x1fU);
+		accessTime = accessTicks * IDE_SYSCLK_NS;
+		recTicks = SYSCLK_TICKS(recTime);
+		recTicks = max(recTicks, 2U) - 1;
+		recTicks = min(recTicks, 0x1fU);
+		recTime = (recTicks + 1) * IDE_SYSCLK_NS;
+		if ((accessTicks > 1) &&
+		    ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
+		    ((recTime - IDE_SYSCLK_NS/2) >= origRecTime)) {
+            		halfTick = 1;
+			accessTicks--;
+		}
+		*timings = ((*timings) & ~TR_33_MDMA_MASK) |
+				(accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
+				(recTicks << TR_33_MDMA_RECOVERY_SHIFT);
+		if (halfTick)
+			*timings |= TR_33_MDMA_HALFTICK;
+	}
+#ifdef IDE_PMAC_DEBUG
+	printk(KERN_ERR "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",
+		speed & 0xf,  *timings);
+#endif	
+	return 0;
+}
+#endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+/* You may notice we don't use this function on normal operation,
+ * our, normal mdma function is supposed to be more precise
+ */
+static int __pmac
+pmac_ide_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	int unit = (drive->select.b.unit & 0x01);
+	int ret = 0;
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	u32 *timings;
+	
+	if (pmif == NULL)
+		return 1;
+
+	timings = &pmif->timings[unit];
+	
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+			if (pmif->kind != controller_kl_ata4_80)
+				return 1;		
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+			if (pmif->kind != controller_kl_ata4 &&
+				pmif->kind != controller_kl_ata4_80)
+				return 1;		
+			ret = set_timings_udma(timings, speed);
+			break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+			ret = set_timings_mdma(pmif->kind, timings, speed, 0);
+			break;
+		case XFER_SW_DMA_2:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+			return 1;
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+			pmac_ide_tuneproc(drive, speed & 0x07);
+			break;
+		default:
+			ret = 1;
+	}
+	if (ret)
+		return ret;
+
+	ret = pmac_ide_do_setfeature(drive, speed);
+	if (ret)
+		return ret;
+		
+	pmac_ide_selectproc(drive);	
+	drive->current_speed = speed;
+
+	return 0;
+}
+
+static void __pmac
+sanitize_timings(pmac_ide_hwif_t *pmif)
+{
+	unsigned value;
+	
+	switch(pmif->kind) {
+		case controller_kl_ata4:
+		case controller_kl_ata4_80:
+			value = 0x0008438c;
+			break;
+		case controller_kl_ata3:
+			value = 0x00084526;
+			break;
+		case controller_heathrow:
+		case controller_ohare:
+		default:
+			value = 0x00074526;
+			break;
+	}
+	pmif->timings[0] = pmif->timings[1] = value;
+}
+
+ide_ioreg_t __pmac
+pmac_ide_get_base(int index)
+{
+	return pmac_ide[index].regbase;
+}
+
+int __pmac
+pmac_ide_check_base(ide_ioreg_t base)
+{
+	int ix;
+	
+ 	for (ix = 0; ix < MAX_HWIFS; ++ix)
+		if (base == pmac_ide[ix].regbase)
+			return ix;
+	return -1;
+}
+
+int __pmac
+pmac_ide_get_irq(ide_ioreg_t base)
+{
+	int ix;
+
+	for (ix = 0; ix < MAX_HWIFS; ++ix)
+		if (base == pmac_ide[ix].regbase)
+			return pmac_ide[ix].irq;
+	return 0;
+}
+
+static int ide_majors[]  __pmacdata = { 3, 22, 33, 34, 56, 57 };
+
+kdev_t __init
+pmac_find_ide_boot(char *bootdevice, int n)
+{
+	int i;
+	
+	/*
+	 * Look through the list of IDE interfaces for this one.
+	 */
+	for (i = 0; i < pmac_ide_count; ++i) {
+		char *name;
+		if (!pmac_ide[i].node || !pmac_ide[i].node->full_name)
+			continue;
+		name = pmac_ide[i].node->full_name;
+		if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) {
+			/* XXX should cope with the 2nd drive as well... */
+			return MKDEV(ide_majors[i], 0);
+		}
+	}
+
+	return 0;
+}
+
+void __init
+pmac_ide_probe(void)
+{
+	struct device_node *np;
+	int i;
+	struct device_node *atas;
+	struct device_node *p, **pp, *removables, **rp;
+	unsigned long base;
+	int irq, big_delay;
+	ide_hwif_t *hwif;
+
+	if (_machine != _MACH_Pmac)
+		return;
+	pp = &atas;
+	rp = &removables;
+	p = find_devices("ATA");
+	if (p == NULL)
+		p = find_devices("IDE");
+	if (p == NULL)
+		p = find_type_devices("ide");
+	if (p == NULL)
+		p = find_type_devices("ata");
+	/* Move removable devices such as the media-bay CDROM
+	   on the PB3400 to the end of the list. */
+	for (; p != NULL; p = p->next) {
+		if (p->parent && p->parent->type
+		    && strcasecmp(p->parent->type, "media-bay") == 0) {
+			*rp = p;
+			rp = &p->next;
+		} else {
+			*pp = p;
+			pp = &p->next;
+		}
+	}
+	*rp = NULL;
+	*pp = removables;
+	big_delay = 0;
+
+	for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) {
+		struct device_node *tp;
+		struct pmac_ide_hwif* pmif;
+		int *bidp;
+		int in_bay = 0;
+		u8 pbus, pid;
+		struct pci_dev *pdev = NULL;
+
+		/*
+		 * If this node is not under a mac-io or dbdma node,
+		 * leave it to the generic PCI driver.
+		 */
+		for (tp = np->parent; tp != 0; tp = tp->parent)
+			if (tp->type && (strcmp(tp->type, "mac-io") == 0
+					 || strcmp(tp->type, "dbdma") == 0))
+				break;
+		if (tp == 0)
+			continue;
+
+		if (np->n_addrs == 0) {
+			printk(KERN_WARNING "ide: no address for device %s\n",
+			       np->full_name);
+			continue;
+		}
+
+		/* We need to find the pci_dev of the mac-io holding the
+		 * IDE interface
+		 */
+		if (pci_device_from_OF_node(tp, &pbus, &pid) == 0)
+			pdev = pci_find_slot(pbus, pid);
+		if (pdev == NULL)
+			printk(KERN_WARNING "ide: no PCI host for device %s, DMA disabled\n",
+			       np->full_name);
+
+		/*
+		 * If this slot is taken (e.g. by ide-pci.c) try the next one.
+		 */
+		while (i < MAX_HWIFS
+		       && ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0)
+			++i;
+		if (i >= MAX_HWIFS)
+			break;
+		pmif = &pmac_ide[i];
+
+		/*
+		 * Some older OFs have bogus sizes, causing request_OF_resource
+		 * to fail. We fix them up here
+		 */
+		if (np->addrs[0].size > 0x1000)
+			np->addrs[0].size = 0x1000;
+		if (np->n_addrs > 1 && np->addrs[1].size > 0x100)
+			np->addrs[1].size = 0x100;
+
+		if (request_OF_resource(np, 0, "  (mac-io IDE IO)") == NULL) {
+			printk(KERN_ERR "ide-pmac(%s): can't request IO resource !\n", np->name);
+			continue;
+		}
+
+		base = (unsigned long) ioremap(np->addrs[0].address, 0x400);
+
+		/* XXX This is bogus. Should be fixed in the registry by checking
+		   the kind of host interrupt controller, a bit like gatwick
+		   fixes in irq.c
+		 */
+		if (np->n_intrs == 0) {
+			printk(KERN_WARNING "ide: no intrs for device %s, using 13\n",
+			       np->full_name);
+			irq = 13;
+		} else {
+			irq = np->intrs[0].line;
+		}
+		pmif->regbase = base;
+		pmif->irq = irq;
+		pmif->node = np;
+		pmif->index = i;
+		if (device_is_compatible(np, "keylargo-ata")) {
+			if (strcmp(np->name, "ata-4") == 0)
+				pmif->kind = controller_kl_ata4;
+			else
+				pmif->kind = controller_kl_ata3;
+		} else if (device_is_compatible(np, "heathrow-ata"))
+			pmif->kind = controller_heathrow;
+		else
+			pmif->kind = controller_ohare;
+
+		bidp = (int *)get_property(np, "AAPL,bus-id", NULL);
+		pmif->aapl_bus_id =  bidp ? *bidp : 0;
+
+		if (pmif->kind == controller_kl_ata4) {
+			char* cable = get_property(np, "cable-type", NULL);
+			if (cable && !strncmp(cable, "80-", 3))
+				pmif->kind = controller_kl_ata4_80;
+		}
+
+		/* Make sure we have sane timings */
+		sanitize_timings(pmif);
+
+		if (np->parent && np->parent->name
+		    && strcasecmp(np->parent->name, "media-bay") == 0) {
+#ifdef CONFIG_PMAC_PBOOK
+			media_bay_set_ide_infos(np->parent,base,irq,i);
+#endif /* CONFIG_PMAC_PBOOK */
+			in_bay = 1;
+			if (!bidp)
+				pmif->aapl_bus_id = 1;
+		} else if (pmif->kind == controller_ohare) {
+			/* The code below is having trouble on some ohare machines
+			 * (timing related ?). Until I can put my hand on one of these
+			 * units, I keep the old way
+			 */
+			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1);
+		} else {
+ 			/* This is necessary to enable IDE when net-booting */
+			printk(KERN_INFO "pmac_ide: enabling IDE bus ID %d\n",
+				pmif->aapl_bus_id);
+			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1);
+			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1);
+			mdelay(10);
+			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0);
+			big_delay = 1;
+		}
+
+		hwif = &ide_hwifs[i];
+		/* Setup MMIO ops */
+		default_hwif_mmiops(hwif);
+		/* Tell common code _not_ to mess with resources */
+		hwif->mmio = 2;
+		hwif->hwif_data = pmif;
+		pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq);
+		memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+		hwif->chipset = ide_pmac;
+		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay;
+		hwif->udma_four = (pmif->kind == controller_kl_ata4_80);
+		hwif->pci_dev = pdev;
+		hwif->drives[0].unmask = 1;
+		hwif->drives[1].unmask = 1;
+		hwif->tuneproc = pmac_ide_tuneproc;
+		hwif->selectproc = pmac_ide_selectproc;
+		hwif->speedproc = pmac_ide_tune_chipset;
+#ifdef CONFIG_PMAC_PBOOK
+		if (in_bay && check_media_bay_by_base(base, MB_CD) == 0)
+			hwif->noprobe = 0;
+#endif /* CONFIG_PMAC_PBOOK */
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+		if (np->n_addrs >= 2) {
+			/* has a DBDMA controller channel */
+			pmac_ide_setup_dma(np, i);
+		}
+		hwif->atapi_dma = 1;
+		hwif->ultra_mask = 0x1f;
+		hwif->mwdma_mask = 0x07;
+		hwif->swdma_mask = 0x07;
+
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+		++i;
+	}
+	pmac_ide_count = i;
+	if (big_delay)
+		mdelay(IDE_WAKEUP_DELAY_MS);
+
+#ifdef CONFIG_PMAC_PBOOK
+	pmu_register_sleep_notifier(&idepmac_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+
+static int
+pmac_ide_build_sglist(ide_hwif_t *hwif, struct request *rq, int data_dir)
+{
+	pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	struct buffer_head *bh;
+	struct scatterlist *sg = pmif->sg_table;
+	int nents = 0;
+
+	if (hwif->sg_dma_active)
+		BUG();
+		
+	bh = rq->bh;
+	do {
+		unsigned char *virt_addr = bh->b_data;
+		unsigned int size = bh->b_size;
+
+		if (nents >= MAX_DCMDS)
+			return 0;
+
+		while ((bh = bh->b_reqnext) != NULL) {
+			if ((virt_addr + size) != (unsigned char *) bh->b_data)
+				break;
+			size += bh->b_size;
+		}
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = size;
+		nents++;
+	} while (bh != NULL);
+
+	pmif->sg_dma_direction = data_dir;
+	return pci_map_sg(hwif->pci_dev, sg, nents, data_dir);
+}
+
+static int
+pmac_ide_raw_build_sglist(ide_hwif_t *hwif, struct request *rq)
+{
+	pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	struct scatterlist *sg = hwif->sg_table;
+	int nents = 0;
+	ide_task_t *args = rq->special;
+	unsigned char *virt_addr = rq->buffer;
+	int sector_count = rq->nr_sectors;
+
+	if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
+		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
+	else
+		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+	
+	if (sector_count > 128) {
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = 128  * SECTOR_SIZE;
+		nents++;
+		virt_addr = virt_addr + (128 * SECTOR_SIZE);
+		sector_count -= 128;
+	}
+	memset(&sg[nents], 0, sizeof(*sg));
+	sg[nents].address = virt_addr;
+	sg[nents].length =  sector_count  * SECTOR_SIZE;
+	nents++;
+   
+	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
+}
+
+/*
+ * pmac_ide_build_dmatable builds the DBDMA command list
+ * for a transfer and sets the DBDMA channel to point to it.
+ */
+static int
+pmac_ide_build_dmatable(ide_drive_t *drive, int wr)
+{
+	struct dbdma_cmd *table;
+	int i, count = 0;
+	struct request *rq = HWGROUP(drive)->rq;
+	ide_hwif_t *hwif = HWIF(drive);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	volatile struct dbdma_regs *dma = pmif->dma_regs;
+	struct scatterlist *sg;
+	int data_dir;
+
+	/* DMA table is already aligned */
+	table = (struct dbdma_cmd *) pmif->dma_table_cpu;
+
+	/* Make sure DMA controller is stopped (necessary ?) */
+	writel((RUN|PAUSE|FLUSH|WAKE|DEAD) << 16, &dma->control);
+	while (readl(&dma->status) & RUN)
+		udelay(1);
+
+	if (wr)
+		data_dir = PCI_DMA_TODEVICE;
+	else
+		data_dir = PCI_DMA_FROMDEVICE;
+
+	/* Build sglist */
+	if (rq->cmd == IDE_DRIVE_TASKFILE)
+		pmif->sg_nents = i = pmac_ide_raw_build_sglist(hwif, rq);
+	else
+		pmif->sg_nents = i = pmac_ide_build_sglist(hwif, rq, data_dir);
+	if (!i)
+		return 0;
+
+	/* Build DBDMA commands list */
+	sg = pmif->sg_table;
+	while (i && sg_dma_len(sg)) {
+		u32 cur_addr;
+		u32 cur_len;
+
+		cur_addr = sg_dma_address(sg);
+		cur_len = sg_dma_len(sg);
+
+		while (cur_len) {
+			unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
+
+			if (++count >= MAX_DCMDS) {
+				printk(KERN_WARNING "%s: DMA table too small\n",
+				       drive->name);
+				return 0; /* revert to PIO for this request */
+			}
+			st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE);
+			st_le16(&table->req_count, tc);
+			st_le32(&table->phy_addr, cur_addr);
+			table->cmd_dep = 0;
+			table->xfer_status = 0;
+			table->res_count = 0;
+			cur_addr += tc;
+			cur_len -= tc;
+			++table;
+		}
+		sg++;
+		i--;
+	}
+
+	/* convert the last command to an input/output last command */
+	if (count)
+		st_le16(&table[-1].command, wr? OUTPUT_LAST: INPUT_LAST);
+	else
+		printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name);
+
+	/* add the stop command to the end of the list */
+	memset(table, 0, sizeof(struct dbdma_cmd));
+	st_le16(&table->command, DBDMA_STOP);
+	mb();
+	writel(pmif->dma_table_dma, &dma->cmdptr);
+	return 1;
+}
+
+/* Teardown mappings after DMA has completed.  */
+static void
+pmac_ide_destroy_dmatable (ide_drive_t *drive)
+{
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	struct scatterlist *sg = pmif->sg_table;
+	int nents = pmif->sg_nents;
+
+	if (nents) {
+		pci_unmap_sg(dev, sg, nents, pmif->sg_dma_direction);
+		pmif->sg_nents = 0;
+	}
+}
+
+static __inline__ unsigned char
+dma_bits_to_command(unsigned char bits)
+{
+	if(bits & 0x04)
+		return XFER_MW_DMA_2;
+	if(bits & 0x02)
+		return XFER_MW_DMA_1;
+	if(bits & 0x01)
+		return XFER_MW_DMA_0;
+	return 0;
+}
+
+static __inline__ unsigned char
+udma_bits_to_command(unsigned char bits, int high_speed)
+{
+	if (high_speed) {
+		if(bits & 0x10)
+			return XFER_UDMA_4;
+		if(bits & 0x08)
+			return XFER_UDMA_3;
+	}
+	if(bits & 0x04)
+		return XFER_UDMA_2;
+	if(bits & 0x02)
+		return XFER_UDMA_1;
+	if(bits & 0x01)
+		return XFER_UDMA_0;
+	return 0;
+}
+
+/* Calculate MultiWord DMA timings */
+static int __pmac
+pmac_ide_mdma_enable(ide_drive_t *drive)
+{
+	u8 bits = drive->id->dma_mword & 0x07;
+	u8 feature = dma_bits_to_command(bits);
+	u32 *timings;
+	int drive_cycle_time;
+	struct hd_driveid *id = drive->id;
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	int ret;
+
+	/* Set feature on drive */
+    	printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf);
+	ret = pmac_ide_do_setfeature(drive, feature);
+	if (ret) {
+	    	printk(KERN_WARNING "%s: Failed !\n", drive->name);
+	    	return 0;
+	}
+
+	if (!drive->init_speed)
+		drive->init_speed = feature;
+	
+	/* which drive is it ? */
+	if (drive->select.b.unit & 0x01)
+		timings = &pmif->timings[1];
+	else
+		timings = &pmif->timings[0];
+
+	/* Check if drive provide explicit cycle time */
+	if ((id->field_valid & 2) && (id->eide_dma_time))
+		drive_cycle_time = id->eide_dma_time;
+	else
+		drive_cycle_time = 0;
+
+	/* Calculate controller timings */
+	set_timings_mdma(pmif->kind, timings, feature, drive_cycle_time);
+
+	drive->current_speed = feature;	
+	return 1;
+}
+
+/* Calculate Ultra DMA timings */
+static int __pmac
+pmac_ide_udma_enable(ide_drive_t *drive, int high_speed)
+{
+	u8 bits = drive->id->dma_ultra & 0x1f;
+	u8 feature = udma_bits_to_command(bits, high_speed);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	u32 *timings;
+	int ret;
+
+	/* Set feature on drive */
+    	printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf);
+	ret = pmac_ide_do_setfeature(drive, feature);
+	if (ret) {
+		printk(KERN_WARNING "%s: Failed !\n", drive->name);
+		return 0;
+	}
+
+	if (!drive->init_speed)
+		drive->init_speed = feature;
+
+	/* which drive is it ? */
+	if (drive->select.b.unit & 0x01)
+		timings = &pmif->timings[1];
+	else
+		timings = &pmif->timings[0];
+
+	set_timings_udma(timings, feature);
+
+	drive->current_speed = feature;	
+	return 1;
+}
+
+int pmac_ide_dma_check(ide_drive_t *drive)
+{
+	int ata4, udma;
+	struct hd_driveid *id = drive->id;
+	ide_hwif_t *hwif = HWIF(drive);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	int enable = 1;
+
+	drive->using_dma = 0;
+	
+	if (pmif == NULL)
+		return 0;
+		
+	if (drive->media == ide_floppy)
+		enable = 0;
+	if (((id->capability & 1) == 0) &&
+	    !HWIF(drive)->ide_dma_good_drive(drive))
+		enable = 0;
+	if (HWIF(drive)->ide_dma_bad_drive(drive))
+		enable = 0;
+	udma = 0;
+	ata4 = (pmif->kind == controller_kl_ata4 ||
+		pmif->kind == controller_kl_ata4_80);
+			
+	if(enable) {
+		if (ata4 && (drive->media == ide_disk) &&
+		    (id->field_valid & 0x0004) && (id->dma_ultra & 0x1f)) {
+			/* UltraDMA modes. */
+			drive->using_dma = pmac_ide_udma_enable(drive,
+				pmif->kind == controller_kl_ata4_80);
+		}
+		if (!drive->using_dma && (id->dma_mword & 0x0007)) {
+			/* Normal MultiWord DMA modes. */
+			drive->using_dma = pmac_ide_mdma_enable(drive);
+		}
+		hwif->OUTB(0, IDE_CONTROL_REG);
+		/* Apply settings to controller */
+		pmac_ide_selectproc(drive);
+	}
+	return 0;
+}
+
+static int
+pmac_ide_dma_read (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	struct request *rq = HWGROUP(drive)->rq;
+//	ide_task_t *args = rq->special;
+	u8 unit = (drive->select.b.unit & 0x01);
+	u8 ata4;
+	u8 lba48 = (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command = WIN_NOP;
+
+	if (pmif == NULL)
+		return 1;
+
+	ata4 = (pmif->kind == controller_kl_ata4 ||
+		pmif->kind == controller_kl_ata4_80);
+
+	if (!pmac_ide_build_dmatable(drive, 0))
+		return 1;
+	/* Apple adds 60ns to wrDataSetup on reads */
+	if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) {
+		writel(pmif->timings[unit]+0x00800000UL,
+			(unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
+		(void)readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG));
+	}
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA;
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
+
+	return pmac_ide_dma_begin(drive);
+}
+
+static int
+pmac_ide_dma_write (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	struct request *rq = HWGROUP(drive)->rq;
+//	ide_task_t *args = rq->special;
+	u8 unit = (drive->select.b.unit & 0x01);
+	u8 ata4;
+	u8 lba48 = (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command = WIN_NOP;
+
+	if (pmif == NULL)
+		return 1;
+
+	ata4 = (pmif->kind == controller_kl_ata4 ||
+		pmif->kind == controller_kl_ata4_80);
+
+	if (!pmac_ide_build_dmatable(drive, 1))
+		return 1;
+	/* Apple adds 60ns to wrDataSetup on reads */
+	if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) {
+		writel(pmif->timings[unit],
+			(unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
+		(void)readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG));
+	}
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
+
+	return pmac_ide_dma_begin(drive);
+}
+
+static int
+pmac_ide_dma_count (ide_drive_t *drive)
+{
+	return HWIF(drive)->ide_dma_begin(drive);
+}
+
+static int
+pmac_ide_dma_begin (ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	volatile struct dbdma_regs *dma;
+
+	if (pmif == NULL)
+		return 1;
+	dma = pmif->dma_regs;
+
+	writel((RUN << 16) | RUN, &dma->control);
+	/* Make sure it gets to the controller right now */
+	(void)readl(&dma->control);
+	return 0;
+}
+
+static int
+pmac_ide_dma_end (ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	volatile struct dbdma_regs *dma;
+	u32 dstat;
+	
+	if (pmif == NULL)
+		return 0;
+	dma = pmif->dma_regs;
+
+	drive->waiting_for_dma = 0;
+	dstat = readl(&dma->status);
+	writel(((RUN|WAKE|DEAD) << 16), &dma->control);
+	pmac_ide_destroy_dmatable(drive);
+	/* verify good dma status */
+	return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
+}
+
+static int
+pmac_ide_dma_test_irq (ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	volatile struct dbdma_regs *dma;
+	unsigned long status;
+
+	if (pmif == NULL)
+		return 0;
+	dma = pmif->dma_regs;
+
+	/* We have to things to deal with here:
+	 * 
+	 * - The dbdma won't stop if the command was started
+	 * but completed with an error without transfering all
+	 * datas. This happens when bad blocks are met during
+	 * a multi-block transfer.
+	 * 
+	 * - The dbdma fifo hasn't yet finished flushing to
+	 * to system memory when the disk interrupt occurs.
+	 * 
+	 * The trick here is to increment drive->waiting_for_dma,
+	 * and return as if no interrupt occured. If the counter
+	 * reach a certain timeout value, we then return 1. If
+	 * we really got the interrupt, it will happen right away
+	 * again.
+	 * Apple's solution here may be more elegant. They issue
+	 * a DMA channel interrupt (a separate irq line) via a DBDMA
+	 * NOP command just before the STOP, and wait for both the
+	 * disk and DBDMA interrupts to have completed.
+	 */
+ 
+	/* If ACTIVE is cleared, the STOP command have passed and
+	 * transfer is complete.
+	 */
+	status = readl(&dma->status);
+	if (!(status & ACTIVE))
+		return 1;
+	if (!drive->waiting_for_dma)
+		printk(KERN_WARNING "ide%d, ide_dma_test_irq \
+			called while not waiting\n", pmif->index);
+
+	/* If dbdma didn't execute the STOP command yet, the
+	 * active bit is still set */
+	drive->waiting_for_dma++;
+	if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
+		printk(KERN_WARNING "ide%d, timeout waiting \
+			for dbdma command stop\n", pmif->index);
+		return 1;
+	}
+	udelay(1);
+	return 0;
+}
+
+static int
+pmac_ide_dma_host_off (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int
+pmac_ide_dma_host_on (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int
+pmac_ide_dma_lostirq (ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	volatile struct dbdma_regs *dma;
+	unsigned long status;
+
+	if (pmif == NULL)
+		return 0;
+	dma = pmif->dma_regs;
+
+	status = readl(&dma->status);
+	printk(KERN_ERR "ide-pmac lost interrupt, dma status: %lx\n", status);
+	return 0;
+}
+
+static void __init 
+pmac_ide_setup_dma(struct device_node *np, int ix)
+{
+	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
+
+	if (request_OF_resource(np, 1, " (mac-io IDE DMA)") == NULL) {
+		printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n", np->name);
+		return;
+	}
+
+	pmif->dma_regs =
+		(volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200);
+
+	/*
+	 * Allocate space for the DBDMA commands.
+	 * The +2 is +1 for the stop command and +1 to allow for
+	 * aligning the start address to a multiple of 16 bytes.
+	 */
+	pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent(
+		ide_hwifs[ix].pci_dev,
+		(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
+		&pmif->dma_table_dma);
+	if (pmif->dma_table_cpu == NULL) {
+		printk(KERN_ERR "%s: unable to allocate DMA command list\n",
+		       ide_hwifs[ix].name);
+		return;
+	}
+
+	pmif->sg_table = kmalloc(sizeof(struct scatterlist) * MAX_DCMDS,
+				 GFP_KERNEL);
+	if (pmif->sg_table == NULL) {
+		pci_free_consistent(	ide_hwifs[ix].pci_dev,
+					(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
+				    	pmif->dma_table_cpu, pmif->dma_table_dma);
+		return;
+	}
+	ide_hwifs[ix].ide_dma_off = &__ide_dma_off;
+	ide_hwifs[ix].ide_dma_off_quietly = &__ide_dma_off_quietly;
+	ide_hwifs[ix].ide_dma_on = &__ide_dma_on;
+	ide_hwifs[ix].ide_dma_check = &pmac_ide_dma_check;
+	ide_hwifs[ix].ide_dma_read = &pmac_ide_dma_read;
+	ide_hwifs[ix].ide_dma_write = &pmac_ide_dma_write;
+	ide_hwifs[ix].ide_dma_count = &pmac_ide_dma_count;
+	ide_hwifs[ix].ide_dma_begin = &pmac_ide_dma_begin;
+	ide_hwifs[ix].ide_dma_end = &pmac_ide_dma_end;
+	ide_hwifs[ix].ide_dma_test_irq = &pmac_ide_dma_test_irq;
+	ide_hwifs[ix].ide_dma_host_off = &pmac_ide_dma_host_off;
+	ide_hwifs[ix].ide_dma_host_on = &pmac_ide_dma_host_on;
+	ide_hwifs[ix].ide_dma_good_drive = &__ide_dma_good_drive;
+	ide_hwifs[ix].ide_dma_bad_drive = &__ide_dma_bad_drive;
+	ide_hwifs[ix].ide_dma_verbose = &__ide_dma_verbose;
+	ide_hwifs[ix].ide_dma_timeout = &__ide_dma_timeout;
+	ide_hwifs[ix].ide_dma_retune = &__ide_dma_retune;
+	ide_hwifs[ix].ide_dma_lostirq = &pmac_ide_dma_lostirq;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
+	if (!noautodma)
+		ide_hwifs[ix].autodma = 1;
+#endif
+	ide_hwifs[ix].drives[0].autodma = ide_hwifs[ix].autodma;
+	ide_hwifs[ix].drives[1].autodma = ide_hwifs[ix].autodma;
+}
+
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+static void __pmac
+idepmac_sleep_device(ide_drive_t *drive, unsigned base)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	int j;
+	
+	/* FIXME: We only handle the master IDE disk, we shoud
+	 *        try to fix CD-ROMs here
+	 */
+	switch (drive->media) {
+	case ide_disk:
+		/* Spin down the drive */
+		hwif->OUTB(drive->select.all, base+0x60);
+		(void) hwif->INB(base+0x60);
+		udelay(100);
+		hwif->OUTB(0x0, base+0x30);
+		hwif->OUTB(0x0, base+0x20);
+		hwif->OUTB(0x0, base+0x40);
+		hwif->OUTB(0x0, base+0x50);
+		hwif->OUTB(0xe0, base+0x70);
+		hwif->OUTB(0x2, base+0x160);   
+		for (j = 0; j < 10; j++) {
+			u8 status;
+			mdelay(100);
+			status = hwif->INB(base+0x70);
+			if (!(status & BUSY_STAT) && (status & DRQ_STAT))
+				break;
+		}
+		break;
+	case ide_cdrom:
+		// todo
+		break;
+	case ide_floppy:
+		// todo
+		break;
+	}
+}
+
+#ifdef CONFIG_PMAC_PBOOK
+static void __pmac
+idepmac_wake_device(ide_drive_t *drive, int used_dma)
+{
+	/* We force the IDE subdriver to check for a media change
+	 * This must be done first or we may lost the condition
+	 *
+	 * Problem: This can schedule. I moved the block device
+	 * wakeup almost late by priority because of that.
+	 */
+	if (DRIVER(drive) && DRIVER(drive)->media_change)
+		DRIVER(drive)->media_change(drive);
+
+	/* We kick the VFS too (see fix in ide.c revalidate) */
+	check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS));
+	
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+	/* We re-enable DMA on the drive if it was active. */
+	/* This doesn't work with the CD-ROM in the media-bay, probably
+	 * because of a pending unit attention. The problem if that if I
+	 * clear the error, the filesystem dies.
+	 */
+	if (used_dma && !ide_spin_wait_hwgroup(drive)) {
+		/* Lock HW group */
+		HWGROUP(drive)->busy = 1;
+		pmac_ide_dma_check(drive);
+		HWGROUP(drive)->busy = 0;
+		if (!list_empty(&drive->queue.queue_head))
+			ide_do_request(HWGROUP(drive), 0);
+		spin_unlock_irq(&io_request_lock);
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+}
+
+static void __pmac
+idepmac_sleep_interface(pmac_ide_hwif_t *pmif, unsigned base, int mediabay)
+{
+	struct device_node* np = pmif->node;
+
+	/* We clear the timings */
+	pmif->timings[0] = 0;
+	pmif->timings[1] = 0;
+	
+	/* The media bay will handle itself just fine */
+	if (mediabay)
+		return;
+	
+	/* Disable the bus */
+	ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 0);
+}
+
+static void __pmac
+idepmac_wake_interface(pmac_ide_hwif_t *pmif, unsigned long base, int mediabay)
+{
+	struct device_node* np = pmif->node;
+
+	if (!mediabay) {
+		/* Revive IDE disk and controller */
+		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1);
+		ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1);
+		mdelay(10);
+		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0);
+	}
+}
+
+static void
+idepmac_sleep_drive(ide_drive_t *drive, unsigned long base)
+{
+	int unlock = 0;
+
+	/* Wait for HW group to complete operations */
+	if (ide_spin_wait_hwgroup(drive)) {
+		// What can we do here ? Wake drive we had already
+		// put to sleep and return an error ?
+	} else {
+		unlock = 1;
+		/* Lock HW group */
+		HWGROUP(drive)->busy = 1;
+		/* Stop the device */
+		idepmac_sleep_device(drive, base);
+	}
+	if (unlock)
+		spin_unlock_irq(&io_request_lock);
+}
+
+static void
+idepmac_wake_drive(ide_drive_t *drive, unsigned long base)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long flags;
+	int j;
+	
+	/* Reset timings */
+	pmac_ide_selectproc(drive);
+	mdelay(10);
+	
+	/* Wait up to 20 seconds for the drive to be ready */
+	for (j = 0; j < 200; j++) {
+		u8 status = 0;
+		mdelay(100);
+		hwif->OUTB(drive->select.all, base + 0x60);
+		if ((hwif->INB(base + 0x60)) != drive->select.all)
+			continue;
+		status = hwif->INB(base + 0x70);
+		if (!(status & BUSY_STAT))
+			break;
+	}
+
+	/* We resume processing on the HW group */
+	spin_lock_irqsave(&io_request_lock, flags);
+	HWGROUP(drive)->busy = 0;
+	if (!list_empty(&drive->queue.queue_head))
+		ide_do_request(HWGROUP(drive), 0);
+	spin_unlock_irqrestore(&io_request_lock, flags);			
+}
+
+/* Note: We support only master drives for now. This will have to be
+ * improved if we want to handle sleep on the iMacDV where the CD-ROM
+ * is a slave
+ */
+static int __pmac
+idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
+{
+	int i, ret;
+	unsigned long base;
+	int big_delay;
+ 
+	switch (when) {
+	case PBOOK_SLEEP_REQUEST:
+		break;
+	case PBOOK_SLEEP_REJECT:
+		break;
+	case PBOOK_SLEEP_NOW:
+		for (i = 0; i < pmac_ide_count; ++i) {
+			ide_hwif_t *hwif;
+			int dn;
+
+			if ((base = pmac_ide[i].regbase) == 0)
+				continue;
+
+			hwif = &ide_hwifs[i];
+			for (dn=0; dn<MAX_DRIVES; dn++) {
+				if (!hwif->drives[dn].present)
+					continue;
+				idepmac_sleep_drive(&hwif->drives[dn], base);
+			}
+			/* Disable irq during sleep */
+			disable_irq(pmac_ide[i].irq);
+			
+			/* Check if this is a media bay with an IDE device or not
+			 * a media bay.
+			 */
+			ret = check_media_bay_by_base(base, MB_CD);
+			if ((ret == 0) || (ret == -ENODEV))
+				idepmac_sleep_interface(&pmac_ide[i], base, (ret == 0));
+		}
+		break;
+	case PBOOK_WAKE:
+		big_delay = 0;
+		for (i = 0; i < pmac_ide_count; ++i) {
+
+			if ((base = pmac_ide[i].regbase) == 0)
+				continue;
+				
+			/* Make sure we have sane timings */		
+			sanitize_timings(&pmac_ide[i]);
+
+			/* Check if this is a media bay with an IDE device or not
+			 * a media bay
+			 */
+			ret = check_media_bay_by_base(base, MB_CD);
+			if ((ret == 0) || (ret == -ENODEV)) {
+				idepmac_wake_interface(&pmac_ide[i], base, (ret == 0));				
+				big_delay = 1;
+			}
+
+		}
+		/* Let hardware get up to speed */
+		if (big_delay)
+			mdelay(IDE_WAKEUP_DELAY_MS);
+	
+		for (i = 0; i < pmac_ide_count; ++i) {
+			ide_hwif_t *hwif;
+			int used_dma, dn;
+			int irq_on = 0;
+			
+			if ((base = pmac_ide[i].regbase) == 0)
+				continue;
+				
+			hwif = &ide_hwifs[i];
+			for (dn=0; dn<MAX_DRIVES; dn++) {
+				ide_drive_t *drive = &hwif->drives[dn];
+				if (!drive->present)
+					continue;
+				/* We don't have re-configured DMA yet */
+				used_dma = drive->using_dma;
+				drive->using_dma = 0;
+				idepmac_wake_drive(drive, base);
+				if (!irq_on) {
+					enable_irq(pmac_ide[i].irq);
+					irq_on = 1;
+				}
+				idepmac_wake_device(drive, used_dma);
+			}
+			if (!irq_on)
+				enable_irq(pmac_ide[i].irq);
+		}
+		break;
+	}
+	return PBOOK_SLEEP_OK;
+}
+#endif /* CONFIG_PMAC_PBOOK */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ppc/swarm.c linux-2.4.21/drivers/ide/ppc/swarm.c
--- linux-2.4.20/drivers/ide/ppc/swarm.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/ppc/swarm.c	2002-12-18 18:58:11.000000000 +0000
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2001 Broadcom 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.  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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/*  Derived loosely from ide-pmac.c, so:
+ *  
+ *  Copyright (C) 1998 Paul Mackerras.
+ *  Copyright (C) 1995-1998 Mark Lord
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/sibyte/sb1250_int.h>
+
+#define __IDE_SWARM_C
+
+#include <asm/sibyte/swarm_ide.h>
+
+void __init swarm_ide_probe(void)
+{
+	int i;
+	ide_hwif_t *hwif;
+	/* 
+	 * Find the first untaken slot in hwifs 
+	 */
+	for (i = 0; i < MAX_HWIFS; i++) {
+		if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET]) {
+			break;
+		}
+	}
+	if (i == MAX_HWIFS) {
+		printk("No space for SWARM onboard IDE driver in ide_hwifs[].  Not enabled.\n");
+		return;
+	}
+
+	/* Set up our stuff */
+	hwif = &ide_hwifs[i];
+	hwif->hw.io_ports[IDE_DATA_OFFSET]    = SWARM_IDE_REG(0x1f0);
+	hwif->hw.io_ports[IDE_ERROR_OFFSET]   = SWARM_IDE_REG(0x1f1);
+	hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SWARM_IDE_REG(0x1f2);
+	hwif->hw.io_ports[IDE_SECTOR_OFFSET]  = SWARM_IDE_REG(0x1f3);
+	hwif->hw.io_ports[IDE_LCYL_OFFSET]    = SWARM_IDE_REG(0x1f4);
+	hwif->hw.io_ports[IDE_HCYL_OFFSET]    = SWARM_IDE_REG(0x1f5);
+	hwif->hw.io_ports[IDE_SELECT_OFFSET]  = SWARM_IDE_REG(0x1f6);
+	hwif->hw.io_ports[IDE_STATUS_OFFSET]  = SWARM_IDE_REG(0x1f7);
+	hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SWARM_IDE_REG(0x3f6);
+	hwif->hw.io_ports[IDE_IRQ_OFFSET]     = SWARM_IDE_REG(0x3f7);
+//	hwif->hw->ack_intr                    = swarm_ide_ack_intr;
+	hwif->hw.irq                          = SWARM_IDE_INT;
+#if 0
+	hwif->iops                            = swarm_iops;
+#else
+	hwif->OUTB      = hwif->OUTBP         = swarm_outb;
+	hwif->OUTW      = hwif->OUTWP         = swarm_outw;
+	hwif->OUTL      = hwif->OUTLP         = swarm_outl;
+	hwif->OUTSW     = hwif->OUTSWP        = swarm_outsw;
+	hwif->OUTSL     = hwif->OUTSLP        = swarm_outsl;
+	hwif->INB       = hwif->INBP          = swarm_inb;
+	hwif->INW       = hwif->INWP          = swarm_inw;
+	hwif->INL       = hwif->INLP          = swarm_inl;
+	hwif->INSW      = hwif->INSWP         = swarm_insw;
+	hwif->INSL      = hwif->INSLP         = swarm_insl;
+#endif
+#if 0
+	hwif->pioops                          = swarm_pio_ops;
+#else
+	hwif->ata_input_data                  = swarm_ata_input_data;
+	hwif->ata_output_data                 = swarm_ata_output_data;
+	hwif->atapi_input_bytes               = swarm_atapi_input_bytes;
+	hwif->atapi_output_bytes              = swarm_atapi_output_bytes;
+#endif
+	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+	hwif->irq                             = hwif->hw.irq;
+	printk("SWARM onboard IDE configured as device %i\n", i);
+
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(hwif->index);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/q40ide.c linux-2.4.21/drivers/ide/q40ide.c
--- linux-2.4.20/drivers/ide/q40ide.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ide/q40ide.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,91 +0,0 @@
-/*
- *  linux/drivers/ide/q40ide.c -- Q40 I/O port IDE Driver
- *
- *     (c) Richard Zidlicky
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- *
- *
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/ide.h>
-
-    /*
-     *  Bases of the IDE interfaces
-     */
-
-#define Q40IDE_NUM_HWIFS	2
-
-#define PCIDE_BASE1	0x1f0
-#define PCIDE_BASE2	0x170
-#define PCIDE_BASE3	0x1e8
-#define PCIDE_BASE4	0x168
-#define PCIDE_BASE5	0x1e0
-#define PCIDE_BASE6	0x160
-
-static const q40ide_ioreg_t pcide_bases[Q40IDE_NUM_HWIFS] = {
-    PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4  , PCIDE_BASE5,
-    PCIDE_BASE6 */
-};
-
-
-    /*
-     *  Offsets from one of the above bases
-     */
-
-
-/* HD_DATA was redefined in asm-m68k/ide.h */
-#undef HD_DATA
-#define HD_DATA  0x1f0
-
-
-#define PCIDE_REG(x)	((q40ide_ioreg_t)(HD_##x-PCIDE_BASE1))
-
-static const int pcide_offsets[IDE_NR_PORTS] = {
-    PCIDE_REG(DATA), PCIDE_REG(ERROR), PCIDE_REG(NSECTOR), PCIDE_REG(SECTOR),
-    PCIDE_REG(LCYL), PCIDE_REG(HCYL), PCIDE_REG(CURRENT), PCIDE_REG(STATUS),
-    PCIDE_REG(CMD)
-};
-
-static int q40ide_default_irq(q40ide_ioreg_t base)
-{
-           switch (base) { 
-	            case 0x1f0: return 14;
-		    case 0x170: return 15;
-		    case 0x1e8: return 11;
-		    default:
-			return 0;
-	   }
-}
-
-
-
-    /*
-     *  Probe for Q40 IDE interfaces
-     */
-
-void q40ide_init(void)
-{
-    int i;
-
-    if (!MACH_IS_Q40)
-      return ;
-
-    for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
-	hw_regs_t hw;
-
-	ide_setup_ports(&hw, (ide_ioreg_t)pcide_bases[i], (int *)pcide_offsets,
-			(ide_ioreg_t)pcide_bases[i]+0x206,
-			0, NULL, q40ide_default_irq(pcide_bases[i]));
-	ide_register_hw(&hw, NULL);
-    }
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/qd65xx.c linux-2.4.21/drivers/ide/qd65xx.c
--- linux-2.4.20/drivers/ide/qd65xx.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/qd65xx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,456 +0,0 @@
-/*
- *  linux/drivers/ide/qd65xx.c		Version 0.07	Sep 30, 2001
- *
- *  Copyright (C) 1996-2001  Linus Torvalds & author (see below)
- */
-
-/*
- *  Version 0.03	Cleaned auto-tune, added probe
- *  Version 0.04	Added second channel tuning
- *  Version 0.05	Enhanced tuning ; added qd6500 support
- *  Version 0.06	Added dos driver's list
- *  Version 0.07	Second channel bug fix 
- *
- * QDI QD6500/QD6580 EIDE controller fast support
- *
- * Please set local bus speed using kernel parameter idebus
- * 	for example, "idebus=33" stands for 33Mhz VLbus
- * To activate controller support, use "ide0=qd65xx"
- * To enable tuning, use "ide0=autotune"
- * To enable second channel tuning (qd6580 only), use "ide1=autotune"
- */
-
-/*
- * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
- * Samuel Thibault <samuel.thibault@fnac.net>
- */
-
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <asm/io.h>
-
-#include "ide_modes.h"
-#include "qd65xx.h"
-
-/*
- * I/O ports are 0x30-0x31 (and 0x32-0x33 for qd6580)
- *            or 0xb0-0xb1 (and 0xb2-0xb3 for qd6580)
- *	-- qd6500 is a single IDE interface
- *	-- qd6580 is a dual IDE interface
- *
- * More research on qd6580 being done by willmore@cig.mot.com (David)
- * More Information given by Petr Soucek (petr@ryston.cz)
- * http://www.ryston.cz/petr/vlb
- */
-
-/*
- * base: Timer1
- *
- *
- * base+0x01: Config (R/O)
- *
- * bit 0: ide baseport: 1 = 0x1f0 ; 0 = 0x170 (only useful for qd6500)
- * bit 1: qd65xx baseport: 1 = 0xb0 ; 0 = 0x30
- * bit 2: ID3: bus speed: 1 = <=33MHz ; 0 = >33MHz
- * bit 3: qd6500: 1 = disabled, 0 = enabled
- *        qd6580: 1
- * upper nibble:
- *        qd6500: 1100
- *        qd6580: either 1010 or 0101
- *
- *
- * base+0x02: Timer2 (qd6580 only)
- *
- *
- * base+0x03: Control (qd6580 only)
- *
- * bits 0-3 must always be set 1
- * bit 4 must be set 1, but is set 0 by dos driver while measuring vlb clock
- * bit 0 : 1 = Only primary port enabled : channel 0 for hda, channel 1 for hdb
- *         0 = Primary and Secondary ports enabled : channel 0 for hda & hdb
- *                                                   channel 1 for hdc & hdd
- * bit 1 : 1 = only disks on primary port
- *         0 = disks & ATAPI devices on primary port
- * bit 2-4 : always 0
- * bit 5 : status, but of what ?
- * bit 6 : always set 1 by dos driver
- * bit 7 : set 1 for non-ATAPI devices on primary port
- * 	(maybe read-ahead and post-write buffer ?)
- */
-
-static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */
-
-static void qd_write_reg (byte content, byte reg)
-{
-	unsigned long flags;
-
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-	outb(content,reg);
-	restore_flags(flags);	/* all CPUs */
-}
-
-byte __init qd_read_reg (byte reg)
-{
-	unsigned long flags;
-	byte read;
-
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-	read = inb(reg);
-	restore_flags(flags);	/* all CPUs */
-	return read;
-}
-
-/*
- * qd_select:
- *
- * This routine is invoked from ide.c to prepare for access to a given drive.
- */
-
-static void qd_select (ide_drive_t *drive)
-{
-	byte index = (( (QD_TIMREG(drive)) & 0x80 ) >> 7) |
-			(QD_TIMREG(drive) & 0x02);
-
-	if (timings[index] != QD_TIMING(drive))
-		qd_write_reg(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
-}
-
-/*
- * qd6500_compute_timing
- *
- * computes the timing value where
- * 	lower nibble represents active time,   in count of VLB clocks
- * 	upper nibble represents recovery time, in count of VLB clocks
- */
-
-static byte qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time)
-{
-	byte active_cycle,recovery_cycle;
-
-	if (ide_system_bus_speed()<=33) {
-		active_cycle =   9  - IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 2, 9);
-		recovery_cycle = 15 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 0, 15);
-	} else {
-		active_cycle =   8  - IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 1, 8);
-		recovery_cycle = 18 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 3, 18);
-	}
-
-	return((recovery_cycle<<4) | 0x08 | active_cycle);
-}
-
-/*
- * qd6580_compute_timing
- *
- * idem for qd6580
- */
-
-static byte qd6580_compute_timing (int active_time, int recovery_time)
-{
-	byte active_cycle   = 17-IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 2, 17);
-	byte recovery_cycle = 15-IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 2, 15);
-
-	return((recovery_cycle<<4) | active_cycle);
-}
-
-/*
- * qd_find_disk_type
- *
- * tries to find timing from dos driver's table
- */
-
-static int qd_find_disk_type (ide_drive_t *drive,
-		int *active_time, int *recovery_time)
-{
-	struct qd65xx_timing_s *p;
-	char model[40];
-
-	if (!*drive->id->model) return 0;
-
-	strncpy(model,drive->id->model,40);
-	ide_fixstring(model,40,1); /* byte-swap */
-
-	for (p = qd65xx_timing ; p->offset != -1 ; p++) {
-		if (!strncmp(p->model, model+p->offset,4)) {
-			printk(KERN_DEBUG "%s: listed !\n",drive->name);
-			*active_time = p->active;
-			*recovery_time = p->recovery;
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- * qd_timing_ok:
- *
- * check whether timings don't conflict
- */
-
-static int qd_timing_ok (ide_drive_t drives[])
-{
-	return (IDE_IMPLY(drives[0].present && drives[1].present,
-			IDE_IMPLY(QD_TIMREG(drives) == QD_TIMREG(drives+1),
-			          QD_TIMING(drives) == QD_TIMING(drives+1))));
-	/* if same timing register, must be same timing */
-}
-
-/*
- * qd_set_timing:
- *
- * records the timing, and enables selectproc as needed
- */
-
-static void qd_set_timing (ide_drive_t *drive, byte timing)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-
-	drive->drive_data &= 0xff00;
-	drive->drive_data |= timing;
-	if (qd_timing_ok(hwif->drives)) {
-		qd_select(drive); /* selects once */
-		hwif->selectproc = NULL;
-	} else
-		hwif->selectproc = &qd_select;
-
-	printk(KERN_DEBUG "%s: %#x\n",drive->name,timing);
-}
-
-/*
- * qd6500_tune_drive
- */
-
-static void qd6500_tune_drive (ide_drive_t *drive, byte pio)
-{
-	int active_time   = 175;
-	int recovery_time = 415; /* worst case values from the dos driver */
-
-	if (drive->id && !qd_find_disk_type(drive,&active_time,&recovery_time)
-		&& drive->id->tPIO && (drive->id->field_valid & 0x02)
-		&& drive->id->eide_pio >= 240) {
-
-		printk(KERN_INFO "%s: PIO mode%d\n", drive->name,
-				drive->id->tPIO);
-		active_time = 110;
-		recovery_time = drive->id->eide_pio - 120;
-	}
-
-	qd_set_timing(drive,qd6500_compute_timing(HWIF(drive),active_time,recovery_time));
-}
-
-/*
- * qd6580_tune_drive
- */
-
-static void qd6580_tune_drive (ide_drive_t *drive, byte pio)
-{
-	ide_pio_data_t d;
-	int base = HWIF(drive)->select_data;
-	int active_time   = 175;
-	int recovery_time = 415; /* worst case values from the dos driver */
-
-	if (drive->id && !qd_find_disk_type(drive,&active_time,&recovery_time)) {
-		pio = ide_get_best_pio_mode(drive, pio, 255, &d);
-		pio = IDE_MIN(pio,4);
-
-		switch (pio) {
-			case 0: break;
-			case 3:
-				if (d.cycle_time >= 110) {
-					active_time = 86;
-					recovery_time = d.cycle_time-102;
-				} else
-					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
-				break;
-			case 4:
-				if (d.cycle_time >= 69) {
-					active_time = 70;
-					recovery_time = d.cycle_time-61;
-				} else
-					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
-				break;
-			default:
-				if (d.cycle_time >= 180) {
-					active_time = 110;
-					recovery_time = d.cycle_time - 120;
-				} else {
-					active_time = ide_pio_timings[pio].active_time;
-					recovery_time = d.cycle_time
-							-active_time;
-				}
-		}
-		printk(KERN_INFO "%s: PIO mode%d\n",drive->name,pio);
-	}
-
-	if (!HWIF(drive)->channel && drive->media != ide_disk) {
-		qd_write_reg(0x5f,QD_CONTROL_PORT);
-		printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO and post-write buffer on %s.\n",drive->name,HWIF(drive)->name);
-	}
-
-	qd_set_timing(drive,qd6580_compute_timing(active_time,recovery_time));
-}
-
-/*
- * qd_testreg
- *
- * tests if the given port is a register
- */
-
-static int __init qd_testreg(int port)
-{
-	byte savereg;
-	byte readreg;
-	unsigned long flags;
-
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-	savereg = inb_p(port);
-	outb_p(QD_TESTVAL,port);	/* safe value */
-	readreg = inb_p(port);
-	outb(savereg,port);
-	restore_flags(flags);	/* all CPUs */
-
-	if (savereg == QD_TESTVAL) {
-		printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n");
-		printk(KERN_ERR "Please contact maintainers to tell about your hardware\n");
-		printk(KERN_ERR "Assuming qd65xx is not present.\n");
-		return 1;
-	}
-
-	return (readreg != QD_TESTVAL);
-}
-
-/*
- * probe:
- *
- * looks at the specified baseport, and if qd found, registers & initialises it
- * return 1 if another qd may be probed
- */
-
-int __init probe (int base)
-{
-	byte config;
-	byte index;
-
-	config = qd_read_reg(QD_CONFIG_PORT);
-
-	if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) ) return 1;
-
-	index = ! (config & QD_CONFIG_IDE_BASEPORT);
-
-	if ((config & 0xf0) == QD_CONFIG_QD6500) {
-		ide_hwif_t *hwif = &ide_hwifs[index];
-
-		if (qd_testreg(base)) return 1;		/* bad register */
-
-			/* qd6500 found */
-
-		printk(KERN_NOTICE "%s: qd6500 at %#x\n",
-			ide_hwifs[index].name, base);
-		
-		printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
-			config, QD_ID3);
-		
-		if (config & QD_CONFIG_DISABLED) {
-			printk(KERN_WARNING "qd6500 is disabled !\n");
-			return 1;
-		}
-
-		hwif->chipset = ide_qd65xx;
-		hwif->select_data = base;
-		hwif->config_data = config;
-		hwif->drives[0].drive_data =
-		hwif->drives[1].drive_data = QD6500_DEF_DATA;
-		hwif->drives[0].io_32bit =
-		hwif->drives[1].io_32bit = 1;
-		hwif->tuneproc = &qd6500_tune_drive;
-		return 1;
-	}
-
-	if (((config & 0xf0) == QD_CONFIG_QD6580_A) || ((config & 0xf0) == QD_CONFIG_QD6580_B)) {
-
-		byte control;
-
-		if (qd_testreg(base) || qd_testreg(base+0x02)) return 1;
-			/* bad registers */
-
-			/* qd6580 found */
-
-		control = qd_read_reg(QD_CONTROL_PORT);
-
-		printk(KERN_NOTICE "qd6580 at %#x\n", base);
-		printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n",
-			config, control, QD_ID3);
-
-		if (control & QD_CONTR_SEC_DISABLED) {
-			ide_hwif_t *hwif = &ide_hwifs[index];
-
-			/* secondary disabled */
-			printk(KERN_INFO "%s: qd6580: single IDE board\n",
-					ide_hwifs[index].name);
-
-			hwif->chipset = ide_qd65xx;
-			hwif->select_data = base;
-			hwif->config_data = config | (control <<8);
-			hwif->drives[0].drive_data =
-			hwif->drives[1].drive_data = QD6580_DEF_DATA;
-			hwif->drives[0].io_32bit =
-			hwif->drives[1].io_32bit = 1;
-			hwif->tuneproc = &qd6580_tune_drive;
-
-			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
-
-			return 1;
-		} else {
-			int i,j;
-			/* secondary enabled */
-			printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n",
-					ide_hwifs[0].name,ide_hwifs[1].name);
-
-			for (i=0;i<2;i++) {
-
-				ide_hwifs[i].chipset = ide_qd65xx;
-				ide_hwifs[i].mate = &ide_hwifs[i^1];
-				ide_hwifs[i].channel = i;
-
-				ide_hwifs[i].select_data = base;
-				ide_hwifs[i].config_data = config | (control <<8);
-				ide_hwifs[i].tuneproc = &qd6580_tune_drive;
-
-				for (j=0;j<2;j++) {
-					ide_hwifs[i].drives[j].drive_data =
-					       i?QD6580_DEF_DATA2:QD6580_DEF_DATA;
-					ide_hwifs[i].drives[j].io_32bit = 1;
-				}
-			}
-
-			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
-
-			return 0; /* no other qd65xx possible */
-		}
-	}
-	/* no qd65xx found */
-	return 1;
-}
-
-/*
- * init_qd65xx:
- *
- * called at the very beginning of initialization ; should just probe and link
- */
-
-void __init init_qd65xx (void)
-{
-	if (probe(0x30)) probe(0xb0);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/qd65xx.h linux-2.4.21/drivers/ide/qd65xx.h
--- linux-2.4.20/drivers/ide/qd65xx.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/qd65xx.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,140 +0,0 @@
-/*
- * linux/drivers/ide/qd65xx.h
- *
- * Copyright (c) 2000	Linus Torvalds & authors
- */
-
-/*
- * Authors:	Petr Soucek <petr@ryston.cz>
- * 		Samuel Thibault <samuel.thibault@fnac.net>
- */
-
-/* truncates a in [b,c] */
-#define IDE_IN(a,b,c)   ( ((a)<(b)) ? (b) : ( (a)>(c) ? (c) : (a)) )
-
-#define IDE_IMPLY(a,b)	((!(a)) || (b))
-
-#define QD_TIM1_PORT		(base)
-#define QD_CONFIG_PORT		(base+0x01)
-#define QD_TIM2_PORT		(base+0x02)
-#define QD_CONTROL_PORT		(base+0x03)
-
-#define QD_CONFIG_IDE_BASEPORT	0x01
-#define QD_CONFIG_BASEPORT	0x02
-#define QD_CONFIG_ID3		0x04
-#define QD_CONFIG_DISABLED	0x08
-#define QD_CONFIG_QD6500	0xc0
-#define QD_CONFIG_QD6580_A	0xa0
-#define QD_CONFIG_QD6580_B	0x50
-
-#define QD_CONTR_SEC_DISABLED	0x01
-
-#define QD_ID3			((config & QD_CONFIG_ID3)!=0)
-
-#define QD_CONFIG(hwif)		((hwif)->config_data & 0x00ff)
-#define QD_CONTROL(hwif)	(((hwif)->config_data & 0xff00) >> 8)
-
-#define QD_TIMING(drive)	(byte)(((drive)->drive_data) & 0x00ff)
-#define QD_TIMREG(drive)	(byte)((((drive)->drive_data) & 0xff00) >> 8)
-
-#define QD6500_DEF_DATA		((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08))
-#define QD6580_DEF_DATA		((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
-#define QD6580_DEF_DATA2	((QD_TIM2_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
-#define QD_DEF_CONTR		(0x40 | ((control & 0x02) ? 0x9f : 0x1f))
-
-#define QD_TESTVAL		0x19	/* safe value */
-
-/* Drive specific timing taken from DOS driver v3.7 */
-
-struct qd65xx_timing_s {
-	char	offset;   /* ofset from the beginning of Model Number" */
-	char	model[4];    /* 4 chars from Model number, no conversion */
-	short	active;   /* active time */
-	short	recovery; /* recovery time */
-} qd65xx_timing [] = {
-	{ 30, "2040", 110, 225 },  /* Conner CP30204			*/
-	{ 30, "2045", 135, 225 },  /* Conner CP30254			*/
-	{ 30, "1040", 155, 325 },  /* Conner CP30104			*/
-	{ 30, "1047", 135, 265 },  /* Conner CP30174			*/
-	{ 30, "5344", 135, 225 },  /* Conner CP3544			*/
-	{ 30, "01 4", 175, 405 },  /* Conner CP-3104			*/
-	{ 27, "C030", 175, 375 },  /* Conner CP3000			*/
-	{  8, "PL42", 110, 295 },  /* Quantum LP240			*/
-	{  8, "PL21", 110, 315 },  /* Quantum LP120			*/
-	{  8, "PL25", 175, 385 },  /* Quantum LP52			*/
-	{  4, "PA24", 110, 285 },  /* WD Piranha SP4200			*/
-	{  6, "2200", 110, 260 },  /* WD Caviar AC2200			*/
-	{  6, "3204", 110, 235 },  /* WD Caviar AC2340			*/
-	{  6, "1202", 110, 265 },  /* WD Caviar AC2120			*/
-	{  0, "DS3-", 135, 315 },  /* Teac SD340			*/
-	{  8, "KM32", 175, 355 },  /* Toshiba MK234			*/
-	{  2, "53A1", 175, 355 },  /* Seagate ST351A			*/
-	{  2, "4108", 175, 295 },  /* Seagate ST1480A			*/
-	{  2, "1344", 175, 335 },  /* Seagate ST3144A			*/
-	{  6, "7 12", 110, 225 },  /* Maxtor 7213A			*/
-	{ 30, "02F4", 145, 295 },  /* Conner 3204F			*/
-	{  2, "1302", 175, 335 },  /* Seagate ST3120A			*/
-	{  2, "2334", 145, 265 },  /* Seagate ST3243A			*/
-	{  2, "2338", 145, 275 },  /* Seagate ST3283A			*/
-	{  2, "3309", 145, 275 },  /* Seagate ST3390A			*/
-	{  2, "5305", 145, 275 },  /* Seagate ST3550A			*/
-	{  2, "4100", 175, 295 },  /* Seagate ST1400A			*/
-	{  2, "4110", 175, 295 },  /* Seagate ST1401A			*/
-	{  2, "6300", 135, 265 },  /* Seagate ST3600A			*/
-	{  2, "5300", 135, 265 },  /* Seagate ST3500A			*/
-	{  6, "7 31", 135, 225 },  /* Maxtor 7131 AT			*/
-	{  6, "7 43", 115, 265 },  /* Maxtor 7345 AT			*/
-	{  6, "7 42", 110, 255 },  /* Maxtor 7245 AT			*/
-	{  6, "3 04", 135, 265 },  /* Maxtor 340 AT			*/
-	{  6, "61 0", 135, 285 },  /* WD AC160				*/
-	{  6, "1107", 135, 235 },  /* WD AC1170				*/
-	{  6, "2101", 110, 220 },  /* WD AC1210				*/
-	{  6, "4202", 135, 245 },  /* WD AC2420				*/
-	{  6, "41 0", 175, 355 },  /* WD Caviar 140			*/
-	{  6, "82 0", 175, 355 },  /* WD Caviar 280			*/
-	{  8, "PL01", 175, 375 },  /* Quantum LP105			*/
-	{  8, "PL25", 110, 295 },  /* Quantum LP525			*/
-	{ 10, "4S 2", 175, 385 },  /* Quantum ELS42			*/
-	{ 10, "8S 5", 175, 385 },  /* Quantum ELS85			*/
-	{ 10, "1S72", 175, 385 },  /* Quantum ELS127			*/
-	{ 10, "1S07", 175, 385 },  /* Quantum ELS170			*/
-	{  8, "ZE42", 135, 295 },  /* Quantum EZ240			*/
-	{  8, "ZE21", 175, 385 },  /* Quantum EZ127			*/
-	{  8, "ZE58", 175, 385 },  /* Quantum EZ85			*/
-	{  8, "ZE24", 175, 385 },  /* Quantum EZ42			*/
-	{ 27, "C036", 155, 325 },  /* Conner CP30064			*/
-	{ 27, "C038", 155, 325 },  /* Conner CP30084			*/
-	{  6, "2205", 110, 255 },  /* WDC AC2250			*/
-	{  2, " CHA", 140, 415 },  /* WDC AH series; WDC AH260, WDC	*/
-	{  2, " CLA", 140, 415 },  /* WDC AL series: WDC AL2120, 2170,	*/
-	{  4, "UC41", 140, 415 },  /* WDC CU140				*/
-	{  6, "1207", 130, 275 },  /* WDC AC2170			*/
-	{  6, "2107", 130, 275 },  /* WDC AC1270			*/
-	{  6, "5204", 130, 275 },  /* WDC AC2540			*/
-	{ 30, "3004", 110, 235 },  /* Conner CP30340			*/
-	{ 30, "0345", 135, 255 },  /* Conner CP30544			*/
-	{ 12, "12A3", 175, 320 },  /* MAXTOR LXT-213A			*/
-	{ 12, "43A0", 145, 240 },  /* MAXTOR LXT-340A			*/
-	{  6, "7 21", 180, 290 },  /* Maxtor 7120 AT			*/
-	{  6, "7 71", 135, 240 },  /* Maxtor 7170 AT			*/
-	{ 12, "45\0000", 110, 205 },   /* MAXTOR MXT-540		*/
-	{  8, "PL11", 180, 290 },  /* QUANTUM LP110A			*/
-	{  8, "OG21", 150, 275 },  /* QUANTUM GO120			*/
-	{ 12, "42A5", 175, 320 },  /* MAXTOR LXT-245A			*/
-	{  2, "2309", 175, 295 },  /* ST3290A				*/
-	{  2, "3358", 180, 310 },  /* ST3385A				*/
-	{  2, "6355", 180, 310 },  /* ST3655A				*/
-	{  2, "1900", 175, 270 },  /* ST9100A				*/
-	{  2, "1954", 175, 270 },  /* ST9145A				*/
-	{  2, "1909", 175, 270 },  /* ST9190AG				*/
-	{  2, "2953", 175, 270 },  /* ST9235A				*/
-	{  2, "1359", 175, 270 },  /* ST3195A				*/
-	{ 24, "3R11", 175, 290 },  /* ALPS ELECTRIC Co.,LTD, DR311C	*/
-	{  0, "2M26", 175, 215 },  /* M262XT-0Ah			*/
-	{  4, "2253", 175, 300 },  /* HP C2235A				*/
-	{  4, "-32A", 145, 245 },  /* H3133-A2				*/
-	{ 30, "0326", 150, 270 },  /* Samsung Electronics 120MB		*/
-	{ 30, "3044", 110, 195 },  /* Conner CFA340A			*/
-	{ 30, "43A0", 110, 195 },  /* Conner CFA340A			*/
-	{ -1, "    ", 175, 415 }   /* unknown disk name			*/
-};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/Makefile linux-2.4.21/drivers/ide/raid/Makefile
--- linux-2.4.20/drivers/ide/raid/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/raid/Makefile	2002-12-18 18:58:11.000000000 +0000
@@ -0,0 +1,18 @@
+
+O_TARGET := idedriver-raid.o
+
+obj-y		:=
+obj-m		:=
+
+export-objs := ataraid.o
+
+# The virtualised raid layers MUST come after the ide itself or bad stuff
+# will happen.
+
+obj-$(CONFIG_BLK_DEV_ATARAID)		+= ataraid.o
+obj-$(CONFIG_BLK_DEV_ATARAID_PDC)	+= pdcraid.o
+obj-$(CONFIG_BLK_DEV_ATARAID_HPT)	+= hptraid.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/ataraid.c linux-2.4.21/drivers/ide/raid/ataraid.c
--- linux-2.4.20/drivers/ide/raid/ataraid.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/raid/ataraid.c	2002-12-18 18:58:08.000000000 +0000
@@ -0,0 +1,317 @@
+/*
+   ataraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
+
+   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, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+   
+   Authors: 	Arjan van de Ven <arjanv@redhat.com>
+   		
+   
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/semaphore.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+#include <linux/kdev_t.h>
+#include <linux/swap.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#include "ataraid.h"
+
+                                        
+static int ataraid_hardsect_size[256];
+static int ataraid_blksize_size[256];
+
+static struct raid_device_operations* ataraid_ops[16];
+
+static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int ataraid_open(struct inode * inode, struct file * filp);
+static int ataraid_release(struct inode * inode, struct file * filp);
+static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh);
+
+
+struct gendisk ataraid_gendisk;
+static int ataraid_gendisk_sizes[256];
+static int ataraid_readahead[256];
+
+static struct block_device_operations ataraid_fops = {
+	owner:			THIS_MODULE,
+	open:                   ataraid_open,
+	release:                ataraid_release,
+	ioctl:                  ataraid_ioctl,
+};
+                
+
+
+static DECLARE_MUTEX(ataraid_sem);
+
+/* Bitmap for the devices currently in use */
+static unsigned int ataraiduse;
+
+
+/* stub fops functions */
+
+static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)  
+{
+	int minor;
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+	
+	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->ioctl))
+		return (ataraid_ops[minor]->ioctl)(inode,file,cmd,arg);
+	return -EINVAL;
+}
+
+static int ataraid_open(struct inode * inode, struct file * filp)
+{
+	int minor;
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+
+	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->open))
+		return (ataraid_ops[minor]->open)(inode,filp);
+	return -EINVAL;
+}
+
+
+static int ataraid_release(struct inode * inode, struct file * filp)
+{
+	int minor;
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+
+	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->release))
+		return (ataraid_ops[minor]->release)(inode,filp);
+	return -EINVAL;
+}
+
+static int ataraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	int minor;
+	int retval;
+	minor = MINOR(bh->b_rdev)>>SHIFT;
+
+	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->make_request)) {
+		
+		retval= (ataraid_ops[minor]->make_request)(q,rw,bh);
+		if (retval == -1) {
+			ataraid_split_request(q,rw,bh);		
+			return 0;
+		} else
+			return retval;
+	}
+	return -EINVAL;
+}
+
+struct buffer_head *ataraid_get_bhead(void)
+{
+	void *ptr = NULL;
+	while (!ptr) {
+		ptr=kmalloc(sizeof(struct buffer_head),GFP_NOIO);
+		if (!ptr) {
+			__set_current_state(TASK_RUNNING);
+			yield();
+		}
+	}
+	return ptr;
+}
+
+EXPORT_SYMBOL(ataraid_get_bhead);
+
+struct ataraid_bh_private *ataraid_get_private(void)
+{
+	void *ptr = NULL;
+	while (!ptr) {
+		ptr=kmalloc(sizeof(struct ataraid_bh_private),GFP_NOIO);
+		if (!ptr) {
+			__set_current_state(TASK_RUNNING);
+			yield();
+		}
+	}
+	return ptr;
+}
+
+EXPORT_SYMBOL(ataraid_get_private);
+
+void ataraid_end_request(struct buffer_head *bh, int uptodate)
+{
+	struct ataraid_bh_private *private = bh->b_private;
+
+	if (private==NULL)
+		BUG();
+
+	if (atomic_dec_and_test(&private->count)) {
+		private->parent->b_end_io(private->parent,uptodate);
+		private->parent = NULL;
+		kfree(private);
+	}
+	kfree(bh);
+}
+
+EXPORT_SYMBOL(ataraid_end_request);
+
+static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	struct buffer_head *bh1,*bh2;
+	struct ataraid_bh_private *private;
+	bh1=ataraid_get_bhead();
+	bh2=ataraid_get_bhead();
+
+	/* If either of those ever fails we're doomed */
+	if ((!bh1)||(!bh2))
+		BUG();
+	private = ataraid_get_private();
+	if (private==NULL)
+		BUG();
+	
+	memcpy(bh1, bh, sizeof(*bh));
+	memcpy(bh2, bh, sizeof(*bh));
+	
+	bh1->b_end_io = ataraid_end_request;
+	bh2->b_end_io = ataraid_end_request;
+
+	bh2->b_rsector += bh->b_size >> 10;
+	bh1->b_size /= 2;
+	bh2->b_size /= 2;
+	private->parent = bh;
+
+	bh1->b_private = private;
+	bh2->b_private = private;
+	atomic_set(&private->count,2);
+
+	bh2->b_data +=  bh->b_size/2;
+
+	generic_make_request(rw,bh1);
+	generic_make_request(rw,bh2);
+}
+
+
+
+
+/* device register / release functions */
+
+
+int ataraid_get_device(struct raid_device_operations *fops)
+{
+	int bit;
+	down(&ataraid_sem);
+	if (ataraiduse==~0U) {
+		up(&ataraid_sem);
+		return -ENODEV;
+	}
+	bit=ffz(ataraiduse); 
+	ataraiduse |= 1<<bit;
+	ataraid_ops[bit] = fops;
+	up(&ataraid_sem);
+	return bit;
+}
+
+void ataraid_release_device(int device)
+{
+	down(&ataraid_sem);
+	
+	if ((ataraiduse & (1<<device))==0)
+		BUG();	/* device wasn't registered at all */
+	
+	ataraiduse &= ~(1<<device);
+	ataraid_ops[device] = NULL;
+	up(&ataraid_sem);
+}
+
+void ataraid_register_disk(int device,long size)
+{
+	register_disk(&ataraid_gendisk, MKDEV(ATAMAJOR,16*device),16,
+		&ataraid_fops,size);
+
+}
+
+static __init int ataraid_init(void) 
+{
+	int i;
+        for(i=0;i<256;i++)
+	{
+        	ataraid_hardsect_size[i] = 512;
+		ataraid_blksize_size[i] = 1024;  
+		ataraid_readahead[i] = 1023;
+	}
+	
+	if (blksize_size[ATAMAJOR]==NULL)
+		blksize_size[ATAMAJOR] = ataraid_blksize_size;
+	if (hardsect_size[ATAMAJOR]==NULL)
+		hardsect_size[ATAMAJOR] = ataraid_hardsect_size;
+	
+	
+	/* setup the gendisk structure */	
+	ataraid_gendisk.part = kmalloc(256 * sizeof(struct hd_struct),GFP_KERNEL);
+	if (ataraid_gendisk.part==NULL) {
+		printk(KERN_ERR "ataraid: Couldn't allocate memory, aborting \n");
+		return -1;
+	}
+	
+	memset(&ataraid_gendisk.part[0],0,256*sizeof(struct hd_struct));
+	
+	
+	ataraid_gendisk.major       = ATAMAJOR;
+	ataraid_gendisk.major_name  = "ataraid";
+	ataraid_gendisk.minor_shift = 4;
+	ataraid_gendisk.max_p	    = 15;
+	ataraid_gendisk.sizes	    = &ataraid_gendisk_sizes[0];
+	ataraid_gendisk.nr_real	    = 16;
+	ataraid_gendisk.fops        = &ataraid_fops;
+	
+	
+	add_gendisk(&ataraid_gendisk);
+			
+	if (register_blkdev(ATAMAJOR, "ataraid", &ataraid_fops)) {
+		printk(KERN_ERR "ataraid: Could not get major %d \n",ATAMAJOR);
+		return -1;
+	}
+	
+	                
+	
+	blk_queue_make_request(BLK_DEFAULT_QUEUE(ATAMAJOR),ataraid_make_request);
+                                                                                     	
+	return 0;                                                        	
+}
+
+
+static void __exit ataraid_exit(void)
+{
+	unregister_blkdev(ATAMAJOR, "ataraid");
+	hardsect_size[ATAMAJOR] = NULL;
+	blk_size[ATAMAJOR] = NULL;
+	blksize_size[ATAMAJOR] = NULL;                       
+	max_readahead[ATAMAJOR] = NULL;
+
+	del_gendisk(&ataraid_gendisk);
+        
+	if (ataraid_gendisk.part) {
+		kfree(ataraid_gendisk.part);
+		ataraid_gendisk.part = NULL;
+	}
+}
+
+module_init(ataraid_init);
+module_exit(ataraid_exit);
+
+
+
+EXPORT_SYMBOL(ataraid_get_device);
+EXPORT_SYMBOL(ataraid_release_device);
+EXPORT_SYMBOL(ataraid_gendisk);
+EXPORT_SYMBOL(ataraid_register_disk);
+MODULE_LICENSE("GPL");
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/ataraid.h linux-2.4.21/drivers/ide/raid/ataraid.h
--- linux-2.4.20/drivers/ide/raid/ataraid.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/raid/ataraid.h	2002-12-18 18:58:06.000000000 +0000
@@ -0,0 +1,72 @@
+/*
+   ataraid.h  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
+
+   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, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+   
+   Authors: 	Arjan van de Ven <arjanv@redhat.com>
+   		
+   
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/semaphore.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#define ATAMAJOR 114
+#define SHIFT 4
+#define MINOR_MASK 15
+#define MAJOR_MASK 15
+
+                                        
+/* raid_device_operations is a light struct block_device_operations with an
+   added method for make_request */
+struct raid_device_operations {
+	int (*open) (struct inode *, struct file *);
+	int (*release) (struct inode *, struct file *);
+	int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
+	int (*make_request) (request_queue_t *q, int rw, struct buffer_head * bh);
+};
+
+
+struct geom {
+	unsigned char heads;
+	unsigned int cylinders;
+	unsigned char sectors;
+};
+
+/* structure for the splitting of bufferheads */
+
+struct ataraid_bh_private {
+	struct buffer_head *parent;
+	atomic_t count;
+};
+
+extern struct gendisk ataraid_gendisk;
+
+extern int ataraid_get_device(struct raid_device_operations *fops);
+extern void ataraid_release_device(int device);
+extern int get_blocksize(kdev_t dev);
+extern void ataraid_register_disk(int device,long size);
+extern struct buffer_head *ataraid_get_bhead(void);
+extern struct ataraid_bh_private *ataraid_get_private(void);
+extern void ataraid_end_request(struct buffer_head *bh, int uptodate);
+
+
+
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/hptraid.c linux-2.4.21/drivers/ide/raid/hptraid.c
--- linux-2.4.20/drivers/ide/raid/hptraid.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/raid/hptraid.c	2002-12-18 18:58:09.000000000 +0000
@@ -0,0 +1,436 @@
+/*
+   hptraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
+
+   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, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+   
+   Authors: 	Arjan van de Ven <arjanv@redhat.com>
+
+   Based on work
+   	Copyleft  (C) 2001 by Wilfried Weissmann <wweissmann@gmx.at>
+	Copyright (C) 1994-96 Marc ZYNGIER <zyngier@ufr-info-p7.ibp.fr>
+   Based on work done by Søren Schmidt for FreeBSD
+
+   
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#include "ataraid.h"
+
+static int hptraid_open(struct inode * inode, struct file * filp);
+static int hptraid_release(struct inode * inode, struct file * filp);
+static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int hptraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+
+
+
+struct hptdisk {
+	kdev_t	device;
+	unsigned long sectors;
+	struct block_device *bdev;
+};
+
+struct hptraid {
+	unsigned int stride;
+	unsigned int disks;
+	unsigned long sectors;
+	struct geom geom;
+	
+	struct hptdisk disk[8];
+	
+	unsigned long cutoff[8];
+	unsigned int cutoff_disks[8];	
+};
+
+static struct raid_device_operations hptraid_ops = {
+	open:                   hptraid_open,
+	release:                hptraid_release,
+	ioctl:			hptraid_ioctl,
+	make_request:		hptraid_make_request
+};
+
+static struct hptraid raid[16];
+
+static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	unsigned int minor;
+	unsigned char val;
+	unsigned long sectors;
+	
+	if (!inode || !inode->i_rdev) 	
+		return -EINVAL;
+
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+	
+	switch (cmd) {
+         	case BLKGETSIZE:   /* Return device size */
+			if (!arg)  return -EINVAL;
+			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
+			if (MINOR(inode->i_rdev)&15)
+				return put_user(sectors, (unsigned long *) arg);
+			return put_user(raid[minor].sectors , (unsigned long *) arg);
+			break;
+			
+
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry *loc = (struct hd_geometry *) arg;
+			unsigned short bios_cyl;
+			
+			if (!loc) return -EINVAL;
+			val = 255;
+			if (put_user(val, (byte *) &loc->heads)) return -EFAULT;
+			val=63;
+			if (put_user(val, (byte *) &loc->sectors)) return -EFAULT;
+			bios_cyl = raid[minor].sectors/63/255;
+			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+
+		case HDIO_GETGEO_BIG:
+		{
+			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+			unsigned int bios_cyl;
+			if (!loc) return -EINVAL;
+			val = 255;
+			if (put_user(val, (byte *) &loc->heads)) return -EFAULT;
+			val = 63;
+			if (put_user(val, (byte *) &loc->sectors)) return -EFAULT;
+			bios_cyl = raid[minor].sectors/63/255;
+			if (put_user(bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+			
+		default:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
+	};
+
+	return 0;
+}
+
+
+static int hptraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	unsigned long rsect;
+	unsigned long rsect_left,rsect_accum = 0;
+	unsigned long block;
+	unsigned int disk=0,real_disk=0;
+	int i;
+	int device;
+	struct hptraid *thisraid;
+
+	rsect = bh->b_rsector;
+
+	/* Ok. We need to modify this sector number to a new disk + new sector number. 
+	 * If there are disks of different sizes, this gets tricky. 
+	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
+	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
+	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
+	 * and the last 1Gb is disk 3 only.
+	 *
+	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
+	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
+	 * point, we have to divide by one less.
+	 */
+	
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	thisraid = &raid[device];
+	if (thisraid->stride==0)
+		thisraid->stride=1;
+
+	/* Partitions need adding of the start sector of the partition to the requested sector */
+	
+	rsect += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
+
+	/* Woops we need to split the request to avoid crossing a stride barrier */
+	if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
+		return -1;
+	}
+			
+	rsect_left = rsect;
+	
+	for (i=0;i<8;i++) {
+		if (thisraid->cutoff_disks[i]==0)
+			break;
+		if (rsect > thisraid->cutoff[i]) {
+			/* we're in the wrong area so far */
+			rsect_left -= thisraid->cutoff[i];
+			rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
+		} else {
+			block = rsect_left / thisraid->stride;
+			disk = block % thisraid->cutoff_disks[i];
+			block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
+			rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
+			break;
+		}
+	}
+	
+	for (i=0;i<8;i++) {
+		if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
+			real_disk = i;
+			break;
+		}
+		if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
+			disk--;
+		}
+		
+	}
+	disk = real_disk;
+	
+	/* All but the first disk have a 10 sector offset */
+	if (i>0)
+		rsect+=10;
+		
+	
+	/*
+	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
+	 * is the only IO operation happening on this bh.
+	 */
+	 
+	bh->b_rdev = thisraid->disk[disk].device;
+	bh->b_rsector = rsect;
+
+	/*
+	 * Let the main block layer submit the IO and resolve recursion:
+	 */
+	return 1;
+}
+
+
+#include "hptraid.h"
+
+static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
+{
+	int ret = -EINVAL;
+	struct buffer_head *bh = NULL;
+	kdev_t dev = MKDEV(major,minor);
+	
+	if (blksize_size[major]==NULL)	 /* device doesn't exist */
+		return -EINVAL;
+	
+
+	/* Superblock is at 4096+412 bytes */
+	set_blocksize (dev, 4096);
+	bh = bread (dev, 1, 4096);
+
+	
+	if (bh) {
+		memcpy (buffer, bh->b_data, bufsize);
+	} else {
+		printk(KERN_ERR "hptraid: Error reading superblock.\n");
+		goto abort;
+	}
+	ret = 0;
+abort:
+	if (bh)
+		brelse (bh);
+	return ret;
+}
+
+static unsigned long maxsectors (int major,int minor)
+{
+	unsigned long lba = 0;
+	kdev_t dev;
+	ide_drive_t *ideinfo;
+	
+	dev = MKDEV(major,minor);
+	ideinfo = get_info_ptr (dev);
+	if (ideinfo==NULL)
+		return 0;
+	
+	
+	/* first sector of the last cluster */
+	if (ideinfo->head==0) 
+		return 0;
+	if (ideinfo->sect==0)
+		return 0;
+	lba = (ideinfo->capacity);
+
+	return lba;
+}
+
+static void __init probedisk(int major, int minor,int device)
+{
+	int i;
+        struct highpoint_raid_conf *prom;
+	static unsigned char block[4096];
+	struct block_device *bdev;
+	
+	if (maxsectors(major,minor)==0)
+		return;
+	
+        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
+        	return;
+                                                                                                                 
+        prom = (struct highpoint_raid_conf*)&block[512];
+                
+        if (prom->magic!=  0x5a7816f0)
+        	return;
+        if (prom->type) {
+        	printk(KERN_INFO "hptraid: only RAID0 is supported currently\n");
+        	return;
+        }
+
+	i = prom->disk_number;
+	if (i<0)
+		return;
+	if (i>8) 
+		return;
+
+	bdev = bdget(MKDEV(major,minor));
+	if (bdev && blkdev_get(bdev,FMODE_READ|FMODE_WRITE,0,BDEV_RAW) == 0) {
+        	int j=0;
+        	struct gendisk *gd;
+		raid[device].disk[i].bdev = bdev;
+        	/* This is supposed to prevent others from stealing our underlying disks */
+		/* now blank the /proc/partitions table for the wrong partition table,
+		   so that scripts don't accidentally mount it and crash the kernel */
+		 /* XXX: the 0 is an utter hack  --hch */
+		gd=get_gendisk(MKDEV(major, 0));
+		if (gd!=NULL) {
+			for (j=1+(minor<<gd->minor_shift);j<((minor+1)<<gd->minor_shift);j++) 
+				gd->part[j].nr_sects=0;					
+		}
+        }
+	raid[device].disk[i].device = MKDEV(major,minor);
+	raid[device].disk[i].sectors = maxsectors(major,minor);
+	raid[device].stride = (1<<prom->raid0_shift);
+	raid[device].disks = prom->raid_disks;
+	raid[device].sectors = prom->total_secs;
+			
+}
+
+static void __init fill_cutoff(int device)
+{
+	int i,j;
+	unsigned long smallest;
+	unsigned long bar;
+	int count;
+	
+	bar = 0;
+	for (i=0;i<8;i++) {
+		smallest = ~0;
+		for (j=0;j<8;j++) 
+			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
+				smallest = raid[device].disk[j].sectors;
+		count = 0;
+		for (j=0;j<8;j++) 
+			if (raid[device].disk[j].sectors >= smallest)
+				count++;
+		
+		smallest = smallest * count;		
+		bar = smallest;
+		raid[device].cutoff[i] = smallest;
+		raid[device].cutoff_disks[i] = count;
+		
+	}
+}
+
+
+static __init int hptraid_init_one(int device)
+{
+	int i,count;
+
+	probedisk(IDE0_MAJOR,  0, device);
+	probedisk(IDE0_MAJOR, 64, device);
+	probedisk(IDE1_MAJOR,  0, device);
+	probedisk(IDE1_MAJOR, 64, device);
+	probedisk(IDE2_MAJOR,  0, device);
+	probedisk(IDE2_MAJOR, 64, device);
+	probedisk(IDE3_MAJOR,  0, device);
+	probedisk(IDE3_MAJOR, 64, device);
+	probedisk(IDE4_MAJOR,  0, device);
+	probedisk(IDE4_MAJOR, 64, device);
+	probedisk(IDE5_MAJOR,  0, device);
+	probedisk(IDE5_MAJOR, 64, device);
+
+	fill_cutoff(device);
+	
+	/* Initialize the gendisk structure */
+	
+	ataraid_register_disk(device,raid[device].sectors);
+
+	count=0;
+	printk(KERN_INFO "Highpoint HPT370 Softwareraid driver for linux version 0.01\n");
+		
+	for (i=0;i<8;i++) {
+		if (raid[device].disk[i].device!=0) {
+			printk(KERN_INFO "Drive %i is %li Mb \n",
+				i,raid[device].disk[i].sectors/2048);
+			count++;
+		}
+	}
+	if (count) {
+		printk(KERN_INFO "Raid array consists of %i drives. \n",count);
+		return 0;
+	} else {
+		printk(KERN_INFO "No raid array found\n");
+		return -ENODEV;
+	}
+	
+}
+
+static __init int hptraid_init(void)
+{
+	int retval,device;
+	
+	device=ataraid_get_device(&hptraid_ops);
+	if (device<0)
+		return -ENODEV;
+	retval = hptraid_init_one(device);
+	if (retval)
+		ataraid_release_device(device);
+	return retval;
+}
+
+static void __exit hptraid_exit (void)
+{
+	int i,device;
+	for (device = 0; device<16; device++) {
+		for (i=0;i<8;i++)  {
+			struct block_device *bdev = raid[device].disk[i].bdev;
+			raid[device].disk[i].bdev = NULL;
+			if (bdev)
+				blkdev_put(bdev, BDEV_RAW);
+		}       
+		if (raid[device].sectors)
+			ataraid_release_device(device);
+	}
+}
+
+static int hptraid_open(struct inode * inode, struct file * filp) 
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+static int hptraid_release(struct inode * inode, struct file * filp)
+{	
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+module_init(hptraid_init);
+module_exit(hptraid_exit);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/hptraid.h linux-2.4.21/drivers/ide/raid/hptraid.h
--- linux-2.4.20/drivers/ide/raid/hptraid.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/raid/hptraid.h	2002-12-18 18:58:02.000000000 +0000
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2000,2001 Søren Schmidt <sos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+                            
+struct highpoint_raid_conf
+{
+       int8_t  filler1[32];
+       u_int32_t       magic;
+#define HPT_MAGIC_OK   0x5a7816f0
+#define HPT_MAGIC_BAD  0x5a7816fd  
+
+       u_int32_t       magic_0;
+       u_int32_t       magic_1;
+       u_int32_t       order;  
+#define HPT_O_MIRROR   0x01  
+#define HPT_O_STRIPE   0x02
+#define HPT_O_OK       0x04
+
+       u_int8_t        raid_disks;
+       u_int8_t        raid0_shift; 
+       u_int8_t        type;
+#define HPT_T_RAID_0   0x00 
+#define HPT_T_RAID_1   0x01
+#define HPT_T_RAID_01_RAID_0   0x02
+#define HPT_T_SPAN             0x03
+#define HPT_T_RAID_3           0x04   
+#define HPT_T_RAID_5           0x05
+#define HPT_T_SINGLEDISK       0x06
+#define HPT_T_RAID_01_RAID_1   0x07
+
+       u_int8_t        disk_number;
+       u_int32_t       total_secs; 
+       u_int32_t       disk_mode;  
+       u_int32_t       boot_mode;
+       u_int8_t        boot_disk; 
+       u_int8_t        boot_protect;
+       u_int8_t        error_log_entries;
+       u_int8_t        error_log_index;  
+       struct
+       {
+               u_int32_t       timestamp;
+               u_int8_t        reason;   
+#define HPT_R_REMOVED          0xfe      
+#define HPT_R_BROKEN           0xff      
+
+               u_int8_t        disk;
+               u_int8_t        status;
+               u_int8_t        sectors;
+               u_int32_t       lba;
+       } errorlog[32];
+       u_int8_t        filler[60];
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/pdcraid.c linux-2.4.21/drivers/ide/raid/pdcraid.c
--- linux-2.4.20/drivers/ide/raid/pdcraid.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/raid/pdcraid.c	2002-12-18 18:58:08.000000000 +0000
@@ -0,0 +1,646 @@
+/*
+   pdcraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
+
+   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, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+   
+   Authors: 	Arjan van de Ven <arjanv@redhat.com>
+   		
+   Based on work done by Søren Schmidt for FreeBSD  
+
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#include "ataraid.h"
+
+static int pdcraid_open(struct inode * inode, struct file * filp);
+static int pdcraid_release(struct inode * inode, struct file * filp);
+static int pdcraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int pdcraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+static int pdcraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+
+struct disk_dev {
+	int major;
+	int minor;
+	int device;
+};
+
+static struct disk_dev devlist[]= {
+	{IDE0_MAJOR,  0,  -1 },
+	{IDE0_MAJOR, 64,  -1 },
+	{IDE1_MAJOR,  0,  -1 },
+	{IDE1_MAJOR, 64,  -1 },
+	{IDE2_MAJOR,  0,  -1 },
+	{IDE2_MAJOR, 64,  -1 },
+	{IDE3_MAJOR,  0,  -1 },
+	{IDE3_MAJOR, 64,  -1 },
+	{IDE4_MAJOR,  0,  -1 },
+	{IDE4_MAJOR, 64,  -1 },
+	{IDE5_MAJOR,  0,  -1 },
+	{IDE5_MAJOR, 64,  -1 },
+	{IDE6_MAJOR,  0,  -1 },
+	{IDE6_MAJOR, 64,  -1 },
+};
+
+
+struct pdcdisk {
+	kdev_t	device;
+	unsigned long sectors;
+	struct block_device *bdev;
+	unsigned long last_pos;
+};
+
+struct pdcraid {
+	unsigned int stride;
+	unsigned int disks;
+	unsigned long sectors;
+	struct geom geom;
+	
+	struct pdcdisk disk[8];
+	
+	unsigned long cutoff[8];
+	unsigned int cutoff_disks[8];
+};
+
+static struct raid_device_operations pdcraid0_ops = {
+        open:                   pdcraid_open,
+	release:                pdcraid_release,
+	ioctl:			pdcraid_ioctl,
+	make_request:		pdcraid0_make_request
+};
+
+static struct raid_device_operations pdcraid1_ops = {
+        open:                   pdcraid_open,
+	release:                pdcraid_release,
+	ioctl:			pdcraid_ioctl,
+	make_request:		pdcraid1_make_request
+};
+
+static struct pdcraid raid[16];
+
+
+static int pdcraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	unsigned int minor;
+   	unsigned long sectors;
+
+	if (!inode || !inode->i_rdev) 
+		return -EINVAL;
+
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+	
+	switch (cmd) {
+
+         	case BLKGETSIZE:   /* Return device size */
+ 			if (!arg)  return -EINVAL;
+			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
+			if (MINOR(inode->i_rdev)&15)
+				return put_user(sectors, (unsigned long *) arg);
+			return put_user(raid[minor].sectors , (unsigned long *) arg);
+			break;
+			
+
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry *loc = (struct hd_geometry *) arg;
+			unsigned short bios_cyl = raid[minor].geom.cylinders; /* truncate */
+			
+			if (!loc) return -EINVAL;
+			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
+			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+
+		case HDIO_GETGEO_BIG:
+		{
+			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+			if (!loc) return -EINVAL;
+			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
+			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(raid[minor].geom.cylinders, (unsigned int *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+
+			
+		case BLKROSET:
+		case BLKROGET:
+		case BLKSSZGET:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
+
+		default:
+			printk("Invalid ioctl \n");
+			return -EINVAL;
+	};
+
+	return 0;
+}
+
+
+unsigned long partition_map_normal(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
+{
+	return block + partition_off;
+}
+
+unsigned long partition_map_linux(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
+{
+	unsigned long newblock;
+	
+	newblock = stride - (partition_off%stride); if (newblock == stride) newblock = 0;
+	newblock += block;
+	newblock = newblock % partition_size;
+	newblock += partition_off;
+	
+	return newblock;
+}
+
+static int funky_remap[8] = { 0, 1,  2, 3, 4, 5, 6, 7 };
+
+unsigned long partition_map_linux_raid0_4disk(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
+{
+	unsigned long newblock,temp,temp2;
+	
+	newblock = stride - (partition_off%stride); if (newblock == stride) newblock = 0;
+
+	if (block < (partition_size / (8*stride))*8*stride ) {
+		temp = block % stride;
+		temp2 = block / stride;
+		temp2 = ((temp2>>3)<<3)|(funky_remap[temp2&7]);
+		block = temp2*stride+temp;
+	}
+
+	
+	newblock += block;
+	newblock = newblock % partition_size;
+	newblock += partition_off;
+	
+	return newblock;
+}
+
+
+
+static int pdcraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	unsigned long rsect;
+	unsigned long rsect_left,rsect_accum = 0;
+	unsigned long block;
+	unsigned int disk=0,real_disk=0;
+	int i;
+	int device;
+	struct pdcraid *thisraid;
+
+	rsect = bh->b_rsector;
+	
+	/* Ok. We need to modify this sector number to a new disk + new sector number. 
+	 * If there are disks of different sizes, this gets tricky. 
+	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
+	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
+	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
+	 * and the last 1Gb is disk 3 only.
+	 *
+	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
+	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
+	 * point, we have to divide by one less.
+	 */
+	
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	thisraid = &raid[device];
+	if (thisraid->stride==0)
+		thisraid->stride=1;
+
+	/* Partitions need adding of the start sector of the partition to the requested sector */
+	
+	rsect = partition_map_normal(rsect, ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect, ataraid_gendisk.part[MINOR(bh->b_rdev)].nr_sects, thisraid->stride);
+
+	/* Woops we need to split the request to avoid crossing a stride barrier */
+	if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
+		return -1;  
+	}
+	
+	rsect_left = rsect;
+	
+	for (i=0;i<8;i++) {
+		if (thisraid->cutoff_disks[i]==0)
+			break;
+		if (rsect > thisraid->cutoff[i]) {
+			/* we're in the wrong area so far */
+			rsect_left -= thisraid->cutoff[i];
+			rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
+		} else {
+			block = rsect_left / thisraid->stride;
+			disk = block % thisraid->cutoff_disks[i];
+			block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
+			rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
+			break;
+		}
+	}
+	
+	for (i=0;i<8;i++) {
+		if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
+			real_disk = i;
+			break;
+		}
+		if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
+			disk--;
+		}
+		
+	}
+	disk = real_disk;
+		
+	
+	/*
+	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
+	 * is the only IO operation happening on this bh.
+	 */
+	bh->b_rdev = thisraid->disk[disk].device;
+	bh->b_rsector = rsect;
+
+	/*
+	 * Let the main block layer submit the IO and resolve recursion:
+	 */
+	return 1;
+}
+
+static int pdcraid1_write_request(request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	struct buffer_head *bh1;
+	struct ataraid_bh_private *private;
+	int device;
+	int i;
+
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	private = ataraid_get_private();
+	if (private==NULL)
+		BUG();
+
+	private->parent = bh;
+	
+	atomic_set(&private->count,raid[device].disks);
+
+
+	for (i = 0; i< raid[device].disks; i++) { 
+		bh1=ataraid_get_bhead();
+		/* If this ever fails we're doomed */
+		if (!bh1)
+			BUG();
+	
+		/* dupe the bufferhead and update the parts that need to be different */
+		memcpy(bh1, bh, sizeof(*bh));
+		
+		bh1->b_end_io = ataraid_end_request;
+		bh1->b_private = private;
+		bh1->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect; /* partition offset */
+		bh1->b_rdev = raid[device].disk[i].device;
+
+		/* update the last known head position for the drive */
+		raid[device].disk[i].last_pos = bh1->b_rsector+(bh1->b_size>>9);
+
+		generic_make_request(rw,bh1);
+	}
+	return 0;
+}
+
+static int pdcraid1_read_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	int device;
+	int dist;
+	int bestsofar,bestdist,i;
+	static int previous;
+
+	/* Reads are simple in principle. Pick a disk and go. 
+	   Initially I cheat by just picking the one which the last known
+	   head position is closest by.
+	   Later on, online/offline checking and performance needs adding */
+	
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	bh->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
+
+	bestsofar = 0; 
+	bestdist = raid[device].disk[0].last_pos - bh->b_rsector;
+	if (bestdist<0) 
+		bestdist=-bestdist;
+	if (bestdist>4095)
+		bestdist=4095;
+
+	for (i=1 ; i<raid[device].disks; i++) {
+		dist = raid[device].disk[i].last_pos - bh->b_rsector;
+		if (dist<0) 
+			dist = -dist;
+		if (dist>4095)
+			dist=4095;
+		
+		if (bestdist==dist) {  /* it's a tie; try to do some read balancing */
+			if ((previous>bestsofar)&&(previous<=i))  
+				bestsofar = i;
+			previous = (previous + 1) % raid[device].disks;
+		} else if (bestdist>dist) {
+			bestdist = dist;
+			bestsofar = i;
+		}
+	
+	}
+	
+	bh->b_rdev = raid[device].disk[bestsofar].device; 
+	raid[device].disk[bestsofar].last_pos = bh->b_rsector+(bh->b_size>>9);
+
+	/*
+	 * Let the main block layer submit the IO and resolve recursion:
+	 */
+                          	
+	return 1;
+}
+
+
+static int pdcraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	/* Read and Write are totally different cases; split them totally here */
+	if (rw==READA)
+		rw = READ;
+	
+	if (rw==READ)
+		return pdcraid1_read_request(q,rw,bh);
+	else
+		return pdcraid1_write_request(q,rw,bh);
+}
+
+#include "pdcraid.h"
+
+static unsigned long calc_pdcblock_offset (int major,int minor)
+{
+	unsigned long lba = 0;
+	kdev_t dev;
+	ide_drive_t *ideinfo;
+	
+	dev = MKDEV(major,minor);
+	ideinfo = get_info_ptr (dev);
+	if (ideinfo==NULL)
+		return 0;
+	
+	
+	/* first sector of the last cluster */
+	if (ideinfo->head==0) 
+		return 0;
+	if (ideinfo->sect==0)
+		return 0;
+	lba = (ideinfo->capacity / (ideinfo->head*ideinfo->sect));
+	lba = lba * (ideinfo->head*ideinfo->sect);
+	lba = lba - ideinfo->sect;
+
+	return lba;
+}
+
+
+static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
+{
+	int ret = -EINVAL;
+	struct buffer_head *bh = NULL;
+	kdev_t dev = MKDEV(major,minor);
+	unsigned long sb_offset;
+
+	if (blksize_size[major]==NULL)   /* device doesn't exist */
+		return -EINVAL;
+                       
+	
+	/*
+	 * Calculate the position of the superblock,
+	 * it's at first sector of the last cylinder
+	 */
+	sb_offset = calc_pdcblock_offset(major,minor)/8;
+	/* The /8 transforms sectors into 4Kb blocks */
+
+	if (sb_offset==0)
+		return -1;	
+	
+	set_blocksize (dev, 4096);
+
+	bh = bread (dev, sb_offset, 4096);
+	
+	if (bh) {
+		memcpy (buffer, bh->b_data, bufsize);
+	} else {
+		printk(KERN_ERR "pdcraid: Error reading superblock.\n");
+		goto abort;
+	}
+	ret = 0;
+abort:
+	if (bh)
+		brelse (bh);
+	return ret;
+}
+
+static unsigned int calc_sb_csum (unsigned int* ptr)
+{	
+	unsigned int sum;
+	int count;
+	
+	sum = 0;
+	for (count=0;count<511;count++)
+		sum += *ptr++;
+	
+	return sum;
+}
+
+static int cookie = 0;
+
+static void __init probedisk(int devindex,int device, int raidlevel)
+{
+	int i;
+	int major, minor;
+        struct promise_raid_conf *prom;
+	static unsigned char block[4096];
+	struct block_device *bdev;
+
+	if (devlist[devindex].device!=-1) /* already assigned to another array */
+		return;
+	
+	major = devlist[devindex].major;
+	minor = devlist[devindex].minor; 
+
+        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
+        	return;
+                                                                                                                 
+        prom = (struct promise_raid_conf*)&block[512];
+
+        /* the checksums must match */
+	if (prom->checksum != calc_sb_csum((unsigned int*)prom))
+		return;
+	if (prom->raid.type!=raidlevel) /* different raidlevel */
+		return;
+
+	if ((cookie!=0) && (cookie != prom->raid.magic_1)) /* different array */
+		return;
+	
+	cookie = prom->raid.magic_1;
+
+	/* This looks evil. But basically, we have to search for our adapternumber
+	   in the arraydefinition, both of which are in the superblock */	
+        for (i=0;(i<prom->raid.total_disks)&&(i<8);i++) {
+        	if ( (prom->raid.disk[i].channel== prom->raid.channel) &&
+        	     (prom->raid.disk[i].device == prom->raid.device) ) {
+
+        	        bdev = bdget(MKDEV(major,minor));
+        	        if (bdev && blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW) == 0) {
+				raid[device].disk[i].bdev = bdev;
+			}
+			raid[device].disk[i].device = MKDEV(major,minor);
+			raid[device].disk[i].sectors = prom->raid.disk_secs;
+			raid[device].stride = (1<<prom->raid.raid0_shift);
+			raid[device].disks = prom->raid.total_disks;
+			raid[device].sectors = prom->raid.total_secs;
+			raid[device].geom.heads = prom->raid.heads+1;
+			raid[device].geom.sectors = prom->raid.sectors;
+			raid[device].geom.cylinders = prom->raid.cylinders+1;
+			devlist[devindex].device=device;
+        	     }
+        }
+	               
+}
+
+static void __init fill_cutoff(int device)
+{
+	int i,j;
+	unsigned long smallest;
+	unsigned long bar;
+	int count;
+	
+	bar = 0;
+	for (i=0;i<8;i++) {
+		smallest = ~0;
+		for (j=0;j<8;j++) 
+			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
+				smallest = raid[device].disk[j].sectors;
+		count = 0;
+		for (j=0;j<8;j++) 
+			if (raid[device].disk[j].sectors >= smallest)
+				count++;
+				
+		smallest = smallest * count;
+		bar = smallest;
+		raid[device].cutoff[i] = smallest;
+		raid[device].cutoff_disks[i] = count;
+	}
+}
+			   
+static __init int pdcraid_init_one(int device,int raidlevel)
+{
+	int i, count;
+
+	for (i=0; i<14; i++)
+		probedisk(i, device, raidlevel);
+	
+	if (raidlevel==0)
+		fill_cutoff(device);
+	
+	/* Initialize the gendisk structure */
+	
+	ataraid_register_disk(device,raid[device].sectors);        
+		
+	count=0;
+	
+	for (i=0;i<8;i++) {
+		if (raid[device].disk[i].device!=0) {
+			printk(KERN_INFO "Drive %i is %li Mb (%i / %i) \n",
+				i,raid[device].disk[i].sectors/2048,MAJOR(raid[device].disk[i].device),MINOR(raid[device].disk[i].device));
+			count++;
+		}
+	}
+	if (count) {
+		printk(KERN_INFO "Raid%i array consists of %i drives. \n",raidlevel,count);
+		return 0;
+	} else {
+		return -ENODEV;
+	}
+}
+
+static __init int pdcraid_init(void)
+{
+	int retval, device, count = 0;
+
+	do {
+		cookie = 0;
+		device=ataraid_get_device(&pdcraid0_ops);
+		if (device<0)
+			break;
+		retval = pdcraid_init_one(device,0);
+		if (retval) {
+			ataraid_release_device(device);
+			break;
+		} else {
+			count++;
+		}
+	} while (1);
+
+	do {
+	
+		cookie = 0;
+		device=ataraid_get_device(&pdcraid1_ops);
+		if (device<0)
+			break;
+		retval = pdcraid_init_one(device,1);
+		if (retval) {
+			ataraid_release_device(device);
+			break;
+		} else {
+			count++;
+		}
+	} while (1);
+
+	if (count) {
+		printk(KERN_INFO "Promise Fasttrak(tm) Softwareraid driver for linux version 0.03beta\n");
+		return 0;
+	}
+	printk(KERN_DEBUG "Promise Fasttrak(tm) Softwareraid driver 0.03beta: No raid array found\n");
+	return -ENODEV;
+}
+
+static void __exit pdcraid_exit (void)
+{
+	int i,device;
+	for (device = 0; device<16; device++) {
+		for (i=0;i<8;i++) {
+			struct block_device *bdev = raid[device].disk[i].bdev;
+			raid[device].disk[i].bdev = NULL;
+			if (bdev)
+				blkdev_put(bdev, BDEV_RAW);
+		}	
+		if (raid[device].sectors)
+			ataraid_release_device(device);
+	}
+}
+
+static int pdcraid_open(struct inode * inode, struct file * filp) 
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+static int pdcraid_release(struct inode * inode, struct file * filp)
+{	
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+module_init(pdcraid_init);
+module_exit(pdcraid_exit);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/pdcraid.h linux-2.4.21/drivers/ide/raid/pdcraid.h
--- linux-2.4.20/drivers/ide/raid/pdcraid.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/raid/pdcraid.h	2002-12-18 18:58:04.000000000 +0000
@@ -0,0 +1,47 @@
+struct promise_raid_conf {
+    char                promise_id[24];
+
+    u32             dummy_0;
+    u32             magic_0;
+    u32             dummy_1;
+    u32             magic_1;
+    u16             dummy_2;
+    u8              filler1[470];
+    struct {
+        u32 flags;                          /* 0x200 */
+        u8          dummy_0;
+        u8          disk_number;
+        u8          channel;
+        u8          device;
+        u32         magic_0;
+        u32         dummy_1;
+        u32         dummy_2;                /* 0x210 */
+        u32         disk_secs;
+        u32         dummy_3;
+        u16         dummy_4;
+        u8          status;
+        u8          type;
+        u8        total_disks;            /* 0x220 */
+        u8        raid0_shift;
+        u8        raid0_disks;
+        u8        array_number;
+        u32       total_secs;
+        u16       cylinders;
+        u8        heads;
+        u8        sectors;
+        u32         magic_1;
+        u32         dummy_5;                /* 0x230 */
+        struct {
+            u16     dummy_0;
+            u8      channel;
+            u8      device;
+            u32     magic_0;
+            u32     disk_number;
+        } disk[8];
+    } raid;
+    u32             filler2[346];
+    u32            checksum;
+};
+
+#define PR_MAGIC        "Promise Technology, Inc."
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/rapide.c linux-2.4.21/drivers/ide/rapide.c
--- linux-2.4.20/drivers/ide/rapide.c	2001-10-11 16:14:32.000000000 +0000
+++ linux-2.4.21/drivers/ide/rapide.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,94 +0,0 @@
-/*
- * linux/drivers/ide/rapide.c
- *
- * Copyright (c) 1996-1998 Russell King.
- *
- * Changelog:
- *  08-06-1996	RMK	Created
- *  13-04-1998	RMK	Added manufacturer and product IDs
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/errno.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/ecard.h>
-
-static card_ids __init rapide_cids[] = {
-	{ MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 },
-	{ 0xffff, 0xffff }
-};
-
-static struct expansion_card *ec[MAX_ECARDS];
-static int result[MAX_ECARDS];
-
-static inline int rapide_register(struct expansion_card *ec)
-{
-	unsigned long port = ecard_address (ec, ECARD_MEMC, 0);
-	hw_regs_t hw;
-
-	int i;
-
-	memset(&hw, 0, sizeof(hw));
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw.io_ports[i] = (ide_ioreg_t)port;
-		port += 1 << 4;
-	}
-	hw.io_ports[IDE_CONTROL_OFFSET] = port + 0x206;
-	hw.irq = ec->irq;
-
-	return ide_register_hw(&hw, NULL);
-}
-
-int __init rapide_init(void)
-{
-	int i;
-
-	for (i = 0; i < MAX_ECARDS; i++)
-		ec[i] = NULL;
-
-	ecard_startfind();
-
-	for (i = 0; ; i++) {
-		if ((ec[i] = ecard_find(0, rapide_cids)) == NULL)
-			break;
-
-		ecard_claim(ec[i]);
-		result[i] = rapide_register(ec[i]);
-	}
-	for (i = 0; i < MAX_ECARDS; i++)
-		if (ec[i] && result[i] < 0) {
-			ecard_release(ec[i]);
-			ec[i] = NULL;
-	}
-	return 0;
-}
-
-#ifdef MODULE
-MODULE_LICENSE("GPL");
-
-int init_module (void)
-{
-	return rapide_init();
-}
-
-void cleanup_module (void)
-{
-	int i;
-
-	for (i = 0; i < MAX_ECARDS; i++)
-		if (ec[i]) {
-			unsigned long port;
-			port = ecard_address(ec[i], ECARD_MEMC, 0);
-
-			ide_unregister_port(port, ec[i]->irq, 16);
-			ecard_release(ec[i]);
-			ec[i] = NULL;
-		}
-}
-#endif
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/rz1000.c linux-2.4.21/drivers/ide/rz1000.c
--- linux-2.4.20/drivers/ide/rz1000.c	2001-05-01 23:05:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/rz1000.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,97 +0,0 @@
-/*
- *  linux/drivers/ide/rz1000.c		Version 0.05	December 8, 1997
- *
- *  Copyright (C) 1995-1998  Linus Torvalds & author (see below)
- */
-
-/*
- *  Principal Author:  mlord@pobox.com (Mark Lord)
- *
- *  See linux/MAINTAINERS for address of current maintainer.
- *
- *  This file provides support for disabling the buggy read-ahead
- *  mode of the RZ1000 IDE chipset, commonly used on Intel motherboards.
- *
- *  Dunno if this fixes both ports, or only the primary port (?).
- */
-
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-
-#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#ifdef CONFIG_BLK_DEV_IDEPCI
-
-void __init ide_init_rz1000 (ide_hwif_t *hwif)	/* called from ide-pci.c */
-{
-	unsigned short reg;
-	struct pci_dev *dev = hwif->pci_dev;
-
-	hwif->chipset = ide_rz1000;
-	if (!pci_read_config_word (dev, 0x40, &reg)
-	 && !pci_write_config_word(dev, 0x40, reg & 0xdfff))
-	{
-		printk("%s: disabled chipset read-ahead (buggy RZ1000/RZ1001)\n", hwif->name);
-	} else {
-		hwif->serialized = 1;
-		hwif->drives[0].no_unmask = 1;
-		hwif->drives[1].no_unmask = 1;
-		printk("%s: serialized, disabled unmasking (buggy RZ1000/RZ1001)\n", hwif->name);
-	}
-}
-
-#else
-
-static void __init init_rz1000 (struct pci_dev *dev, const char *name)
-{
-	unsigned short reg, h;
-
-	if (!pci_read_config_word (dev, PCI_COMMAND, &reg) && !(reg & PCI_COMMAND_IO)) {
-		printk("%s: buggy IDE controller disabled (BIOS)\n", name);
-		return;
-	}
-	if (!pci_read_config_word (dev, 0x40, &reg)
-	 && !pci_write_config_word(dev, 0x40, reg & 0xdfff))
-	{
-		printk("IDE: disabled chipset read-ahead (buggy %s)\n", name);
-	} else {
-		for (h = 0; h < MAX_HWIFS; ++h) {
-			ide_hwif_t *hwif = &ide_hwifs[h];
-			if ((hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0 || hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
-			 && (hwif->chipset == ide_unknown || hwif->chipset == ide_generic))
-			{
-				hwif->chipset = ide_rz1000;
-				hwif->serialized = 1;
-				hwif->drives[0].no_unmask = 1;
-				hwif->drives[1].no_unmask = 1;
-				if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
-					hwif->channel = 1;
-				printk("%s: serialized, disabled unmasking (buggy %s)\n", hwif->name, name);
-			}
-		}
-	}
-}
-
-void __init ide_probe_for_rz100x (void)	/* called from ide.c */
-{
-	struct pci_dev *dev = NULL;
-
-	while ((dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, dev))!=NULL)
-		init_rz1000 (dev, "RZ1000");
-	while ((dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, dev))!=NULL)
-		init_rz1000 (dev, "RZ1001");
-}
-
-#endif /* CONFIG_BLK_DEV_IDEPCI */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/serverworks.c linux-2.4.21/drivers/ide/serverworks.c
--- linux-2.4.20/drivers/ide/serverworks.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/serverworks.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,675 +0,0 @@
-/*
- * linux/drivers/ide/serverworks.c		Version 0.3	26 Oct 2001
- *
- * May be copied or modified under the terms of the GNU General Public License
- *
- * Copyright (C) 1998-2000 Michel Aubry
- * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
- * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
- * Portions copyright (c) 2001 Sun Microsystems
- *
- *
- * RCC/ServerWorks IDE driver for Linux
- *
- *   OSB4: `Open South Bridge' IDE Interface (fn 1)
- *         supports UDMA mode 2 (33 MB/s)
- *
- *   CSB5: `Champion South Bridge' IDE Interface (fn 1)
- *         all revisions support UDMA mode 4 (66 MB/s)
- *         revision A2.0 and up support UDMA mode 5 (100 MB/s)
- *
- *         *** The CSB5 does not provide ANY register ***
- *         *** to detect 80-conductor cable presence. ***
- *
- *
- * here's the default lspci:
- *
- * 00:0f.1 IDE interface: ServerWorks: Unknown device 0211 (prog-if 8a [Master SecP PriP])
- *	Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B-
- *	Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
- *	Latency: 255
- *	Region 4: I/O ports at c200
- * 00: 66 11 11 02 05 01 00 02 00 8a 01 01 00 ff 80 00
- * 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 20: 01 c2 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 40: 99 99 99 99 ff ff ff ff 0c 0c 00 00 00 00 00 00
- * 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- *
- * 00:0f.1 IDE interface: ServerWorks: Unknown device 0212 (rev 92) (prog-if 8a [Master SecP PriP])
- *         Subsystem: ServerWorks: Unknown device 0212
- *         Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
- *         Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
- *         Latency: 64, cache line size 08
- *         Region 0: I/O ports at 01f0
- *         Region 1: I/O ports at 03f4
- *         Region 2: I/O ports at 0170
- *         Region 3: I/O ports at 0374
- *         Region 4: I/O ports at 08b0
- *         Region 5: I/O ports at 1000
- *
- * 00:0f.1 IDE interface: ServerWorks: Unknown device 0212 (rev 92)
- * 00: 66 11 12 02 05 00 00 02 92 8a 01 01 08 40 80 00
- * 10: f1 01 00 00 f5 03 00 00 71 01 00 00 75 03 00 00
- * 20: b1 08 00 00 01 10 00 00 00 00 00 00 66 11 12 02
- * 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 40: 4f 4f 4f 4f 20 ff ff ff f0 50 44 44 00 00 00 00
- * 50: 00 00 00 00 07 00 44 02 0f 04 03 00 00 00 00 00
- * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- *
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_SVWKS_TIMINGS	1
-#undef SVWKS_DEBUG_DRIVE_INFO
-
-#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static struct pci_dev *bmide_dev;
-static byte svwks_revision = 0;
-
-static int svwks_get_info(char *, char **, off_t, int);
-extern int (*svwks_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-
-static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-	u32 reg40, reg44;
-	u16 reg48, reg56;
-	u8  reg54, c0=0, c1=0;
-
-	pci_read_config_dword(bmide_dev, 0x40, &reg40);
-	pci_read_config_dword(bmide_dev, 0x44, &reg44);
-	pci_read_config_word(bmide_dev, 0x48, &reg48);
-	pci_read_config_byte(bmide_dev, 0x54, &reg54);
-	pci_read_config_word(bmide_dev, 0x56, &reg56);
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
-			p += sprintf(p, "\n                            "
-				     "ServerWorks CSB5 Chipset (rev %02x)\n",
-				     svwks_revision);
-			break;
-		case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
-			p += sprintf(p, "\n                            "
-				     "ServerWorks OSB4 Chipset (rev %02x)\n",
-				     svwks_revision);
-			break;
-		default:
-			p += sprintf(p, "\n                            "
-				     "ServerWorks %04x Chipset (rev %02x)\n",
-				     bmide_dev->device, svwks_revision);
-			break;
-	}
-
-	p += sprintf(p, "------------------------------- General Status ---------------------------------\n");
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %sabled                         %sabled\n",
-			(c0&0x80) ? "dis" : " en",
-			(c1&0x80) ? "dis" : " en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	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 " );
-	p += sprintf(p, "UDMA enabled:   %s              %s             %s               %s\n",
-			(reg54 & 0x01) ? "yes" : "no ",
-			(reg54 & 0x02) ? "yes" : "no ",
-			(reg54 & 0x04) ? "yes" : "no ",
-			(reg54 & 0x08) ? "yes" : "no " );
-	p += sprintf(p, "UDMA enabled:   %s                %s               %s                 %s\n",
-			((reg56&0x0005)==0x0005)?"5":
-				((reg56&0x0004)==0x0004)?"4":
-				((reg56&0x0003)==0x0003)?"3":
-				((reg56&0x0002)==0x0002)?"2":
-				((reg56&0x0001)==0x0001)?"1":
-				((reg56&0x000F))?"?":"0",
-			((reg56&0x0050)==0x0050)?"5":
-				((reg56&0x0040)==0x0040)?"4":
-				((reg56&0x0030)==0x0030)?"3":
-				((reg56&0x0020)==0x0020)?"2":
-				((reg56&0x0010)==0x0010)?"1":
-				((reg56&0x00F0))?"?":"0",
-			((reg56&0x0500)==0x0500)?"5":
-				((reg56&0x0400)==0x0400)?"4":
-				((reg56&0x0300)==0x0300)?"3":
-				((reg56&0x0200)==0x0200)?"2":
-				((reg56&0x0100)==0x0100)?"1":
-				((reg56&0x0F00))?"?":"0",
-			((reg56&0x5000)==0x5000)?"5":
-				((reg56&0x4000)==0x4000)?"4":
-				((reg56&0x3000)==0x3000)?"3":
-				((reg56&0x2000)==0x2000)?"2":
-				((reg56&0x1000)==0x1000)?"1":
-				((reg56&0xF000))?"?":"0");
-	p += sprintf(p, "DMA enabled:    %s                %s               %s                 %s\n",
-			((reg44&0x00002000)==0x00002000)?"2":
-				((reg44&0x00002100)==0x00002100)?"1":
-				((reg44&0x00007700)==0x00007700)?"0":
-				((reg44&0x0000FF00)==0x0000FF00)?"X":"?",
-			((reg44&0x00000020)==0x00000020)?"2":
-				((reg44&0x00000021)==0x00000021)?"1":
-				((reg44&0x00000077)==0x00000077)?"0":
-				((reg44&0x000000FF)==0x000000FF)?"X":"?",
-			((reg44&0x20000000)==0x20000000)?"2":
-				((reg44&0x21000000)==0x21000000)?"1":
-				((reg44&0x77000000)==0x77000000)?"0":
-				((reg44&0xFF000000)==0xFF000000)?"X":"?",
-			((reg44&0x00200000)==0x00200000)?"2":
-				((reg44&0x00210000)==0x00210000)?"1":
-				((reg44&0x00770000)==0x00770000)?"0":
-				((reg44&0x00FF0000)==0x00FF0000)?"X":"?");
-
-		p += sprintf(p, "PIO  enabled:   %s                %s               %s                 %s\n",
-			((reg40&0x00002000)==0x00002000)?"4":
-				((reg40&0x00002200)==0x00002200)?"3":
-				((reg40&0x00003400)==0x00003400)?"2":
-				((reg40&0x00004700)==0x00004700)?"1":
-				((reg40&0x00005D00)==0x00005D00)?"0":"?",
-			((reg40&0x00000020)==0x00000020)?"4":
-				((reg40&0x00000022)==0x00000022)?"3":
-				((reg40&0x00000034)==0x00000034)?"2":
-				((reg40&0x00000047)==0x00000047)?"1":
-				((reg40&0x0000005D)==0x0000005D)?"0":"?",
-			((reg40&0x20000000)==0x20000000)?"4":
-				((reg40&0x22000000)==0x22000000)?"3":
-				((reg40&0x34000000)==0x34000000)?"2":
-				((reg40&0x47000000)==0x47000000)?"1":
-				((reg40&0x5D000000)==0x5D000000)?"0":"?",
-			((reg40&0x00200000)==0x00200000)?"4":
-				((reg40&0x00220000)==0x00220000)?"3":
-				((reg40&0x00340000)==0x00340000)?"2":
-				((reg40&0x00470000)==0x00470000)?"1":
-				((reg40&0x005D0000)==0x005D0000)?"0":"?");
-	return p-buffer;	 /* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-#define SVWKS_CSB5_REVISION_NEW	0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
-
-byte svwks_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-static struct pci_dev *isa_dev;
-
-static int svwks_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	byte udma_modes[]	= { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
-	byte dma_modes[]	= { 0x77, 0x21, 0x20 };
-	byte pio_modes[]	= { 0x5d, 0x47, 0x34, 0x22, 0x20 };
-
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte unit		= (drive->select.b.unit & 0x01);
-	byte csb5		= (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	unsigned long dma_base	= hwif->dma_base;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	int err;
-
-	byte drive_pci		= 0x00;
-	byte drive_pci2		= 0x00;
-	byte drive_pci3		= hwif->channel ? 0x57 : 0x56;
-
-	byte ultra_enable	= 0x00;
-	byte ultra_timing	= 0x00;
-	byte dma_timing		= 0x00;
-	byte pio_timing		= 0x00;
-	unsigned short csb5_pio	= 0x00;
-
-	byte pio	= ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-        switch (drive->dn) {
-		case 0: drive_pci = 0x41; drive_pci2 = 0x45; break;
-		case 1: drive_pci = 0x40; drive_pci2 = 0x44; break;
-		case 2: drive_pci = 0x43; drive_pci2 = 0x47; break;
-		case 3: drive_pci = 0x42; drive_pci2 = 0x46; break;
-		default:
-			return -1;
-	}
-
-	pci_read_config_byte(dev, drive_pci, &pio_timing);
-	pci_read_config_byte(dev, drive_pci2, &dma_timing);
-	pci_read_config_byte(dev, drive_pci3, &ultra_timing);
-	pci_read_config_word(dev, 0x4A, &csb5_pio);
-	pci_read_config_byte(dev, 0x54, &ultra_enable);
-
-#ifdef DEBUG
-	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
-		drive->name, ultra_timing, dma_timing, pio_timing);
-#endif
-
-	pio_timing	&= ~0xFF;
-	dma_timing	&= ~0xFF;
-	ultra_timing	&= ~(0x0F << (4*unit));
-	ultra_enable	&= ~(0x01 << drive->dn);
-	csb5_pio	&= ~(0x0F << (4*drive->dn));
-
-	switch(speed) {
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-			pio_timing |= pio_modes[speed - XFER_PIO_0];
-			csb5_pio   |= ((speed - XFER_PIO_0) << (4*drive->dn));
-			break;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_MW_DMA_0:
-			pio_timing |= pio_modes[pio];
-			csb5_pio   |= (pio << (4*drive->dn));
-			dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
-			break;
-
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-			pio_timing   |= pio_modes[pio];
-			csb5_pio     |= (pio << (4*drive->dn));
-			dma_timing   |= dma_modes[2];
-			ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
-			ultra_enable |= (0x01 << drive->dn);
-#endif
-		default:
-			break;
-	}
-
-#ifdef DEBUG
-	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
-		drive->name, ultra_timing, dma_timing, pio_timing);
-#endif
-
-#if SVWKS_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* SVWKS_DEBUG_DRIVE_INFO */
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	pci_write_config_byte(dev, drive_pci, pio_timing);
-	if (csb5)
-		pci_write_config_word(dev, 0x4A, csb5_pio);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	pci_write_config_byte(dev, drive_pci2, dma_timing);
-	pci_write_config_byte(dev, drive_pci3, ultra_timing);
-	pci_write_config_byte(dev, 0x54, ultra_enable);
-	
-	if (speed > XFER_PIO_4)
-		outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-	else
-		outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return err;
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-	unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
-	unsigned short xfer_pio = drive->id->eide_pio_modes;
-	byte timing, speed, pio;
-
-	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-	if (xfer_pio> 4)
-		xfer_pio = 0;
-
-	if (drive->id->eide_pio_iordy > 0)
-		for (xfer_pio = 5;
-			xfer_pio>0 &&
-			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
-			xfer_pio--);
-	else
-		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
-			   (drive->id->eide_pio_modes & 2) ? 0x04 :
-			   (drive->id->eide_pio_modes & 1) ? 0x03 :
-			   (drive->id->tPIO & 2) ? 0x02 :
-			   (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
-
-	timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
-	switch(timing) {
-		case 4: speed = XFER_PIO_4;break;
-		case 3: speed = XFER_PIO_3;break;
-		case 2: speed = XFER_PIO_2;break;
-		case 1: speed = XFER_PIO_1;break;
-		default:
-			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
-			break;
-	}
-	(void) svwks_tune_chipset(drive, speed);
-	drive->current_speed = speed;
-}
-
-static void svwks_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-	switch(pio) {
-		case 4:		speed = XFER_PIO_4;break;
-		case 3:		speed = XFER_PIO_3;break;
-		case 2:		speed = XFER_PIO_2;break;
-		case 1:		speed = XFER_PIO_1;break;
-		default:	speed = XFER_PIO_0;break;
-	}
-	(void) svwks_tune_chipset(drive, speed);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	byte udma_66	= eighty_ninty_three(drive);
-	int ultra66	= (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
-	int ultra100 	= (ultra66 && svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 1 : 0;
-	byte speed;
-
-	if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) {
-		speed = XFER_UDMA_5;
-	} else if (id->dma_ultra & 0x0010) {
-		speed = ((udma_66) && (ultra66)) ? XFER_UDMA_4 : XFER_UDMA_2;
-	} else if (id->dma_ultra & 0x0008) {
-		speed = ((udma_66) && (ultra66)) ? XFER_UDMA_3 : XFER_UDMA_1;
-	} else if (id->dma_ultra & 0x0004) {
-		speed = XFER_UDMA_2;
-	} else if (id->dma_ultra & 0x0002) {
-		speed = XFER_UDMA_1;
-	} else if (id->dma_ultra & 0x0001) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-	} else {
-		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-	}
-
-	(void) svwks_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		config_chipset_for_pio(drive);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-static int svwks_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_end:
-		{
-			ide_hwif_t *hwif		= HWIF(drive);
-			unsigned long dma_base		= hwif->dma_base;
-	
-			if(inb(dma_base+0x02)&1)
-			{
-#if 0		
-				int i;
-				printk(KERN_ERR "Curious - OSB4 thinks the DMA is still running.\n");
-				for(i=0;i<10;i++)
-				{
-					if(!(inb(dma_base+0x02)&1))
-					{
-						printk(KERN_ERR "OSB4 now finished.\n");
-						break;
-					}
-					udelay(5);
-				}
-#endif		
-				printk(KERN_CRIT "Serverworks OSB4 in impossible state.\n");
-				printk(KERN_CRIT "Disable UDMA or if you are using Seagate then try switching disk types\n");
-				printk(KERN_CRIT "on this controller. Please report this event to osb4-bug@ide.cabal.tm\n");
-#if 0		
-				/* Panic might sys_sync -> death by corrupt disk */
-				panic("OSB4: continuing might cause disk corruption.\n");
-#else
-				printk(KERN_CRIT "OSB4: continuing might cause disk corruption.\n");
-				while(1)
-					cpu_relax();
-#endif				
-			}
-			/* and drop through */
-		}
-		default:
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name)
-{
-	unsigned int reg;
-	byte btr;
-
-	/* save revision id to determine DMA capability */
-	pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
-
-	/* force Master Latency Timer value to 64 PCICLKs */
-	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
-
-	/* OSB4 : South Bridge and IDE */
-	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
-		isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
-			  PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
-		if (isa_dev) {
-			pci_read_config_dword(isa_dev, 0x64, &reg);
-			reg &= ~0x00002000; /* disable 600ns interrupt mask */
-			reg |=  0x00004000; /* enable UDMA/33 support */
-			pci_write_config_dword(isa_dev, 0x64, reg);
-		}
-	}
-
-	/* setup CSB5 : South Bridge and IDE */
-	else if (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) {
-		/* setup the UDMA Control register
-		 *
-		 * 1. clear bit 6 to enable DMA
-		 * 2. enable DMA modes with bits 0-1
-		 *      00 : legacy
-		 *      01 : udma2
-		 *      10 : udma2/udma4
-		 *      11 : udma2/udma4/udma5
-		 */
-		pci_read_config_byte(dev, 0x5A, &btr);
-		btr &= ~0x40;
-		btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
-		pci_write_config_byte(dev, 0x5A, btr);
-	}
-
-#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!svwks_proc) {
-		svwks_proc = 1;
-		bmide_dev = dev;
-		svwks_display_info = &svwks_get_info;
-	}
-#endif /* DISPLAY_SVWKS_TIMINGS && CONFIG_PROC_FS */
-	return 0;
-}
-
-/* On Dell PowerEdge servers with a CSB5, the top two bits of the subsystem
- * device ID indicate presence of an 80-pin cable.
- * Bit 15 clear = secondary IDE channel does not have 80-pin cable.
- * Bit 15 set   = secondary IDE channel has 80-pin cable.
- * Bit 14 clear = primary IDE channel does not have 80-pin cable.
- * Bit 14 set   = primary IDE channel has 80-pin cable.
- */
-static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev = hwif->pci_dev;
-	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
-	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
-	    dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
-		return ((1 << (hwif->channel + 14)) &
-			dev->subsystem_device) ? 1 : 0;
-	return 0;
-}
-
-/* Sun Cobalt Alpine hardware avoids the 80-pin cable
- * detect issue by attaching the drives directly to the board.
- * This check follows the Dell precedent (how scary is that?!)
- *
- * WARNING: this only works on Alpine hardware!
- */
-static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev = hwif->pci_dev;
-	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
-	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
-	    dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
-		return ((1 << (hwif->channel + 14)) &
-			dev->subsystem_device) ? 1 : 0;
-	return 0;
-}
-
-unsigned int __init ata66_svwks (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev = hwif->pci_dev;
-
-	/* Dell PowerEdge */
-	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL)
-		return ata66_svwks_dell (hwif);
-
-	/* Cobalt Alpine */
-	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN)
-		return ata66_svwks_cobalt (hwif);
-
-	return 0;
-}
-
-void __init ide_init_svwks (ide_hwif_t *hwif)
-{
-	if (!hwif->irq)
-		hwif->irq = hwif->channel ? 15 : 14;
-
-	hwif->tuneproc = &svwks_tune_drive;
-	hwif->speedproc = &svwks_tune_chipset;
-
-#ifndef CONFIG_BLK_DEV_IDEDMA
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-#else /* CONFIG_BLK_DEV_IDEDMA */
-	if (hwif->dma_base) {
-#ifdef CONFIG_IDEDMA_AUTO
-		if (!noautodma)
-			hwif->autodma = 1;
-#endif	
-		hwif->dmaproc = &svwks_dmaproc;
-	} else {
-		hwif->autodma = 0;
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-	}
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/setup-pci.c linux-2.4.21/drivers/ide/setup-pci.c
--- linux-2.4.20/drivers/ide/setup-pci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/ide/setup-pci.c	2002-12-18 18:58:09.000000000 +0000
@@ -0,0 +1,837 @@
+/*
+ *  linux/drivers/ide/setup-pci.c		Version 1.10	2002/08/19
+ *
+ *  Copyright (c) 1998-2000  Andre Hedrick <andre@linux-ide.org>
+ *
+ *  Copyright (c) 1995-1998  Mark Lord
+ *  May be copied or modified under the terms of the GNU General Public License
+ *
+ *  Recent Changes
+ *	Split the set up function into multiple functions
+ *	Use pci_set_master
+ *	Fix misreporting of I/O v MMIO problems
+ *	Initial fixups for simplex devices
+ */
+
+/*
+ *  This module provides support for automatic detection and
+ *  configuration of all PCI IDE interfaces present in a system.  
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+
+/**
+ *	ide_match_hwif	-	match a PCI IDE against an ide_hwif
+ *	@io_base: I/O base of device
+ *	@bootable: set if its bootable
+ *	@name: name of device
+ *
+ *	Match a PCI IDE port against an entry in ide_hwifs[],
+ *	based on io_base port if possible. Return the matching hwif,
+ *	or a new hwif. If we find an error (clashing, out of devices, etc)
+ *	return NULL
+ *
+ *	FIXME: we need to handle mmio matches here too
+ */
+
+static ide_hwif_t *ide_match_hwif(unsigned long io_base, u8 bootable, const char *name)
+{
+	int h;
+	ide_hwif_t *hwif;
+
+	/*
+	 * Look for a hwif with matching io_base specified using
+	 * parameters to ide_setup().
+	 */
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		hwif = &ide_hwifs[h];
+		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
+			if (hwif->chipset == ide_generic)
+				return hwif; /* a perfect match */
+		}
+	}
+	/*
+	 * Look for a hwif with matching io_base default value.
+	 * If chipset is "ide_unknown", then claim that hwif slot.
+	 * Otherwise, some other chipset has already claimed it..  :(
+	 */
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		hwif = &ide_hwifs[h];
+		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
+			if (hwif->chipset == ide_unknown)
+				return hwif; /* match */
+			printk(KERN_ERR "%s: port 0x%04lx already claimed by %s\n",
+				name, io_base, hwif->name);
+			return NULL;	/* already claimed */
+		}
+	}
+	/*
+	 * Okay, there is no hwif matching our io_base,
+	 * so we'll just claim an unassigned slot.
+	 * Give preference to claiming other slots before claiming ide0/ide1,
+	 * just in case there's another interface yet-to-be-scanned
+	 * which uses ports 1f0/170 (the ide0/ide1 defaults).
+	 *
+	 * Unless there is a bootable card that does not use the standard
+	 * ports 1f0/170 (the ide0/ide1 defaults). The (bootable) flag.
+	 */
+	if (bootable) {
+		for (h = 0; h < MAX_HWIFS; ++h) {
+			hwif = &ide_hwifs[h];
+			if (hwif->chipset == ide_unknown)
+				return hwif;	/* pick an unused entry */
+		}
+	} else {
+		for (h = 2; h < MAX_HWIFS; ++h) {
+			hwif = ide_hwifs + h;
+			if (hwif->chipset == ide_unknown)
+				return hwif;	/* pick an unused entry */
+		}
+	}
+	for (h = 0; h < 2; ++h) {
+		hwif = ide_hwifs + h;
+		if (hwif->chipset == ide_unknown)
+			return hwif;	/* pick an unused entry */
+	}
+	printk(KERN_ERR "%s: too many IDE interfaces, no room in table\n", name);
+	return NULL;
+}
+
+/**
+ *	ide_setup_pci_baseregs	-	place a PCI IDE controller native
+ *	@dev: PCI device of interface to switch native
+ *	@name: Name of interface
+ *
+ *	We attempt to place the PCI interface into PCI native mode. If
+ *	we succeed the BARs are ok and the controller is in PCI mode.
+ *	Returns 0 on success or an errno code. 
+ *
+ *	FIXME: if we program the interface and then fail to set the BARS
+ *	we don't switch it back to legacy mode. Do we actually care ??
+ */
+ 
+static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *name)
+{
+	u8 progif = 0;
+
+	/*
+	 * Place both IDE interfaces into PCI "native" mode:
+	 */
+	if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
+			 (progif & 5) != 5) {
+		if ((progif & 0xa) != 0xa) {
+			printk(KERN_INFO "%s: device not capable of full "
+				"native PCI mode\n", name);
+			return -EOPNOTSUPP;
+		}
+		printk("%s: placing both ports into native PCI mode\n", name);
+		(void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
+		if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
+		    (progif & 5) != 5) {
+			printk(KERN_ERR "%s: rewrite of PROGIF failed, wanted "
+				"0x%04x, got 0x%04x\n",
+				name, progif|5, progif);
+			return -EOPNOTSUPP;
+		}
+	}
+	return 0;
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
+/*
+ * Long lost data from 2.0.34 that is now in 2.0.39
+ *
+ * This was used in ./drivers/block/triton.c to do DMA Base address setup
+ * when PnP failed.  Oh the things we forget.  I believe this was part
+ * of SFF-8038i that has been withdrawn from public access... :-((
+ */
+#define DEFAULT_BMIBA	0xe800	/* in case BIOS did not init it */
+#define DEFAULT_BMCRBA	0xcc00	/* VIA's default value */
+#define DEFAULT_BMALIBA	0xd400	/* ALI's default value */
+#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
+
+/**
+ *	ide_get_or_set_dma_base		-	setup BMIBA
+ *	@hwif: Interface
+ *
+ *	Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
+ *	If need be we set up the DMA base. Where a device has a partner that
+ *	is already in DMA mode we check and enforce IDE simplex rules.
+ */
+
+static unsigned long __init ide_get_or_set_dma_base (ide_hwif_t *hwif)
+{
+	unsigned long	dma_base = 0;
+	struct pci_dev	*dev = hwif->pci_dev;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
+	int second_chance = 0;
+
+second_chance_to_dma:
+#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
+
+	if ((hwif->mmio) && (hwif->dma_base))
+		return hwif->dma_base;
+
+	if (hwif->mate && hwif->mate->dma_base) {
+		dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
+	} else {
+		dma_base = (hwif->mmio) ?
+			((unsigned long) hwif->hwif_data) :
+			(pci_resource_start(dev, 4));
+		if (!dma_base) {
+			printk(KERN_ERR "%s: dma_base is invalid (0x%04lx)\n",
+				hwif->cds->name, dma_base);
+			dma_base = 0;
+		}
+	}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
+	/* FIXME - should use pci_assign_resource surely */
+	if ((!dma_base) && (!second_chance)) {
+		unsigned long set_bmiba = 0;
+		second_chance++;
+		switch(dev->vendor) {
+			case PCI_VENDOR_ID_AL:
+				set_bmiba = DEFAULT_BMALIBA; break;
+			case PCI_VENDOR_ID_VIA:
+				set_bmiba = DEFAULT_BMCRBA; break;
+			case PCI_VENDOR_ID_INTEL:
+				set_bmiba = DEFAULT_BMIBA; break;
+			default:
+				return dma_base;
+		}
+		pci_write_config_dword(dev, 0x20, set_bmiba|1);
+		goto second_chance_to_dma;
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
+
+	if (dma_base) {
+		u8 simplex_stat = 0;
+		dma_base += hwif->channel ? 8 : 0;
+
+		switch(dev->device) {
+			case PCI_DEVICE_ID_AL_M5219:
+			case PCI_DEVICE_ID_AL_M5229:
+			case PCI_DEVICE_ID_AMD_VIPER_7409:
+			case PCI_DEVICE_ID_CMD_643:
+			case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+				simplex_stat = hwif->INB(dma_base + 2);
+				hwif->OUTB((simplex_stat&0x60),(dma_base + 2));
+				simplex_stat = hwif->INB(dma_base + 2);
+				if (simplex_stat & 0x80) {
+					printk(KERN_INFO "%s: simplex device: "
+						"DMA forced\n",
+						hwif->cds->name);
+				}
+				break;
+			default:
+				/*
+				 * If the device claims "simplex" DMA,
+				 * this means only one of the two interfaces
+				 * can be trusted with DMA at any point in time.
+				 * So we should enable DMA only on one of the
+				 * two interfaces.
+				 */
+				simplex_stat = hwif->INB(dma_base + 2);
+				if (simplex_stat & 0x80) {
+					/* simplex device? */
+#if 0					
+/*
+ *	At this point we haven't probed the drives so we can't make the
+ *	appropriate decision. Really we should defer this problem
+ *	until we tune the drive then try to grab DMA ownership if we want
+ *	to be the DMA end. This has to be become dynamic to handle hot
+ *	plug.
+ */
+					/* Don't enable DMA on a simplex channel with no drives */
+					if (!hwif->drives[0].present && !hwif->drives[1].present)
+					{
+						printk(KERN_INFO "%s: simplex device with no drives: DMA disabled\n",
+								hwif->cds->name);
+						dma_base = 0;
+					}
+					/* If our other channel has DMA then we cannot */
+					else 
+#endif					
+					if(hwif->mate && hwif->mate->dma_base) 
+					{
+						printk(KERN_INFO "%s: simplex device: "
+							"DMA disabled\n",
+							hwif->cds->name);
+						dma_base = 0;
+					}
+				}
+		}
+	}
+	return dma_base;
+}
+
+static void ide_setup_pci_noise (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((d->vendor != dev->vendor) && (d->device != dev->device)) {
+		printk(KERN_INFO "%s: unknown IDE controller at PCI slot "
+			"%s, VID=%04x, DID=%04x\n",
+			d->name, dev->slot_name, dev->vendor, dev->device);
+        } else {
+		printk(KERN_INFO "%s: IDE controller at PCI slot %s\n",
+			d->name, dev->slot_name);
+	}
+}
+
+/**
+ *	ide_pci_enable	-	do PCI enables
+ *	@dev: PCI device
+ *	@d: IDE pci device data
+ *
+ *	Enable the IDE PCI device. We attempt to enable the device in full
+ *	but if that fails then we only need BAR4 so we will enable that.
+ *	
+ *	Returns zero on success or an error code
+ */
+ 
+static int ide_pci_enable(struct pci_dev *dev, ide_pci_device_t *d)
+{
+	
+	if (pci_enable_device(dev)) {
+		if (pci_enable_device_bars(dev, 1 << 4)) {
+			printk(KERN_WARNING "%s: (ide_setup_pci_device:) "
+				"Could not enable device.\n", d->name);
+			return -EBUSY;
+		} else
+			printk(KERN_WARNING "%s: Not fully BIOS configured!\n", d->name);
+	}
+
+	/*
+	 * assume all devices can do 32-bit dma for now. we can add a
+	 * dma mask field to the ide_pci_device_t if we need it (or let
+	 * lower level driver set the dma mask)
+	 */
+	if (pci_set_dma_mask(dev, 0xffffffff)) {
+		printk(KERN_ERR "%s: can't set dma mask\n", d->name);
+		return -EBUSY;
+	}
+	 
+	/* FIXME: Temporary - until we put in the hotplug interface logic
+	   Check that the bits we want are not in use by someone else */
+	if (pci_request_region(dev, 4, "ide_tmp"))
+		return -EBUSY;
+	pci_release_region(dev, 4);
+	
+	return 0;	
+}
+
+/**
+ *	ide_pci_configure	-	configure an unconfigured device
+ *	@dev: PCI device
+ *	@d: IDE pci device data
+ *
+ *	Enable and configure the PCI device we have been passed.
+ *	Returns zero on success or an error code.
+ */
+ 
+static int ide_pci_configure(struct pci_dev *dev, ide_pci_device_t *d)
+{
+	u16 pcicmd = 0;
+	/*
+	 * PnP BIOS was *supposed* to have setup this device, but we
+	 * can do it ourselves, so long as the BIOS has assigned an IRQ
+	 * (or possibly the device is using a "legacy header" for IRQs).
+	 * Maybe the user deliberately *disabled* the device,
+	 * but we'll eventually ignore it again if no drives respond.
+	 */
+	if (ide_setup_pci_baseregs(dev, d->name) || pci_write_config_word(dev, PCI_COMMAND, pcicmd|PCI_COMMAND_IO)) 
+	{
+		printk(KERN_INFO "%s: device disabled (BIOS)\n", d->name);
+		return -ENODEV;
+	}
+	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
+		printk(KERN_ERR "%s: error accessing PCI regs\n", d->name);
+		return -EIO;
+	}
+	if (!(pcicmd & PCI_COMMAND_IO)) {
+		printk(KERN_ERR "%s: unable to enable IDE controller\n", d->name);
+		return -ENXIO;
+	}
+	return 0;
+}
+
+/**
+ *	ide_pci_check_iomem	-	check a register is I/O
+ *	@dev: pci device
+ *	@d: ide_pci_device
+ *	@bar: bar number
+ *
+ *	Checks if a BAR is configured and points to MMIO space. If so
+ *	print an error and return an error code. Otherwise return 0
+ */
+ 
+static int ide_pci_check_iomem(struct pci_dev *dev, ide_pci_device_t *d, int bar)
+{
+	ulong flags = pci_resource_flags(dev, bar);
+	
+	/* Unconfigured ? */
+	if (!flags || pci_resource_len(dev, bar) == 0)
+		return 0;
+
+	/* I/O space */		
+	if(flags & PCI_BASE_ADDRESS_IO_MASK)
+		return 0;
+		
+	/* Bad */
+	printk(KERN_ERR "%s: IO baseregs (BIOS) are reported "
+			"as MEM, report to "
+			"<andre@linux-ide.org>.\n", d->name);
+	return -EINVAL;
+}
+	
+		
+/**
+ *	ide_hwif_configure	-	configure an IDE interface
+ *	@dev: PCI device holding interface
+ *	@d: IDE pci data
+ *	@mate: Paired interface if any
+ *
+ *	Perform the initial set up for the hardware interface structure. This
+ *	is done per interface port rather than per PCI device. There may be
+ *	more than one port per device.
+ *
+ *	Returns the new hardware interface structure, or NULL on a failure
+ */
+ 
+static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *mate, int port, int irq)
+{
+	unsigned long ctl = 0, base = 0;
+	ide_hwif_t *hwif;
+
+	/*  Possibly we should fail if these checks report true */
+	ide_pci_check_iomem(dev, d, 2*port);
+	ide_pci_check_iomem(dev, d, 2*port+1);
+ 
+	ctl  = pci_resource_start(dev, 2*port+1);
+	base = pci_resource_start(dev, 2*port);
+	if ((ctl && !base) || (base && !ctl)) {
+		printk(KERN_ERR "%s: inconsistent baseregs (BIOS) "
+			"for port %d, skipping\n", d->name, port);
+		return NULL;
+	}
+	if (!ctl)
+	{
+		/* Use default values */
+		ctl = port ? 0x374 : 0x3f4;
+		base = port ? 0x170 : 0x1f0;
+	}
+	if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL)
+		return NULL;	/* no room in ide_hwifs[] */
+	if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
+fixup_address:
+		ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL);
+		memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
+	} else if (hwif->io_ports[IDE_CONTROL_OFFSET] != (ctl | 2)) {
+		goto fixup_address;
+	}
+	hwif->chipset = ide_pci;
+	hwif->pci_dev = dev;
+	hwif->cds = (struct ide_pci_device_s *) d;
+	hwif->channel = port;
+
+	if (!hwif->irq)
+		hwif->irq = irq;
+	if (mate) {
+		hwif->mate = mate;
+		mate->mate = hwif;
+	}
+	return hwif;
+}
+
+/**
+ *	ide_hwif_setup_dma	-	configure DMA interface
+ *	@dev: PCI device
+ *	@d: IDE pci data
+ *	@hwif: Hardware interface we are configuring
+ *
+ *	Set up the DMA base for the interface. Enable the master bits as
+ *	neccessary and attempt to bring the device DMA into a ready to use
+ *	state
+ */
+ 
+static void ide_hwif_setup_dma(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *hwif)
+{
+	u16 pcicmd;
+	pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
+
+	if ((d->autodma == AUTODMA) ||
+	    ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
+	     (dev->class & 0x80))) {
+		unsigned long dma_base = ide_get_or_set_dma_base(hwif);
+		if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) {
+			/*
+ 			 * Set up BM-DMA capability
+			 * (PnP BIOS should have done this)
+ 			 */
+			if (!((d->device == PCI_DEVICE_ID_CYRIX_5530_IDE && d->vendor == PCI_VENDOR_ID_CYRIX)
+			    ||(d->device == PCI_DEVICE_ID_NS_SCx200_IDE && d->vendor == PCI_VENDOR_ID_NS)))
+			{
+				/*
+				 * default DMA off if we had to
+				 * configure it here
+				 */
+				hwif->autodma = 0;
+			}
+			pci_set_master(dev);
+			if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) || !(pcicmd & PCI_COMMAND_MASTER)) {
+				printk(KERN_ERR "%s: %s error updating PCICMD\n",
+					hwif->name, d->name);
+				dma_base = 0;
+			}
+		}
+		if (dma_base) {
+			if (d->init_dma) {
+				d->init_dma(hwif, dma_base);
+			} else {
+				ide_setup_dma(hwif, dma_base, 8);
+			}
+		} else {
+			printk(KERN_INFO "%s: %s Bus-Master DMA disabled "
+				"(BIOS)\n", hwif->name, d->name);
+		}
+	}
+}
+
+/**
+ *	ide_setup_pci_controller	-	set up IDE PCI
+ *	@dev: PCI device
+ *	@d: IDE PCI data
+ *	@noisy: verbose flag
+ *	@config: returned as 1 if we configured the hardware
+ *
+ *	Set up the PCI and controller side of the IDE interface. This brings
+ *	up the PCI side of the device, checks that the device is enabled
+ *	and enables it if need be
+ */
+ 
+static int ide_setup_pci_controller(struct pci_dev *dev, ide_pci_device_t *d, int noisy, int *config)
+{
+	int ret = 0;
+	u32 class_rev;
+	u16 pcicmd;
+
+	if (!noautodma)
+		ret = 1;
+
+	if (noisy)
+		ide_setup_pci_noise(dev, d);
+
+	if (ide_pci_enable(dev, d))
+		return -EBUSY;
+		
+	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
+		printk(KERN_ERR "%s: error accessing PCI regs\n", d->name);
+		return -EIO;
+	}
+	if (!(pcicmd & PCI_COMMAND_IO)) {	/* is device disabled? */
+		if (ide_pci_configure(dev, d))
+			return -ENODEV;
+		/* default DMA off if we had to configure it here */
+		ret = 0;
+		*config = 1;
+		printk(KERN_INFO "%s: device enabled (Linux)\n", d->name);
+	}
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+	if (noisy)
+		printk(KERN_INFO "%s: chipset revision %d\n", d->name, class_rev);
+	return ret;
+}
+
+/*
+ * ide_setup_pci_device() looks at the primary/secondary interfaces
+ * on a PCI IDE device and, if they are enabled, prepares the IDE driver
+ * for use with them.  This generic code works for most PCI chipsets.
+ *
+ * One thing that is not standardized is the location of the
+ * primary/secondary interface "enable/disable" bits.  For chipsets that
+ * we "know" about, this information is in the ide_pci_device_t struct;
+ * for all other chipsets, we just assume both interfaces are enabled.
+ */
+static ata_index_t do_ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d, u8 noisy)
+{
+	u32 port, at_least_one_hwif_enabled = 0, autodma = 0;
+	int pciirq = 0;
+	int tried_config = 0;
+	int drive0_tune, drive1_tune;
+	ata_index_t index;
+	u8 tmp = 0;
+	ide_hwif_t *hwif, *mate = NULL;
+	static int secondpdc = 0;
+
+	index.all = 0xf0f0;
+
+	if((autodma = ide_setup_pci_controller(dev, d, noisy, &tried_config)) < 0)
+		return index;
+
+	/*
+	 * Can we trust the reported IRQ?
+	 */
+	pciirq = dev->irq;
+	
+	if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) {
+		if (noisy)
+			printk(KERN_INFO "%s: not 100%% native mode: "
+				"will probe irqs later\n", d->name);
+		/*
+		 * This allows offboard ide-pci cards the enable a BIOS,
+		 * verify interrupt settings of split-mirror pci-config
+		 * space, place chipset into init-mode, and/or preserve
+		 * an interrupt if the card is not native ide support.
+		 */
+		pciirq = (d->init_chipset) ? d->init_chipset(dev, d->name) : 0;
+	} else if (tried_config) {
+		if (noisy)
+			printk(KERN_INFO "%s: will probe irqs later\n", d->name);
+		pciirq = 0;
+	} else if (!pciirq) {
+		if (noisy)
+			printk(KERN_WARNING "%s: bad irq (%d): will probe later\n",
+				d->name, pciirq);
+		pciirq = 0;
+	} else {
+		if (d->init_chipset)
+		{
+			if(d->init_chipset(dev, d->name) < 0)
+				return index;
+		}
+		if (noisy)
+#ifdef __sparc__
+			printk(KERN_INFO "%s: 100%% native mode on irq %s\n",
+			       d->name, __irq_itoa(pciirq));
+#else
+			printk(KERN_INFO "%s: 100%% native mode on irq %d\n",
+				d->name, pciirq);
+#endif
+	}
+	
+	if(pciirq < 0)		/* Error not an IRQ */
+		return index;
+
+	/*
+	 * Set up the IDE ports
+	 */
+	 
+	for (port = 0; port <= 1; ++port) {
+		ide_pci_enablebit_t *e = &(d->enablebits[port]);
+	
+		/* 
+		 * If this is a Promise FakeRaid controller,
+		 * the 2nd controller will be marked as 
+		 * disabled while it is actually there and enabled
+		 * by the bios for raid purposes. 
+		 * Skip the normal "is it enabled" test for those.
+		 */
+		if (((d->vendor == PCI_VENDOR_ID_PROMISE) &&
+		     ((d->device == PCI_DEVICE_ID_PROMISE_20262) ||
+		      (d->device == PCI_DEVICE_ID_PROMISE_20265))) &&
+		    (secondpdc++==1) && (port==1))
+			goto controller_ok;
+			
+		if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
+		    (tmp & e->mask) != e->val))
+			continue;	/* port not enabled */
+controller_ok:
+
+		if (d->channels	<= port)
+			return index;
+	
+		if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL)
+			continue;
+
+		/* setup proper ancestral information */
+		// 2.5 only hwif->gendev.parent = &dev->dev;
+
+		if (hwif->channel) {
+			index.b.high = hwif->index;
+		} else {
+			index.b.low = hwif->index;
+		}
+
+		
+		if (d->init_iops)
+			d->init_iops(hwif);
+
+		if (d->autodma == NODMA)
+			goto bypass_legacy_dma;
+		if (d->autodma == NOAUTODMA)
+			autodma = 0;
+		if (autodma)
+			hwif->autodma = 1;
+		ide_hwif_setup_dma(dev, d, hwif);
+bypass_legacy_dma:
+
+		drive0_tune = hwif->drives[0].autotune;
+		drive1_tune = hwif->drives[1].autotune;
+
+		if (d->init_hwif)
+			/* Call chipset-specific routine
+			 * for each enabled hwif
+			 */
+			d->init_hwif(hwif);
+
+		mate = hwif;
+		at_least_one_hwif_enabled = 1;
+	}
+	if (!at_least_one_hwif_enabled)
+		printk(KERN_INFO "%s: neither IDE port enabled (BIOS)\n", d->name);
+	return index;
+}
+
+void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	do_ide_setup_pci_device(dev, d, 1);
+}
+
+EXPORT_SYMBOL_GPL(ide_setup_pci_device);
+
+void ide_setup_pci_devices (struct pci_dev *dev, struct pci_dev *dev2, ide_pci_device_t *d)
+{
+	do_ide_setup_pci_device(dev, d, 1);
+	do_ide_setup_pci_device(dev2, d, 0);
+}
+
+EXPORT_SYMBOL_GPL(ide_setup_pci_devices);
+
+/*
+ *	Module interfaces
+ */
+ 
+static int pre_init = 1;		/* Before first ordered IDE scan */
+static LIST_HEAD(ide_pci_drivers);
+
+/*
+ *	ide_register_pci_driver		-	attach IDE driver
+ *	@driver: pci driver
+ *
+ *	Registers a driver with the IDE layer. The IDE layer arranges that
+ *	boot time setup is done in the expected device order and then 
+ *	hands the controllers off to the core PCI code to do the rest of
+ *	the work.
+ *
+ *	The driver_data of the driver table must point to an ide_pci_device_t
+ *	describing the interface.
+ *
+ *	Returns are the same as for pci_register_driver
+ */
+
+int ide_pci_register_driver(struct pci_driver *driver)
+{
+	if(!pre_init)
+		return pci_module_init(driver);
+	list_add_tail(&driver->node, &ide_pci_drivers);
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(ide_pci_register_driver);
+
+/**
+ *	ide_unregister_pci_driver	-	unregister an IDE driver
+ *	@driver: driver to remove
+ *
+ *	Unregister a currently installed IDE driver. Returns are the same
+ *	as for pci_unregister_driver
+ */
+ 
+void ide_pci_unregister_driver(struct pci_driver *driver)
+{
+	if(!pre_init)
+		pci_unregister_driver(driver);
+	else
+		list_del(&driver->node);
+}
+
+EXPORT_SYMBOL_GPL(ide_pci_unregister_driver);
+
+/**
+ *	ide_scan_pcidev		-	find an IDE driver for a device
+ *	@dev: PCI device to check
+ *
+ *	Look for an IDE driver to handle the device we are considering.
+ *	This is only used during boot up to get the ordering correct. After
+ *	boot up the pci layer takes over the job.
+ */
+ 
+static int __init ide_scan_pcidev(struct pci_dev *dev)
+{
+	struct list_head *l;
+	struct pci_driver *d;
+	
+	list_for_each(l, &ide_pci_drivers)
+	{
+		d = list_entry(l, struct pci_driver, node);
+		if(d->id_table)
+		{
+			const struct pci_device_id *id = pci_match_device(d->id_table, dev);
+			if(id != NULL)
+			{
+				if(d->probe(dev, id) >= 0)
+				{
+					dev->driver = d;
+					return 1;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+/**
+ *	ide_scan_pcibus		-	perform the initial IDE driver scan
+ *	@scan_direction: set for reverse order scanning
+ *
+ *	Perform the initial bus rather than driver ordered scan of the
+ *	PCI drivers. After this all IDE pci handling becomes standard
+ *	module ordering not traditionally ordered.
+ */
+ 	
+void __init ide_scan_pcibus (int scan_direction)
+{
+	struct pci_dev *dev;
+	struct pci_driver *d;
+	struct list_head *l, *n;
+
+	pre_init = 0;
+	if (!scan_direction) {
+		pci_for_each_dev(dev) {
+			ide_scan_pcidev(dev);
+		}
+	} else {
+		pci_for_each_dev_reverse(dev) {
+			ide_scan_pcidev(dev);
+		}
+	}
+	
+	/*
+	 *	Hand the drivers over to the PCI layer now we
+	 *	are post init.
+	 */
+
+	list_for_each_safe(l, n, &ide_pci_drivers)
+	{
+		list_del(l);
+		d = list_entry(l, struct pci_driver, node);
+		pci_register_driver(d);
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/sis5513.c linux-2.4.21/drivers/ide/sis5513.c
--- linux-2.4.20/drivers/ide/sis5513.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/sis5513.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,861 +0,0 @@
-/*
- * linux/drivers/ide/sis5513.c		Version 0.13	March 6, 2002
- *
- * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2002		Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
- * May be copied or modified under the terms of the GNU General Public License
- *
- *
- * Thanks :
- *
- * SiS Taiwan		: for direct support and hardware.
- * Daniela Engert	: for initial ATA100 advices and numerous others.
- * John Fremlin, Manfred Spraul :
- *			  for checking code correctness, providing patches.
- *
- *
- * Original tests and design on the SiS620/5513 chipset.
- * ATA100 tests and design on the SiS735/5513 chipset.
- * ATA16/33 design from specs
- */
-
-/*
- * TODO:
- *	- Get ridden of SisHostChipInfo[] completness dependancy.
- *	- Get ATA-133 datasheets, implement ATA-133 init code.
- *	- Study drivers/ide/ide-timing.h.
- *	- Are there pre-ATA_16 SiS5513 chips ? -> tune init code for them
- *	  or remove ATA_00 define
- *	- More checks in the config registers (force values instead of
- *	  relying on the BIOS setting them correctly).
- *	- Further optimisations ?
- *	  . for example ATA66+ regs 0x48 & 0x4A
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-/* When DEBUG is defined it outputs initial PCI config register
-   values and changes made to them by the driver */   
-// #define DEBUG
-/* When BROKEN_LEVEL is defined it limits the DMA mode
-   at boot time to its value */
-// #define BROKEN_LEVEL XFER_SW_DMA_0
-#define DISPLAY_SIS_TIMINGS
-
-/* Miscellaneaous flags */
-#define SIS5513_LATENCY		0x01
-
-/* registers layout and init values are chipset family dependant */
-/* 1/ define families */
-#define ATA_00		0x00
-#define ATA_16		0x01
-#define ATA_33		0x02
-#define ATA_66		0x03
-#define ATA_100a	0x04 // SiS730 is ATA100 with ATA66 layout
-#define ATA_100		0x05
-#define ATA_133		0x06
-/* 2/ variable holding the controller chipset family value */
-static unsigned char chipset_family;
-
-
-/*
- * Debug code: following IDE config registers' changes
- */
-#ifdef DEBUG
-/* Copy of IDE Config registers 0x00 -> 0x57
-   Fewer might be used depending on the actual chipset */
-static unsigned char ide_regs_copy[0x58];
-
-static byte sis5513_max_config_register(void) {
-	switch(chipset_family) {
-		case ATA_00:
-		case ATA_16:	return 0x4f;
-		case ATA_33:	return 0x52;
-		case ATA_66:
-		case ATA_100a:
-		case ATA_100:
-		case ATA_133:
-		default:	return 0x57;
-	}
-}
-
-/* Read config registers, print differences from previous read */
-static void sis5513_load_verify_registers(struct pci_dev* dev, char* info) {
-	int i;
-	byte reg_val;
-	byte changed=0;
-	byte max = sis5513_max_config_register();
-
-	printk("SIS5513: %s, changed registers:\n", info);
-	for(i=0; i<=max; i++) {
-		pci_read_config_byte(dev, i, &reg_val);
-		if (reg_val != ide_regs_copy[i]) {
-			printk("%0#x: %0#x -> %0#x\n",
-			       i, ide_regs_copy[i], reg_val);
-			ide_regs_copy[i]=reg_val;
-			changed=1;
-		}
-	}
-
-	if (!changed) {
-		printk("none\n");
-	}
-}
-
-/* Load config registers, no printing */
-static void sis5513_load_registers(struct pci_dev* dev) {
-	int i;
-	byte max = sis5513_max_config_register();
-
-	for(i=0; i<=max; i++) {
-		pci_read_config_byte(dev, i, &(ide_regs_copy[i]));
-	}
-}
-
-/* Print a register */
-static void sis5513_print_register(int reg) {
-	printk(" %0#x:%0#x", reg, ide_regs_copy[reg]);
-}
-
-/* Print valuable registers */
-static void sis5513_print_registers(struct pci_dev* dev, char* marker) {
-	int i;
-	byte max = sis5513_max_config_register();
-
-	sis5513_load_registers(dev);
-	printk("SIS5513 %s\n", marker);
-	printk("SIS5513 dump:");
-	for(i=0x00; i<0x40; i++) {
-		if ((i % 0x10)==0) printk("\n             ");
-		sis5513_print_register(i);
-	}
-	for(; i<49; i++) {
-		sis5513_print_register(i);
-	}
-	printk("\n             ");
-
-	for(; i<=max; i++) {
-		sis5513_print_register(i);
-	}
-	printk("\n");
-}
-#endif
-
-
-/*
- * Devices supported
- */
-static const struct {
-	const char *name;
-	unsigned short host_id;
-	unsigned char chipset_family;
-	unsigned char flags;
-} SiSHostChipInfo[] = {
-//	{ "SiS750",	PCI_DEVICE_ID_SI_750,	ATA_100,	SIS5513_LATENCY },
-//	{ "SiS745",	PCI_DEVICE_ID_SI_745,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS740",	PCI_DEVICE_ID_SI_740,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS735",	PCI_DEVICE_ID_SI_735,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS730",	PCI_DEVICE_ID_SI_730,	ATA_100a,	SIS5513_LATENCY },
-//	{ "SiS650",	PCI_DEVICE_ID_SI_650,	ATA_100,	SIS5513_LATENCY },
-//	{ "SiS645",	PCI_DEVICE_ID_SI_645,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS635",	PCI_DEVICE_ID_SI_635,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS640",	PCI_DEVICE_ID_SI_640,	ATA_66,		SIS5513_LATENCY },
-	{ "SiS630",	PCI_DEVICE_ID_SI_630,	ATA_66,		SIS5513_LATENCY },
-	{ "SiS620",	PCI_DEVICE_ID_SI_620,	ATA_66,		SIS5513_LATENCY },
-	{ "SiS540",	PCI_DEVICE_ID_SI_540,	ATA_66,		0},
-	{ "SiS530",	PCI_DEVICE_ID_SI_530,	ATA_66,		0},
-	{ "SiS5600",	PCI_DEVICE_ID_SI_5600,	ATA_33,		0},
-	{ "SiS5598",	PCI_DEVICE_ID_SI_5598,	ATA_33,		0},
-	{ "SiS5597",	PCI_DEVICE_ID_SI_5597,	ATA_33,		0},
-	{ "SiS5591",	PCI_DEVICE_ID_SI_5591,	ATA_33,		0},
-	{ "SiS5513",	PCI_DEVICE_ID_SI_5513,	ATA_16,		0},
-	{ "SiS5511",	PCI_DEVICE_ID_SI_5511,	ATA_16,		0},
-};
-
-/* Cycle time bits and values vary accross chip dma capabilities
-   These three arrays hold the register layout and the values to set.
-   Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */
-static byte cycle_time_offset[] = {0,0,5,4,4,0,0};
-static byte cycle_time_range[] = {0,0,2,3,3,4,4};
-static byte cycle_time_value[][XFER_UDMA_5 - XFER_UDMA_0 + 1] = {
-	{0,0,0,0,0,0}, /* no udma */
-	{0,0,0,0,0,0}, /* no udma */
-	{3,2,1,0,0,0},
-	{7,5,3,2,1,0},
-	{7,5,3,2,1,0},
-	{11,7,5,4,2,1},
-	{0,0,0,0,0,0} /* not yet known, ask SiS */
-};
-
-static struct pci_dev *host_dev = NULL;
-
-
-/*
- * Printing configuration
- */
-#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int sis_get_info(char *, char **, off_t, int);
-extern int (*sis_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-static struct pci_dev *bmide_dev;
-
-static char* cable_type[] = {
-	"80 pins",
-	"40 pins"
-};
-
-static char* recovery_time[] ={
-	"12 PCICLK", "1 PCICLK",
-	"2 PCICLK", "3 PCICLK",
-	"4 PCICLK", "5 PCICLCK",
-	"6 PCICLK", "7 PCICLCK",
-	"8 PCICLK", "9 PCICLCK",
-	"10 PCICLK", "11 PCICLK",
-	"13 PCICLK", "14 PCICLK",
-	"15 PCICLK", "15 PCICLK"
-};
-
-static char* active_time[] = {
-	"8 PCICLK", "1 PCICLCK",
-	"2 PCICLK", "3 PCICLK",
-	"4 PCICLK", "5 PCICLK",
-	"6 PCICLK", "12 PCICLK"
-};
-
-static char* cycle_time[] = {
-	"Reserved", "2 CLK",
-	"3 CLK", "4 CLK",
-	"5 CLK", "6 CLK",
-	"7 CLK", "8 CLK",
-	"9 CLK", "10 CLK",
-	"11 CLK", "12 CLK",
-	"Reserved", "Reserved",
-	"Reserved", "Reserved"
-};
-
-/* Generic add master or slave info function */
-static char* get_drives_info (char *buffer, byte pos)
-{
-	byte reg00, reg01, reg10, reg11; /* timing registers */
-	char* p = buffer;
-
-/* Postwrite/Prefetch */
-	pci_read_config_byte(bmide_dev, 0x4b, &reg00);
-	p += sprintf(p, "Drive %d:        Postwrite %s \t \t Postwrite %s\n",
-		     pos, (reg00 & (0x10 << pos)) ? "Enabled" : "Disabled",
-		     (reg00 & (0x40 << pos)) ? "Enabled" : "Disabled");
-	p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
-		     (reg00 & (0x01 << pos)) ? "Enabled" : "Disabled",
-		     (reg00 & (0x04 << pos)) ? "Enabled" : "Disabled");
-
-	pci_read_config_byte(bmide_dev, 0x40+2*pos, &reg00);
-	pci_read_config_byte(bmide_dev, 0x41+2*pos, &reg01);
-	pci_read_config_byte(bmide_dev, 0x44+2*pos, &reg10);
-	pci_read_config_byte(bmide_dev, 0x45+2*pos, &reg11);
-
-/* UDMA */
-	if (chipset_family >= ATA_33) {
-		p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
-			     (reg01 & 0x80)  ? "Enabled" : "Disabled",
-			     (reg11 & 0x80) ? "Enabled" : "Disabled");
-
-		p += sprintf(p, "                UDMA Cycle Time    ");
-		switch(chipset_family) {
-			case ATA_33:	p += sprintf(p, cycle_time[(reg01 & 0x60) >> 5]); break;
-			case ATA_66:
-			case ATA_100a:	p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break;
-			case ATA_100:	p += sprintf(p, cycle_time[reg01 & 0x0F]); break;
-			case ATA_133:
-			default:	p += sprintf(p, "133+ ?"); break;
-		}
-		p += sprintf(p, " \t UDMA Cycle Time    ");
-		switch(chipset_family) {
-			case ATA_33:	p += sprintf(p, cycle_time[(reg11 & 0x60) >> 5]); break;
-			case ATA_66:
-			case ATA_100a:	p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break;
-			case ATA_100:	p += sprintf(p, cycle_time[reg11 & 0x0F]); break;
-			case ATA_133:
-			default:	p += sprintf(p, "133+ ?"); break;
-		}
-		p += sprintf(p, "\n");
-	}
-
-/* Data Active */
-	p += sprintf(p, "                Data Active Time   ");
-	switch(chipset_family) {
-		case ATA_00:
-		case ATA_16: /* confirmed */
-		case ATA_33:
-		case ATA_66:
-		case ATA_100a: p += sprintf(p, active_time[reg01 & 0x07]); break;
-		case ATA_100: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break;
-		case ATA_133:
-		default: p += sprintf(p, "133+ ?"); break;
-	}
-	p += sprintf(p, " \t Data Active Time   ");
-	switch(chipset_family) {
-		case ATA_00:
-		case ATA_16:
-		case ATA_33:
-		case ATA_66:
-		case ATA_100a: p += sprintf(p, active_time[reg11 & 0x07]); break;
-		case ATA_100: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break;
-		case ATA_133:
-		default: p += sprintf(p, "133+ ?"); break;
-	}
-	p += sprintf(p, "\n");
-
-/* Data Recovery */
-	/* warning: may need (reg&0x07) for pre ATA66 chips */
-	p += sprintf(p, "                Data Recovery Time %s \t Data Recovery Time %s\n",
-		     recovery_time[reg00 & 0x0f], recovery_time[reg10 & 0x0f]);
-
-	return p;
-}
-
-static char* get_masters_info(char* buffer)
-{
-	return get_drives_info(buffer, 0);
-}
-
-static char* get_slaves_info(char* buffer)
-{
-	return get_drives_info(buffer, 1);
-}
-
-/* Main get_info, called on /proc/ide/sis reads */
-static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	byte reg;
-	u16 reg2, reg3;
-
-	p += sprintf(p, "\nSiS 5513 ");
-	switch(chipset_family) {
-		case ATA_00: p += sprintf(p, "Unknown???"); break;
-		case ATA_16: p += sprintf(p, "DMA 16"); break;
-		case ATA_33: p += sprintf(p, "Ultra 33"); break;
-		case ATA_66: p += sprintf(p, "Ultra 66"); break;
-		case ATA_100a:
-		case ATA_100: p += sprintf(p, "Ultra 100"); break;
-		case ATA_133:
-		default: p+= sprintf(p, "Ultra 133+"); break;
-	}
-	p += sprintf(p, " chipset\n");
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-
-/* Status */
-	pci_read_config_byte(bmide_dev, 0x4a, &reg);
-	p += sprintf(p, "Channel Status: ");
-	if (chipset_family < ATA_66) {
-		p += sprintf(p, "%s \t \t \t \t %s\n",
-			     (reg & 0x04) ? "On" : "Off",
-			     (reg & 0x02) ? "On" : "Off");
-	} else {
-		p += sprintf(p, "%s \t \t \t \t %s \n",
-			     (reg & 0x02) ? "On" : "Off",
-			     (reg & 0x04) ? "On" : "Off");
-	}
-
-/* Operation Mode */
-	pci_read_config_byte(bmide_dev, 0x09, &reg);
-	p += sprintf(p, "Operation Mode: %s \t \t \t %s \n",
-		     (reg & 0x01) ? "Native" : "Compatible",
-		     (reg & 0x04) ? "Native" : "Compatible");
-
-/* 80-pin cable ? */
-	if (chipset_family > ATA_33) {
-		pci_read_config_byte(bmide_dev, 0x48, &reg);
-		p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
-			     (reg & 0x10) ? cable_type[1] : cable_type[0],
-			     (reg & 0x20) ? cable_type[1] : cable_type[0]);
-	}
-
-/* Prefetch Count */
-	pci_read_config_word(bmide_dev, 0x4c, &reg2);
-	pci_read_config_word(bmide_dev, 0x4e, &reg3);
-	p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n",
-		     reg2, reg3);
-
-	p = get_masters_info(p);
-	p = get_slaves_info(p);
-
-	return p-buffer;
-}
-#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-
-byte sis_proc = 0;
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-
-/*
- * Configuration functions
- */
-/* Enables per-drive prefetch and postwrite */
-static void config_drive_art_rwp (ide_drive_t *drive)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	byte reg4bh		= 0;
-	byte rw_prefetch	= (0x11 << drive->dn);
-
-#ifdef DEBUG
-	printk("SIS5513: config_drive_art_rwp, drive %d\n", drive->dn);
-	sis5513_load_verify_registers(dev, "config_drive_art_rwp start");
-#endif
-
-	if (drive->media != ide_disk)
-		return;
-	pci_read_config_byte(dev, 0x4b, &reg4bh);
-
-	if ((reg4bh & rw_prefetch) != rw_prefetch)
-		pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "config_drive_art_rwp end");
-#endif
-}
-
-
-/* Set per-drive active and recovery time */
-static void config_art_rwp_pio (ide_drive_t *drive, byte pio)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	byte			timing, drive_pci, test1, test2;
-
-	unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
-	unsigned short xfer_pio = drive->id->eide_pio_modes;
-
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
-#endif
-
-	config_drive_art_rwp(drive);
-	pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
-
-	if (xfer_pio> 4)
-		xfer_pio = 0;
-
-	if (drive->id->eide_pio_iordy > 0) {
-		for (xfer_pio = 5;
-			(xfer_pio > 0) &&
-			(drive->id->eide_pio_iordy > eide_pio_timing[xfer_pio]);
-			xfer_pio--);
-	} else {
-		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
-			   (drive->id->eide_pio_modes & 2) ? 0x04 :
-			   (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
-	}
-
-	timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
-#ifdef DEBUG
-	printk("SIS5513: config_drive_art_rwp_pio, drive %d, pio %d, timing %d\n",
-	       drive->dn, pio, timing);
-#endif
-
-	switch(drive->dn) {
-		case 0:		drive_pci = 0x40; break;
-		case 1:		drive_pci = 0x42; break;
-		case 2:		drive_pci = 0x44; break;
-		case 3:		drive_pci = 0x46; break;
-		default:	return;
-	}
-
-	/* register layout changed with newer ATA100 chips */
-	if (chipset_family < ATA_100) {
-		pci_read_config_byte(dev, drive_pci, &test1);
-		pci_read_config_byte(dev, drive_pci+1, &test2);
-
-		/* Clear active and recovery timings */
-		test1 &= ~0x0F;
-		test2 &= ~0x07;
-
-		switch(timing) {
-			case 4:		test1 |= 0x01; test2 |= 0x03; break;
-			case 3:		test1 |= 0x03; test2 |= 0x03; break;
-			case 2:		test1 |= 0x04; test2 |= 0x04; break;
-			case 1:		test1 |= 0x07; test2 |= 0x06; break;
-			default:	break;
-		}
-		pci_write_config_byte(dev, drive_pci, test1);
-		pci_write_config_byte(dev, drive_pci+1, test2);
-	} else {
-		switch(timing) { /*   active  recovery
-					  v     v */
-			case 4:		test1 = 0x30|0x01; break;
-			case 3:		test1 = 0x30|0x03; break;
-			case 2:		test1 = 0x40|0x04; break;
-			case 1:		test1 = 0x60|0x07; break;
-			default:	break;
-		}
-		pci_write_config_byte(dev, drive_pci, test1);
-	}
-
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
-#endif
-}
-
-static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-
-	switch(pio) {
-		case 4:		speed = XFER_PIO_4; break;
-		case 3:		speed = XFER_PIO_3; break;
-		case 2:		speed = XFER_PIO_2; break;
-		case 1:		speed = XFER_PIO_1; break;
-		default:	speed = XFER_PIO_0; break;
-	}
-
-	config_art_rwp_pio(drive, pio);
-	drive->current_speed = speed;
-	return ide_config_drive_speed(drive, speed);
-}
-
-static int sis5513_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	byte			drive_pci, reg;
-
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "sis5513_tune_chipset start");
-	printk("SIS5513: sis5513_tune_chipset, drive %d, speed %d\n",
-	       drive->dn, speed);
-#endif
-	switch(drive->dn) {
-		case 0:		drive_pci = 0x40; break;
-		case 1:		drive_pci = 0x42; break;
-		case 2:		drive_pci = 0x44; break;
-		case 3:		drive_pci = 0x46; break;
-		default:	return ide_dma_off;
-	}
-
-#ifdef BROKEN_LEVEL
-#ifdef DEBUG
-	printk("SIS5513: BROKEN_LEVEL activated, speed=%d -> speed=%d\n", speed, BROKEN_LEVEL);
-#endif
-	if (speed > BROKEN_LEVEL) speed = BROKEN_LEVEL;
-#endif
-
-	pci_read_config_byte(dev, drive_pci+1, &reg);
-	/* Disable UDMA bit for non UDMA modes on UDMA chips */
-	if ((speed < XFER_UDMA_0) && (chipset_family > ATA_16)) {
-		reg &= 0x7F;
-		pci_write_config_byte(dev, drive_pci+1, reg);
-	}
-
-	/* Config chip for mode */
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-			/* Force the UDMA bit on if we want to use UDMA */
-			reg |= 0x80;
-			/* clean reg cycle time bits */
-			reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family]))
-				 << cycle_time_offset[chipset_family]);
-			/* set reg cycle time bits */
-			reg |= cycle_time_value[chipset_family-ATA_00][speed-XFER_UDMA_0]
-				<< cycle_time_offset[chipset_family];
-			pci_write_config_byte(dev, drive_pci+1, reg);
-			break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_MW_DMA_0:
-		case XFER_SW_DMA_2:
-		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0:
-			break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4: return((int) config_chipset_for_pio(drive, 4));
-		case XFER_PIO_3: return((int) config_chipset_for_pio(drive, 3));
-		case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2));
-		case XFER_PIO_1: return((int) config_chipset_for_pio(drive, 1));
-		case XFER_PIO_0:
-		default:	 return((int) config_chipset_for_pio(drive, 0));	
-	}
-	drive->current_speed = speed;
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "sis5513_tune_chipset end");
-#endif
-	return ((int) ide_config_drive_speed(drive, speed));
-}
-
-static void sis5513_tune_drive (ide_drive_t *drive, byte pio)
-{
-	(void) config_chipset_for_pio(drive, pio);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four))
- */
-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-
-	byte			speed = 0;
-
-	byte unit		= (drive->select.b.unit & 0x01);
-	byte udma_66		= eighty_ninty_three(drive);
-
-#ifdef DEBUG
-	printk("SIS5513: config_chipset_for_dma, drive %d, ultra %d\n",
-	       drive->dn, ultra);
-#endif
-
-	if ((id->dma_ultra & 0x0020) && ultra && udma_66 && (chipset_family >= ATA_100a))
-		speed = XFER_UDMA_5;
-	else if ((id->dma_ultra & 0x0010) && ultra && udma_66 && (chipset_family >= ATA_66))
-		speed = XFER_UDMA_4;
-	else if ((id->dma_ultra & 0x0008) && ultra && udma_66 && (chipset_family >= ATA_66))
-		speed = XFER_UDMA_3;
-	else if ((id->dma_ultra & 0x0004) && ultra && (chipset_family >= ATA_33))
-		speed = XFER_UDMA_2;
-	else if ((id->dma_ultra & 0x0002) && ultra && (chipset_family >= ATA_33))
-		speed = XFER_UDMA_1;
-	else if ((id->dma_ultra & 0x0001) && ultra && (chipset_family >= ATA_33))
-		speed = XFER_UDMA_0;
-	else if (id->dma_mword & 0x0004)
-		speed = XFER_MW_DMA_2;
-	else if (id->dma_mword & 0x0002)
-		speed = XFER_MW_DMA_1;
-	else if (id->dma_mword & 0x0001)
-		speed = XFER_MW_DMA_0;
-	else if (id->dma_1word & 0x0004)
-		speed = XFER_SW_DMA_2;
-	else if (id->dma_1word & 0x0002)
-		speed = XFER_SW_DMA_1;
-	else if (id->dma_1word & 0x0001)
-		speed = XFER_SW_DMA_0;
-	else
-		return ((int) ide_dma_off_quietly);
-
-	outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2);
-
-	sis5513_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id		= drive->id;
-	ide_dma_action_t dma_func	= ide_dma_off_quietly;
-
-	(void) config_chipset_for_pio(drive, 5);
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive, 1);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive, 0);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if ((ide_dmaproc(ide_dma_good_drive, drive)) &&
-			   (id->eide_dma_time > 150)) {
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive, 0);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		(void) config_chipset_for_pio(drive, 5);
-	}
-
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/* initiates/aborts (U)DMA read/write operations on a drive. */
-int sis5513_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			config_drive_art_rwp(drive);
-			config_art_rwp_pio(drive, 5);
-			return config_drive_xfer_rate(drive);
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/* Chip detection and general config */
-unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
-{
-	struct pci_dev *host;
-	int i = 0;
-
-	/* Find the chip */
-	for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !host_dev; i++) {
-		host = pci_find_device (PCI_VENDOR_ID_SI,
-					SiSHostChipInfo[i].host_id,
-					NULL);
-		if (!host)
-			continue;
-
-		host_dev = host;
-		chipset_family = SiSHostChipInfo[i].chipset_family;
-		printk(SiSHostChipInfo[i].name);
-		printk("\n");
-
-#ifdef DEBUG
-		sis5513_print_registers(dev, "pci_init_sis5513 start");
-#endif
-
-		if (SiSHostChipInfo[i].flags & SIS5513_LATENCY) {
-			byte latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */
-			pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency);
-		}
-	}
-
-	/* Make general config ops here
-	   1/ tell IDE channels to operate in Compabitility mode only
-	   2/ tell old chips to allow per drive IDE timings */
-	if (host_dev) {
-		byte reg;
-		switch(chipset_family) {
-			case ATA_133:
-			case ATA_100:
-				/* Set compatibility bit */
-				pci_read_config_byte(dev, 0x49, &reg);
-				if (!(reg & 0x01)) {
-					pci_write_config_byte(dev, 0x49, reg|0x01);
-				}
-				break;
-			case ATA_100a:
-			case ATA_66:
-				/* On ATA_66 chips the bit was elsewhere */
-				pci_read_config_byte(dev, 0x52, &reg);
-				if (!(reg & 0x04)) {
-					pci_write_config_byte(dev, 0x52, reg|0x04);
-				}
-				break;
-			case ATA_33:
-				/* On ATA_33 we didn't have a single bit to set */
-				pci_read_config_byte(dev, 0x09, &reg);
-				if ((reg & 0x0f) != 0x00) {
-					pci_write_config_byte(dev, 0x09, reg&0xf0);
-				}
-			case ATA_16:
-				/* force per drive recovery and active timings
-				   needed on ATA_33 and below chips */
-				pci_read_config_byte(dev, 0x52, &reg);
-				if (!(reg & 0x08)) {
-					pci_write_config_byte(dev, 0x52, reg|0x08);
-				}
-				break;
-			case ATA_00:
-			default: break;
-		}
-
-#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
-		if (!sis_proc) {
-			sis_proc = 1;
-			bmide_dev = dev;
-			sis_display_info = &sis_get_info;
-		}
-#endif
-	}
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "pci_init_sis5513 end");
-#endif
-	return 0;
-}
-
-unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
-{
-	byte reg48h = 0, ata66 = 0;
-	byte mask = hwif->channel ? 0x20 : 0x10;
-	pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
-
-	if (chipset_family >= ATA_66) {
-		ata66 = (reg48h & mask) ? 0 : 1;
-	}
-        return ata66;
-}
-
-void __init ide_init_sis5513 (ide_hwif_t *hwif)
-{
-
-	hwif->irq = hwif->channel ? 15 : 14;
-
-	hwif->tuneproc = &sis5513_tune_drive;
-	hwif->speedproc = &sis5513_tune_chipset;
-
-	if (!(hwif->dma_base))
-		return;
-
-	if (host_dev) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		if (chipset_family > ATA_16) {
-			hwif->autodma = noautodma ? 0 : 1;
-			hwif->dmaproc = &sis5513_dmaproc;
-		} else {
-#endif
-			hwif->autodma = 0;
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		}
-#endif
-	}
-	return;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/sl82c105.c linux-2.4.21/drivers/ide/sl82c105.c
--- linux-2.4.20/drivers/ide/sl82c105.c	2001-09-07 17:45:30.000000000 +0000
+++ linux-2.4.21/drivers/ide/sl82c105.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,274 +0,0 @@
-/*
- * linux/drivers/ide/sl82c105.c
- *
- * SL82C105/Winbond 553 IDE driver
- *
- * Maintainer unknown.
- *
- * Drive tuning added from Rebel.com's kernel sources
- *  -- Russell King (15/11/98) linux@arm.linux.org.uk
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include "ide_modes.h"
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/*
- * Convert a PIO mode and cycle time to the required on/off
- * times for the interface.  This has protection against run-away
- * timings.
- */
-static unsigned int get_timing_sl82c105(ide_pio_data_t *p)
-{
-	unsigned int cmd_on;
-	unsigned int cmd_off;
-
-	cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30;
-	cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30;
-
-	if (cmd_on > 32)
-		cmd_on = 32;
-	if (cmd_on == 0)
-		cmd_on = 1;
-
-	if (cmd_off > 32)
-		cmd_off = 32;
-	if (cmd_off == 0)
-		cmd_off = 1;
-
-	return (cmd_on - 1) << 8 | (cmd_off - 1) | (p->use_iordy ? 0x40 : 0x00);
-}
-
-/*
- * Configure the drive and chipset for PIO
- */
-static void config_for_pio(ide_drive_t *drive, int pio, int report)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
-	ide_pio_data_t p;
-	unsigned short drv_ctrl = 0x909;
-	unsigned int xfer_mode, reg;
-
-	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
-
-	pio = ide_get_best_pio_mode(drive, pio, 5, &p);
-
-	switch (pio) {
-	default:
-	case 0:		xfer_mode = XFER_PIO_0;		break;
-	case 1:		xfer_mode = XFER_PIO_1;		break;
-	case 2:		xfer_mode = XFER_PIO_2;		break;
-	case 3:		xfer_mode = XFER_PIO_3;		break;
-	case 4:		xfer_mode = XFER_PIO_4;		break;
-	}
-
-	if (ide_config_drive_speed(drive, xfer_mode) == 0)
-		drv_ctrl = get_timing_sl82c105(&p);
-
-	if (drive->using_dma == 0) {
-		/*
-		 * If we are actually using MW DMA, then we can not
-		 * reprogram the interface drive control register.
-		 */
-		pci_write_config_word(dev, reg, drv_ctrl);
-		pci_read_config_word(dev, reg, &drv_ctrl);
-
-		if (report) {
-			printk("%s: selected %s (%dns) (%04X)\n", drive->name,
-			       ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl);
-		}
-	}
-}
-
-/*
- * Configure the drive and the chipset for DMA
- */
-static int config_for_dma(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
-	unsigned short drv_ctrl = 0x909;
-	unsigned int reg;
-
-	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
-
-	if (ide_config_drive_speed(drive, XFER_MW_DMA_2) == 0)
-		drv_ctrl = 0x0240;
-
-	pci_write_config_word(dev, reg, drv_ctrl);
-
-	return 0;
-}
-
-/*
- * Check to see if the drive and
- * chipset is capable of DMA mode
- */
-static int sl82c105_check_drive(ide_drive_t *drive)
-{
-	ide_dma_action_t dma_func = ide_dma_off_quietly;
-
-	do {
-		struct hd_driveid *id = drive->id;
-		ide_hwif_t *hwif = HWIF(drive);
-
-		if (!hwif->autodma)
-			break;
-
-		if (!id || !(id->capability & 1))
-			break;
-
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			break;
-		}
-
-		if (id->field_valid & 2) {
-			if  (id->dma_mword & 7 || id->dma_1word & 7)
-				dma_func = ide_dma_on;
-			break;
-		}
-
-		if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			dma_func = ide_dma_on;
-			break;
-		}
-	} while (0);
-
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * Our own dmaproc, only to intercept ide_dma_check
- */
-static int sl82c105_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-	case ide_dma_check:
-		return sl82c105_check_drive(drive);
-	case ide_dma_on:
-		if (config_for_dma(drive))
-			func = ide_dma_off;
-		/* fall through */
-	case ide_dma_off_quietly:
-	case ide_dma_off:
-		config_for_pio(drive, 4, 0);
-		break;
-	default:
-		break;
-	}
-	return ide_dmaproc(func, drive);
-}
-
-/*
- * We only deal with PIO mode here - DMA mode 'using_dma' is not
- * initialised at the point that this function is called.
- */
-static void tune_sl82c105(ide_drive_t *drive, byte pio)
-{
-	config_for_pio(drive, pio, 1);
-
-	/*
-	 * We support 32-bit I/O on this interface, and it
-	 * doesn't have problems with interrupts.
-	 */
-	drive->io_32bit = 1;
-	drive->unmask = 1;
-}
-
-/*
- * Return the revision of the Winbond bridge
- * which this function is part of.
- */
-static unsigned int sl82c105_bridge_revision(struct pci_dev *dev)
-{
-	struct pci_dev *bridge;
-	unsigned char rev;
-
-	bridge = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, NULL);
-
-	/*
-	 * If we are part of a Winbond 553
-	 */
-	if (!bridge || bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA)
-		return -1;
-
-	if (bridge->bus != dev->bus ||
-	    PCI_SLOT(bridge->devfn) != PCI_SLOT(dev->devfn))
-		return -1;
-
-	/*
-	 * We need to find function 0's revision, not function 1
-	 */
-	pci_read_config_byte(bridge, PCI_REVISION_ID, &rev);
-
-	return rev;
-}
-
-/*
- * Enable the PCI device
- */
-unsigned int __init pci_init_sl82c105(struct pci_dev *dev, const char *msg)
-{
-	unsigned char ctrl_stat;
-
-	/*
-	 * Enable the ports
-	 */
-	pci_read_config_byte(dev, 0x40, &ctrl_stat);
-	pci_write_config_byte(dev, 0x40, ctrl_stat | 0x33);
-
-	return dev->irq;
-}
-
-void __init dma_init_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
-{
-	unsigned int rev;
-	byte dma_state;
-
-	dma_state = inb(dma_base + 2);
-	rev = sl82c105_bridge_revision(hwif->pci_dev);
-	if (rev <= 5) {
-		hwif->autodma = 0;
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-		printk("    %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
-		       hwif->name, rev);
-		dma_state &= ~0x60;
-	} else {
-		dma_state |= 0x60;
-		hwif->autodma = 1;
-	}
-	outb(dma_state, dma_base + 2);
-
-	hwif->dmaproc = NULL;
-	ide_setup_dma(hwif, dma_base, 8);
-	if (hwif->dmaproc)
-		hwif->dmaproc = sl82c105_dmaproc;
-}
-
-/*
- * Initialise the chip
- */
-void __init ide_init_sl82c105(ide_hwif_t *hwif)
-{
-	hwif->tuneproc = tune_sl82c105;
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/slc90e66.c linux-2.4.21/drivers/ide/slc90e66.c
--- linux-2.4.20/drivers/ide/slc90e66.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ide/slc90e66.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,396 +0,0 @@
-/*
- *  linux/drivers/ide/slc90e66.c	Version 0.10	October 4, 2000
- *
- *  Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org>
- *  May be copied or modified under the terms of the GNU General Public License
- *
- * 00:07.1 IDE interface: EFAR Microsystems:
- * 		Unknown device 9130 (prog-if 8a [Master SecP PriP])
- * Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV-
- * 		VGASnoop- ParErr- Stepping- SERR- FastB2B-
- * Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium
- * 		>TAbort- <TAbort- <MAbort- >SERR- <PERR-
- * Latency: 64
- * Interrupt: pin A routed to IRQ 255
- * Region 4: I/O ports at 1050
- *
- * 00: 55 10 30 91 05 00 00 02 00 8a 01 01 00 40 00 00
- * 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 20: 51 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 30: 00 00 00 00 00 00 00 00 00 00 00 00 ff 01 00 00
- * 40: 37 e3 33 e3 b9 55 01 00 0d 00 04 22 00 00 00 00
- * 50: 00 00 ff a0 00 00 00 08 40 00 00 00 00 00 00 00
- * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- *
- * This a look-a-like variation of the ICH0 PIIX4 Ultra-66,
- * but this keeps the ISA-Bridge and slots alive.
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#define SLC90E66_DEBUG_DRIVE_INFO		0
-
-#define DISPLAY_SLC90E66_TIMINGS
-
-#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int slc90e66_get_info(char *, char **, off_t, int);
-extern int (*slc90e66_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-
-static int slc90e66_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-        u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
-	u8  c0 = 0, c1 = 0;
-	u8  reg44 = 0, reg47 = 0, reg48 = 0, reg4a = 0, reg4b = 0;
-
-	pci_read_config_word(bmide_dev, 0x40, &reg40);
-	pci_read_config_word(bmide_dev, 0x42, &reg42);
-	pci_read_config_byte(bmide_dev, 0x44, &reg44);
-	pci_read_config_byte(bmide_dev, 0x47, &reg47);
-	pci_read_config_byte(bmide_dev, 0x48, &reg48);
-	pci_read_config_byte(bmide_dev, 0x4a, &reg4a);
-	pci_read_config_byte(bmide_dev, 0x4b, &reg4b);
-
-	psitre = (reg40 & 0x4000) ? 1 : 0;
-	ssitre = (reg42 & 0x4000) ? 1 : 0;
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-#ifdef __mips__	/* only for mips? */
-	c0 = inb_p(bibma + 0x02);
-	c1 = inb_p(bibma + 0x0a);
-#else
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-#endif
-
-	p += sprintf(p, "                                SLC90E66 Chipset.\n");
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %sabled                         %sabled\n",
-			(c0&0x80) ? "dis" : " en",
-			(c1&0x80) ? "dis" : " en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	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 " );
-	p += sprintf(p, "UDMA enabled:   %s              %s             %s               %s\n",
-			(reg48&0x01) ? "yes" : "no ",
-			(reg48&0x02) ? "yes" : "no ",
-			(reg48&0x04) ? "yes" : "no ",
-			(reg48&0x08) ? "yes" : "no " );
-	p += sprintf(p, "UDMA enabled:   %s                %s               %s                 %s\n",
-			((reg4a&0x04)==0x04) ? "4" :
-			((reg4a&0x03)==0x03) ? "3" :
-			(reg4a&0x02) ? "2" :
-			(reg4a&0x01) ? "1" :
-			(reg4a&0x00) ? "0" : "X",
-			((reg4a&0x40)==0x40) ? "4" :
-			((reg4a&0x30)==0x30) ? "3" :
-			(reg4a&0x20) ? "2" :
-			(reg4a&0x10) ? "1" :
-			(reg4a&0x00) ? "0" : "X",
-			((reg4b&0x04)==0x04) ? "4" :
-			((reg4b&0x03)==0x03) ? "3" :
-			(reg4b&0x02) ? "2" :
-			(reg4b&0x01) ? "1" :
-			(reg4b&0x00) ? "0" : "X",
-			((reg4b&0x40)==0x40) ? "4" :
-			((reg4b&0x30)==0x30) ? "3" :
-			(reg4b&0x20) ? "2" :
-			(reg4b&0x10) ? "1" :
-			(reg4b&0x00) ? "0" : "X");
-
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "DMA\n");
-	p += sprintf(p, "PIO\n");
-
-/*
- *	FIXME.... Add configuration junk data....blah blah......
- */
-
-	return p-buffer;	 /* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-/*
- *  Used to set Fifo configuration via kernel command line:
- */
-
-byte slc90e66_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- *
- */
-static byte slc90e66_dma_2_pio (byte xfer_rate) {
-	switch(xfer_rate) {
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-		case XFER_MW_DMA_2:
-		case XFER_PIO_4:
-			return 4;
-		case XFER_MW_DMA_1:
-		case XFER_PIO_3:
-			return 3;
-		case XFER_SW_DMA_2:
-		case XFER_PIO_2:
-			return 2;
-		case XFER_MW_DMA_0:
-		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-		case XFER_PIO_SLOW:
-		default:
-			return 0;
-	}
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- *  Based on settings done by AMI BIOS
- *  (might be useful if drive is not registered in CMOS for any reason).
- */
-static void slc90e66_tune_drive (ide_drive_t *drive, byte pio)
-{
-	unsigned long flags;
-	u16 master_data;
-	byte slave_data;
-	int is_slave		= (&HWIF(drive)->drives[1] == drive);
-	int master_port		= HWIF(drive)->index ? 0x42 : 0x40;
-	int slave_port		= 0x44;
-				 /* ISP  RTC */
-	byte timings[][2]	= { { 0, 0 },
-				    { 0, 0 },
-				    { 1, 0 },
-				    { 2, 1 },
-				    { 2, 3 }, };
-
-	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
-	pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data);
-	if (is_slave) {
-		master_data = master_data | 0x4000;
-		if (pio > 1)
-			/* enable PPE, IE and TIME */
-			master_data = master_data | 0x0070;
-		pci_read_config_byte(HWIF(drive)->pci_dev, slave_port, &slave_data);
-		slave_data = slave_data & (HWIF(drive)->index ? 0x0f : 0xf0);
-		slave_data = slave_data | ((timings[pio][0] << 2) | (timings[pio][1]
-					   << (HWIF(drive)->index ? 4 : 0)));
-	} else {
-		master_data = master_data & 0xccf8;
-		if (pio > 1)
-			/* enable PPE, IE and TIME */
-			master_data = master_data | 0x0007;
-		master_data = master_data | (timings[pio][0] << 12) |
-			      (timings[pio][1] << 8);
-	}
-	save_flags(flags);
-	cli();
-	pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data);
-	if (is_slave)
-		pci_write_config_byte(HWIF(drive)->pci_dev, slave_port, slave_data);
-	restore_flags(flags);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int slc90e66_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte maslave		= hwif->channel ? 0x42 : 0x40;
-	int a_speed		= 7 << (drive->dn * 4);
-	int u_flag		= 1 << drive->dn;
-	int u_speed		= 0;
-	int err			= 0;
-	int			sitre;
-	short			reg4042, reg44, reg48, reg4a;
-
-	pci_read_config_word(dev, maslave, &reg4042);
-	sitre = (reg4042 & 0x4000) ? 1 : 0;
-	pci_read_config_word(dev, 0x44, &reg44);
-	pci_read_config_word(dev, 0x48, &reg48);
-	pci_read_config_word(dev, 0x4a, &reg4a);
-
-	switch(speed) {
-		case XFER_UDMA_4:	u_speed = 4 << (drive->dn * 4); break;
-		case XFER_UDMA_3:	u_speed = 3 << (drive->dn * 4); break;
-		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
-		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
-		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_SW_DMA_2:	break;
-#if 0	/* allow PIO modes */
-		default:		return -1;
-#endif
-	}
-
-	if (speed >= XFER_UDMA_0) {
-		if (!(reg48 & u_flag))
-			pci_write_config_word(dev, 0x48, reg48|u_flag);
-		if ((reg4a & u_speed) != u_speed) {
-			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-			pci_read_config_word(dev, 0x4a, &reg4a);
-			pci_write_config_word(dev, 0x4a, reg4a|u_speed);
-		}
-	}
-	if (speed < XFER_UDMA_0) {
-		if (reg48 & u_flag)
-			pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
-		if (reg4a & a_speed)
-			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-	}
-
-	slc90e66_tune_drive(drive, slc90e66_dma_2_pio(speed));
-
-#if SLC90E66_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* SLC90E66_DEBUG_DRIVE_INFO */
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return err;
-}
-
-static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	int ultra		= 1;
-	byte speed		= 0;
-	byte udma_66		= eighty_ninty_three(drive);
-
-#if 1 /* allow PIO modes */
-	if (!HWIF(drive)->autodma) {
-		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-		(void) slc90e66_tune_chipset(drive, speed);
-		return ((int) ide_dma_off_quietly);
-	}
-#endif
-	if ((id->dma_ultra & 0x0010) && (ultra)) {
-		speed = (udma_66) ? XFER_UDMA_4 : XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0008) && (ultra)) {
-		speed = (udma_66) ? XFER_UDMA_3 : XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0004) && (ultra)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-        } else {
-		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-	}
-
-	(void) slc90e66_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int slc90e66_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			 return ide_dmaproc((ide_dma_action_t) slc90e66_config_drive_for_dma(drive), drive);
-		default :
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-unsigned int __init pci_init_slc90e66 (struct pci_dev *dev, const char *name)
-{
-#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!slc90e66_proc) {
-		slc90e66_proc = 1;
-		bmide_dev = dev;
-		slc90e66_display_info = &slc90e66_get_info;
-	}
-#endif /* DISPLAY_SLC90E66_TIMINGS && CONFIG_PROC_FS */
-	return 0;
-}
-
-unsigned int __init ata66_slc90e66 (ide_hwif_t *hwif)
-{
-#if 1
-	byte reg47 = 0, ata66 = 0;
-	byte mask = hwif->channel ? 0x01 : 0x02;	/* bit0:Primary */
-
-	pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
-
-	ata66 = (reg47 & mask) ? 0 : 1;	/* bit[0(1)]: 0:80, 1:40 */
-#else
-	byte ata66 = 0;
-#endif
-	return ata66;
-}
-
-void __init ide_init_slc90e66 (ide_hwif_t *hwif)
-{
-	if (!hwif->irq)
-		hwif->irq = hwif->channel ? 15 : 14;
-
-	hwif->tuneproc = &slc90e66_tune_drive;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-
-	if (!hwif->dma_base)
-		return;
-
-	hwif->autodma = 0;
-#ifdef CONFIG_BLK_DEV_IDEDMA 
-	if (!noautodma)
-		hwif->autodma = 1;
-	hwif->dmaproc = &slc90e66_dmaproc;
-	hwif->speedproc = &slc90e66_tune_chipset;
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/trm290.c linux-2.4.21/drivers/ide/trm290.c
--- linux-2.4.20/drivers/ide/trm290.c	2000-06-20 14:52:36.000000000 +0000
+++ linux-2.4.21/drivers/ide/trm290.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,289 +0,0 @@
-/*
- *  linux/drivers/ide/trm290.c		Version 1.02	Mar. 18, 2000
- *
- *  Copyright (c) 1997-1998  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 Tekram TRM290 chip, used on a variety of PCI IDE add-on boards,
- * including a "Precision Instruments" board.  The TRM290 pre-dates
- * the sff-8038 standard (ide-dma.c) by a few months, and differs
- * significantly enough to warrant separate routines for some functions,
- * while re-using others from ide-dma.c.
- *
- * EXPERIMENTAL!  It works for me (a sample of one).
- *
- * Works reliably for me in DMA mode (READs only),
- * DMA WRITEs are disabled by default (see #define below);
- *
- * DMA is not enabled automatically for this chipset,
- * but can be turned on manually (with "hdparm -d1") at run time.
- *
- * I need volunteers with "spare" drives for further testing
- * and development, and maybe to help figure out the peculiarities.
- * Even knowing the registers (below), some things behave strangely.
- */
-
-#define TRM290_NO_DMA_WRITES	/* DMA writes seem unreliable sometimes */
-
-/*
- * TRM-290 PCI-IDE2 Bus Master Chip
- * ================================
- * The configuration registers are addressed in normal I/O port space
- * and are used as follows:
- *
- * trm290_base depends on jumper settings, and is probed for by ide-dma.c
- *
- * trm290_base+2 when WRITTEN: chiptest register (byte, write-only)
- *	bit7 must always be written as "1"
- *	bits6-2 undefined
- *	bit1 1=legacy_compatible_mode, 0=native_pci_mode
- *	bit0 1=test_mode, 0=normal(default)
- *
- * trm290_base+2 when READ: status register (byte, read-only)
- *	bits7-2 undefined
- *	bit1 channel0 busmaster interrupt status 0=none, 1=asserted
- *	bit0 channel0 interrupt status 0=none, 1=asserted
- *
- * trm290_base+3 Interrupt mask register
- *	bits7-5 undefined
- *	bit4 legacy_header: 1=present, 0=absent
- *	bit3 channel1 busmaster interrupt status 0=none, 1=asserted (read only)
- *	bit2 channel1 interrupt status 0=none, 1=asserted (read only)
- *	bit1 channel1 interrupt mask: 1=masked, 0=unmasked(default)
- *	bit0 channel0 interrupt mask: 1=masked, 0=unmasked(default)
- *
- * trm290_base+1 "CPR" Config Pointer Register (byte)
- *	bit7 1=autoincrement CPR bits 2-0 after each access of CDR
- *	bit6 1=min. 1 wait-state posted write cycle (default), 0=0 wait-state
- *	bit5 0=enabled master burst access (default), 1=disable  (write only)
- *	bit4 PCI DEVSEL# timing select: 1=medium(default), 0=fast
- *	bit3 0=primary IDE channel, 1=secondary IDE channel
- *	bits2-0 register index for accesses through CDR port
- *
- * trm290_base+0 "CDR" Config Data Register (word)
- *	two sets of seven config registers,
- *	selected by CPR bit 3 (channel) and CPR bits 2-0 (index 0 to 6),
- *	each index defined below:
- *
- * Index-0 Base address register for command block (word)
- *	defaults: 0x1f0 for primary, 0x170 for secondary
- *
- * Index-1 general config register (byte)
- *	bit7 1=DMA enable, 0=DMA disable
- *	bit6 1=activate IDE_RESET, 0=no action (default)
- *	bit5 1=enable IORDY, 0=disable IORDY (default)
- *	bit4 0=16-bit data port(default), 1=8-bit (XT) data port
- *	bit3 interrupt polarity: 1=active_low, 0=active_high(default)
- *	bit2 power-saving-mode(?): 1=enable, 0=disable(default) (write only)
- *	bit1 bus_master_mode(?): 1=enable, 0=disable(default)
- *	bit0 enable_io_ports: 1=enable(default), 0=disable
- *
- * Index-2 read-ahead counter preload bits 0-7 (byte, write only)
- *	bits7-0 bits7-0 of readahead count
- *
- * Index-3 read-ahead config register (byte, write only)
- *	bit7 1=enable_readahead, 0=disable_readahead(default)
- *	bit6 1=clear_FIFO, 0=no_action
- *	bit5 undefined
- *	bit4 mode4 timing control: 1=enable, 0=disable(default)
- *	bit3 undefined
- *	bit2 undefined
- *	bits1-0 bits9-8 of read-ahead count
- *
- * Index-4 base address register for control block (word)
- *	defaults: 0x3f6 for primary, 0x376 for secondary
- *
- * Index-5 data port timings (shared by both drives) (byte)
- *	standard PCI "clk" (clock) counts, default value = 0xf5
- *
- *	bits7-6 setup time:  00=1clk, 01=2clk, 10=3clk, 11=4clk
- *	bits5-3 hold time:	000=1clk, 001=2clk, 010=3clk,
- *				011=4clk, 100=5clk, 101=6clk,
- *				110=8clk, 111=12clk
- *	bits2-0 active time:	000=2clk, 001=3clk, 010=4clk,
- *				011=5clk, 100=6clk, 101=8clk,
- *				110=12clk, 111=16clk
- *
- * Index-6 command/control port timings (shared by both drives) (byte)
- *	same layout as Index-5, default value = 0xde
- *
- * Suggested CDR programming for PIO mode0 (600ns):
- *	0x01f0,0x21,0xff,0x80,0x03f6,0xf5,0xde	; primary
- *	0x0170,0x21,0xff,0x80,0x0376,0xf5,0xde	; secondary
- *
- * Suggested CDR programming for PIO mode3 (180ns):
- *	0x01f0,0x21,0xff,0x80,0x03f6,0x09,0xde	; primary
- *	0x0170,0x21,0xff,0x80,0x0376,0x09,0xde	; secondary
- *
- * Suggested CDR programming for PIO mode4 (120ns):
- *	0x01f0,0x21,0xff,0x80,0x03f6,0x00,0xde	; primary
- *	0x0170,0x21,0xff,0x80,0x0376,0x00,0xde	; secondary
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/init.h>
-#include <linux/hdreg.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned int reg;
-	unsigned long flags;
-
-	/* select PIO or DMA */
-	reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82);
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	if (reg != hwif->select_data) {
-		hwif->select_data = reg;
-		outb(0x51|(hwif->channel<<3), hwif->config_data+1);	/* set PIO/DMA */
-		outw(reg & 0xff, hwif->config_data);
-	}
-
-	/* enable IRQ if not probing */
-	if (drive->present) {
-		reg = inw(hwif->config_data+3) & 0x13;
-		reg &= ~(1 << hwif->channel);
-		outw(reg, hwif->config_data+3);
-	}
-
-	__restore_flags(flags);	/* local CPU only */
-}
-
-static void trm290_selectproc (ide_drive_t *drive)
-{
-	trm290_prepare_drive(drive, drive->using_dma);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned int count, reading = 2, writing = 0;
-
-	switch (func) {
-		case ide_dma_write:
-			reading = 0;
-			writing = 1;
-#ifdef TRM290_NO_DMA_WRITES
-			break;	/* always use PIO for writes */
-#endif
-		case ide_dma_read:
-			if (!(count = ide_build_dmatable(drive, func)))
-				break;		/* try PIO instead of DMA */
-			trm290_prepare_drive(drive, 1);	/* select DMA xfer */
-			outl(hwif->dmatable_dma|reading|writing, hwif->dma_base);
-			drive->waiting_for_dma = 1;
-			outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */
-			if (drive->media != ide_disk)
-				return 0;
-			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
-			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-			return 0;
-		case ide_dma_begin:
-			return 0;
-		case ide_dma_end:
-			drive->waiting_for_dma = 0;
-			ide_destroy_dmatable(drive);		/* purge DMA mappings */
-			return (inw(hwif->dma_base+2) != 0x00ff);
-		case ide_dma_test_irq:
-			return (inw(hwif->dma_base+2) == 0x00ff);
-		default:
-			return ide_dmaproc(func, drive);
-	}
-	trm290_prepare_drive(drive, 0);	/* select PIO xfer */
-	return 1;
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * Invoked from ide-dma.c at boot time.
- */
-void __init ide_init_trm290 (ide_hwif_t *hwif)
-{
-	unsigned int cfgbase = 0;
-	unsigned long flags;
-	byte reg;
-	struct pci_dev *dev = hwif->pci_dev;
-
-	hwif->chipset = ide_trm290;
-	cfgbase = pci_resource_start(dev, 4);
-	if ((dev->class & 5) && cfgbase)
-	{
-		hwif->config_data = cfgbase;
-		printk("TRM290: chip config base at 0x%04lx\n", hwif->config_data);
-	} else {
-		hwif->config_data = 0x3df0;
-		printk("TRM290: using default config base at 0x%04lx\n", hwif->config_data);
-	}
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	/* put config reg into first byte of hwif->select_data */
-	outb(0x51|(hwif->channel<<3), hwif->config_data+1);
-	hwif->select_data = 0x21;			/* select PIO as default */
-	outb(hwif->select_data, hwif->config_data);
-	reg = inb(hwif->config_data+3);			/* get IRQ info */
-	reg = (reg & 0x10) | 0x03;			/* mask IRQs for both ports */
-	outb(reg, hwif->config_data+3);
-	__restore_flags(flags);	/* local CPU only */
-
-	if ((reg & 0x10))
-		hwif->irq = hwif->channel ? 15 : 14;	/* legacy mode */
-	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
-		hwif->irq = hwif->mate->irq;		/* sharing IRQ with mate */
-	ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	hwif->dmaproc = &trm290_dmaproc;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	hwif->selectproc = &trm290_selectproc;
-	hwif->autodma = 0;				/* play it safe for now */
-#if 1
-	{
-		/*
-		 * My trm290-based card doesn't seem to work with all possible values
-		 * for the control basereg, so this kludge ensures that we use only
-		 * values that are known to work.  Ugh.		-ml
-		 */
-		unsigned short old, compat = hwif->channel ? 0x374 : 0x3f4;
-		static unsigned short next_offset = 0;
-
-		outb(0x54|(hwif->channel<<3), hwif->config_data+1);
-		old = inw(hwif->config_data) & ~1;
-		if (old != compat && inb(old+2) == 0xff) {
-			compat += (next_offset += 0x400);	/* leave lower 10 bits untouched */
-#if 1
-			if (ide_check_region(compat + 2, 1))
-				printk("Aieee %s: ide_check_region failure at 0x%04x\n", hwif->name, (compat + 2));
-			/*
-			 * The region check is not needed; however.........
-			 * Since this is the checked in ide-probe.c,
-			 * this is only an assignment.
-			 */
-#endif
-			hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2;
-			outw(compat|1, hwif->config_data);
-			printk("%s: control basereg workaround: old=0x%04x, new=0x%04x\n", hwif->name, old, inw(hwif->config_data) & ~1);
-		}
-	}
-#endif
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/umc8672.c linux-2.4.21/drivers/ide/umc8672.c
--- linux-2.4.20/drivers/ide/umc8672.c	2000-04-14 05:54:26.000000000 +0000
+++ linux-2.4.21/drivers/ide/umc8672.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,160 +0,0 @@
-/*
- *  linux/drivers/ide/umc8672.c		Version 0.05	Jul 31, 1996
- *
- *  Copyright (C) 1995-1996  Linus Torvalds & author (see below)
- */
-
-/*
- *  Principal Author/Maintainer:  PODIEN@hml2.atlas.de (Wolfram Podien)
- *
- *  This file provides support for the advanced features
- *  of the UMC 8672 IDE interface.
- *
- *  Version 0.01	Initial version, hacked out of ide.c,
- *			and #include'd rather than compiled separately.
- *			This will get cleaned up in a subsequent release.
- *
- *  Version 0.02	now configs/compiles separate from ide.c  -ml
- *  Version 0.03	enhanced auto-tune, fix display bug
- *  Version 0.05	replace sti() with restore_flags()  -ml
- *			add detection of possible race condition  -ml
- */
-
-/*
- * VLB Controller Support from 
- * Wolfram Podien
- * Rohoefe 3
- * D28832 Achim
- * Germany
- *
- * To enable UMC8672 support there must a lilo line like
- * append="ide0=umc8672"...
- * To set the speed according to the abilities of the hardware there must be a
- * line like
- * #define UMC_DRIVE0 11
- * in the beginning of the driver, which sets the speed of drive 0 to 11 (there
- * are some lines present). 0 - 11 are allowed speed values. These values are
- * the results from the DOS speed test program supplied from UMC. 11 is the 
- * highest speed (about PIO mode 3)
- */
-#define REALLY_SLOW_IO		/* some systems can safely undef this */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/*
- * Default speeds.  These can be changed with "auto-tune" and/or hdparm.
- */
-#define UMC_DRIVE0      1              /* DOS measured drive speeds */
-#define UMC_DRIVE1      1              /* 0 to 11 allowed */
-#define UMC_DRIVE2      1              /* 11 = Fastest Speed */
-#define UMC_DRIVE3      1              /* In case of crash reduce speed */
-
-static byte current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3};
-static const byte pio_to_umc [5] = {0,3,7,10,11};	/* rough guesses */
-
-/*       0    1    2    3    4    5    6    7    8    9    10   11      */
-static const byte speedtab [3][12] = {
-	{0xf, 0xb, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
-	{0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
-	{0xff,0xcb,0xc0,0x58,0x36,0x33,0x23,0x22,0x21,0x11,0x10,0x0}};
-
-static void out_umc (char port,char wert)
-{
-	outb_p (port,0x108);
-	outb_p (wert,0x109);
-}
-
-static inline byte in_umc (char port)
-{
-	outb_p (port,0x108);
-	return inb_p (0x109);
-}
-
-static void umc_set_speeds (byte speeds[])
-{
-	int i, tmp;
-
-	outb_p (0x5A,0x108); /* enable umc */
-
-	out_umc (0xd7,(speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4)));
-	out_umc (0xd6,(speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4)));
-	tmp = 0;
-	for (i = 3; i >= 0; i--)
-	{
-		tmp = (tmp << 2) | speedtab[1][speeds[i]];
-	}
-	out_umc (0xdc,tmp);
-	for (i = 0;i < 4; i++)
-	{
-		out_umc (0xd0+i,speedtab[2][speeds[i]]);
-		out_umc (0xd8+i,speedtab[2][speeds[i]]);
-	}
-	outb_p (0xa5,0x108); /* disable umc */
-
-	printk ("umc8672: drive speeds [0 to 11]: %d %d %d %d\n",
-		speeds[0], speeds[1], speeds[2], speeds[3]);
-}
-
-static void tune_umc (ide_drive_t *drive, byte pio)
-{
-	unsigned long flags;
-	ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
-
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-	printk("%s: setting umc8672 to PIO mode%d (speed %d)\n", drive->name, pio, pio_to_umc[pio]);
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-	if (hwgroup && hwgroup->handler != NULL) {
-		printk("umc8672: other interface is busy: exiting tune_umc()\n");
-	} else {
-		current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
-		umc_set_speeds (current_speeds);
-	}
-	restore_flags(flags);	/* all CPUs */
-}
-
-void __init init_umc8672 (void)	/* called from ide.c */
-{
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	if (check_region(0x108, 2)) {
-		__restore_flags(flags);
-		printk("\numc8672: PORTS 0x108-0x109 ALREADY IN USE\n");
-		return;
-	}
-	outb_p (0x5A,0x108); /* enable umc */
-	if (in_umc (0xd5) != 0xa0)
-	{
-		__restore_flags(flags);	/* local CPU only */
-		printk ("umc8672: not found\n");
-		return;  
-	}
-	outb_p (0xa5,0x108); /* disable umc */
-
-	umc_set_speeds (current_speeds);
-	__restore_flags(flags);	/* local CPU only */
-
-	request_region(0x108, 2, "umc8672");
-	ide_hwifs[0].chipset = ide_umc8672;
-	ide_hwifs[1].chipset = ide_umc8672;
-	ide_hwifs[0].tuneproc = &tune_umc;
-	ide_hwifs[1].tuneproc = &tune_umc;
-	ide_hwifs[0].mate = &ide_hwifs[1];
-	ide_hwifs[1].mate = &ide_hwifs[0];
-	ide_hwifs[1].channel = 1;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/via82cxxx.c linux-2.4.21/drivers/ide/via82cxxx.c
--- linux-2.4.20/drivers/ide/via82cxxx.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ide/via82cxxx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,532 +0,0 @@
-/*
- * Version 3.35
- *
- * VIA IDE driver for Linux. Supported southbridges:
- *
- *   vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
- *   vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a,
- *   vt8235
- *
- * Copyright (c) 2000-2002 Vojtech Pavlik
- *
- * Based on the work of:
- *	Michel Aubry
- *	Jeff Garzik
- *	Andre Hedrick
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <asm/io.h>
-
-#include "ide-timing.h"
-
-#define VIA_IDE_ENABLE		0x40
-#define VIA_IDE_CONFIG		0x41
-#define VIA_FIFO_CONFIG		0x43
-#define VIA_MISC_1		0x44
-#define VIA_MISC_2		0x45
-#define VIA_MISC_3		0x46
-#define VIA_DRIVE_TIMING	0x48
-#define VIA_8BIT_TIMING		0x4e
-#define VIA_ADDRESS_SETUP	0x4c
-#define VIA_UDMA_TIMING		0x50
-
-#define VIA_UDMA		0x007
-#define VIA_UDMA_NONE		0x000
-#define VIA_UDMA_33		0x001
-#define VIA_UDMA_66		0x002
-#define VIA_UDMA_100		0x003
-#define VIA_UDMA_133		0x004
-#define VIA_BAD_PREQ		0x010	/* Crashes if PREQ# till DDACK# set */
-#define VIA_BAD_CLK66		0x020	/* 66 MHz clock doesn't work correctly */
-#define VIA_SET_FIFO		0x040	/* Needs to have FIFO split set */
-#define VIA_NO_UNMASK		0x080	/* Doesn't work with IRQ unmasking on */
-#define VIA_BAD_ID		0x100	/* Has wrong vendor ID (0x1107) */
-
-#ifndef PCI_DEVICE_ID_VIA_8235
-#define PCI_DEVICE_ID_VIA_8235 0x3177
-#endif
-
-/*
- * VIA SouthBridge chips.
- */
-
-static struct via_isa_bridge {
-	char *name;
-	unsigned short id;
-	unsigned char rev_min;
-	unsigned char rev_max;
-	unsigned short flags;
-} via_isa_bridges[] = {
-#ifdef FUTURE_BRIDGES
-	{ "vt8237",	PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_133 },
-#endif
-	{ "vt8235",	PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_133 },
-	{ "vt8233a",	PCI_DEVICE_ID_VIA_8233A,    0x00, 0x2f, VIA_UDMA_133 },
-	{ "vt8233c",	PCI_DEVICE_ID_VIA_8233C_0,  0x00, 0x2f, VIA_UDMA_100 },
-	{ "vt8233",	PCI_DEVICE_ID_VIA_8233_0,   0x00, 0x2f, VIA_UDMA_100 },
-	{ "vt8231",	PCI_DEVICE_ID_VIA_8231,     0x00, 0x2f, VIA_UDMA_100 },
-	{ "vt82c686b",	PCI_DEVICE_ID_VIA_82C686,   0x40, 0x4f, VIA_UDMA_100 },
-	{ "vt82c686a",	PCI_DEVICE_ID_VIA_82C686,   0x10, 0x2f, VIA_UDMA_66 },
-	{ "vt82c686",	PCI_DEVICE_ID_VIA_82C686,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
-	{ "vt82c596b",	PCI_DEVICE_ID_VIA_82C596,   0x10, 0x2f, VIA_UDMA_66 },
-	{ "vt82c596a",	PCI_DEVICE_ID_VIA_82C596,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
-	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO },
-	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ },
-	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO },
-	{ "vt82c586a",	PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
-	{ "vt82c586",	PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
-	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
-	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
-	{ NULL }
-};
-
-static struct via_isa_bridge *via_config;
-static unsigned char via_enabled;
-static unsigned int via_80w;
-static unsigned int via_clock;
-static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
-
-/*
- * VIA /proc entry.
- */
-
-#ifdef CONFIG_PROC_FS
-
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-int via_proc, via_base;
-static struct pci_dev *bmide_dev, *isa_dev;
-extern int (*via_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-
-static char *via_control3[] = { "No limit", "64", "128", "192" };
-
-#define via_print(format, arg...) p += sprintf(p, format "\n" , ## arg)
-#define via_print_drive(name, format, arg...)\
-	p += sprintf(p, name); for (i = 0; i < 4; i++) p += sprintf(p, format, ## arg); p += sprintf(p, "\n");
-
-static int via_get_info(char *buffer, char **addr, off_t offset, int count)
-{
-	int speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
-		 uen[4], udma[4], umul[4], active8b[4], recover8b[4];
-	struct pci_dev *dev = bmide_dev;
-	unsigned int v, u, i;
-	unsigned short c, w;
-	unsigned char t, x;
-	char *p = buffer;
-
-	via_print("----------VIA BusMastering IDE Configuration----------------");
-
-	via_print("Driver Version:                     3.35");
-	via_print("South Bridge:                       VIA %s", via_config->name);
-
-	pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t);
-	pci_read_config_byte(dev, PCI_REVISION_ID, &x);
-	via_print("Revision:                           ISA %#x IDE %#x", t, x);
-	via_print("Highest DMA rate:                   %s", via_dma[via_config->flags & VIA_UDMA]);
-
-	via_print("BM-DMA base:                        %#x", via_base);
-	via_print("PCI clock:                          %d.%dMHz", via_clock / 1000, via_clock / 100 % 10);
-
-	pci_read_config_byte(dev, VIA_MISC_1, &t);
-	via_print("Master Read  Cycle IRDY:            %dws", (t & 64) >> 6);
-	via_print("Master Write Cycle IRDY:            %dws", (t & 32) >> 5);
-	via_print("BM IDE Status Register Read Retry:  %s", (t & 8) ? "yes" : "no");
-
-	pci_read_config_byte(dev, VIA_MISC_3, &t);
-	via_print("Max DRDY Pulse Width:               %s%s", via_control3[(t & 0x03)], (t & 0x03) ? " PCI clocks" : "");
-
-	via_print("-----------------------Primary IDE-------Secondary IDE------");
-	via_print("Read DMA FIFO flush:   %10s%20s", (t & 0x80) ? "yes" : "no", (t & 0x40) ? "yes" : "no");
-	via_print("End Sector FIFO flush: %10s%20s", (t & 0x20) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
-
-	pci_read_config_byte(dev, VIA_IDE_CONFIG, &t);
-	via_print("Prefetch Buffer:       %10s%20s", (t & 0x80) ? "yes" : "no", (t & 0x20) ? "yes" : "no");
-	via_print("Post Write Buffer:     %10s%20s", (t & 0x40) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
-
-	pci_read_config_byte(dev, VIA_IDE_ENABLE, &t);
-	via_print("Enabled:               %10s%20s", (t & 0x02) ? "yes" : "no", (t & 0x01) ? "yes" : "no");
-
-	c = inb(via_base + 0x02) | (inb(via_base + 0x0a) << 8);
-	via_print("Simplex only:          %10s%20s", (c & 0x80) ? "yes" : "no", (c & 0x8000) ? "yes" : "no");
-
-	via_print("Cable Type:            %10s%20s", (via_80w & 1) ? "80w" : "40w", (via_80w & 2) ? "80w" : "40w");
-
-	via_print("-------------------drive0----drive1----drive2----drive3-----");
-
-	pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
-	pci_read_config_dword(dev, VIA_DRIVE_TIMING, &v);
-	pci_read_config_word(dev, VIA_8BIT_TIMING, &w);
-
-	if (via_config->flags & VIA_UDMA)
-		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
-	else u = 0;
-
-	for (i = 0; i < 4; i++) {
-
-		setup[i]     = ((t >> ((3 - i) << 1)) & 0x3) + 1;
-		recover8b[i] = ((w >> ((1 - (i >> 1)) << 3)) & 0xf) + 1;
-		active8b[i]  = ((w >> (((1 - (i >> 1)) << 3) + 4)) & 0xf) + 1;
-		active[i]    = ((v >> (((3 - i) << 3) + 4)) & 0xf) + 1;
-		recover[i]   = ((v >> ((3 - i) << 3)) & 0xf) + 1;
-		udma[i]      = ((u >> ((3 - i) << 3)) & 0x7) + 2;
-		umul[i]      = ((u >> (((3 - i) & 2) << 3)) & 0x8) ? 1 : 2;
-		uen[i]       = ((u >> ((3 - i) << 3)) & 0x20);
-		den[i]       = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2));
-
-		speed[i] = 2 * via_clock / (active[i] + recover[i]);
-		cycle[i] = 1000000 * (active[i] + recover[i]) / via_clock;
-
-		if (!uen[i] || !den[i])
-			continue;
-
-		switch (via_config->flags & VIA_UDMA) {
-
-			case VIA_UDMA_33:
-				speed[i] = 2 * via_clock / udma[i];
-				cycle[i] = 1000000 * udma[i] / via_clock;
-				break;
-
-			case VIA_UDMA_66:
-				speed[i] = 4 * via_clock / (udma[i] * umul[i]);
-				cycle[i] = 500000 * (udma[i] * umul[i]) / via_clock;
-				break;
-
-			case VIA_UDMA_100:
-				speed[i] = 6 * via_clock / udma[i];
-				cycle[i] = 333333 * udma[i] / via_clock;
-				break;
-
-			case VIA_UDMA_133:
-				speed[i] = 8 * via_clock / udma[i];
-				cycle[i] = 250000 * udma[i] / via_clock;
-				break;
-		}
-	}
-
-	via_print_drive("Transfer Mode: ", "%10s", den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO");
-
-	via_print_drive("Address Setup: ", "%8dns", 1000000 * setup[i] / via_clock);
-	via_print_drive("Cmd Active:    ", "%8dns", 1000000 * active8b[i] / via_clock);
-	via_print_drive("Cmd Recovery:  ", "%8dns", 1000000 * recover8b[i] / via_clock);
-	via_print_drive("Data Active:   ", "%8dns", 1000000 * active[i] / via_clock);
-	via_print_drive("Data Recovery: ", "%8dns", 1000000 * recover[i] / via_clock);
-	via_print_drive("Cycle Time:    ", "%8dns", cycle[i]);
-	via_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 1000, speed[i] / 100 % 10);
-
-	return p - buffer;	/* hoping it is less than 4K... */
-}
-
-#endif
-
-/*
- * via_set_speed() writes timing values to the chipset registers
- */
-
-static void via_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timing *timing)
-{
-	unsigned char t;
-
-	pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
-	t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
-	pci_write_config_byte(dev, VIA_ADDRESS_SETUP, t);
-
-	pci_write_config_byte(dev, VIA_8BIT_TIMING + (1 - (dn >> 1)),
-		((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1));
-
-	pci_write_config_byte(dev, VIA_DRIVE_TIMING + (3 - dn),
-		((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1));
-
-	switch (via_config->flags & VIA_UDMA) {
-		case VIA_UDMA_33:  t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
-		case VIA_UDMA_66:  t = timing->udma ? (0xe8 | (FIT(timing->udma, 2, 9) - 2)) : 0x0f; break;
-		case VIA_UDMA_100: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
-		case VIA_UDMA_133: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
-		default: return;
-	}
-
-	pci_write_config_byte(dev, VIA_UDMA_TIMING + (3 - dn), t);
-}
-
-/*
- * via_set_drive() computes timing values configures the drive and
- * the chipset to a desired transfer mode. It also can be called
- * by upper layers.
- */
-
-static int via_set_drive(ide_drive_t *drive, unsigned char speed)
-{
-	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
-	struct ide_timing t, p;
-	unsigned int T, UT;
-
-	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
-		if (ide_config_drive_speed(drive, speed))
-			printk(KERN_WARNING "ide%d: Drive %d didn't accept speed setting. Oh, well.\n",
-				drive->dn >> 1, drive->dn & 1);
-
-	T = 1000000000 / via_clock;
-
-	switch (via_config->flags & VIA_UDMA) {
-		case VIA_UDMA_33:   UT = T;   break;
-		case VIA_UDMA_66:   UT = T/2; break;
-		case VIA_UDMA_100:  UT = T/3; break;
-		case VIA_UDMA_133:  UT = T/4; break;
-		default: UT = T;
-	}
-
-	ide_timing_compute(drive, speed, &t, T, UT);
-
-	if (peer->present) {
-		ide_timing_compute(peer, peer->current_speed, &p, T, UT);
-		ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
-	}
-
-	via_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-	drive->current_speed = speed;
-
-	return 0;
-}
-
-/*
- * via82cxxx_tune_drive() is a callback from upper layers for
- * PIO-only tuning.
- */
-
-static void via82cxxx_tune_drive(ide_drive_t *drive, unsigned char pio)
-{
-	if (!((via_enabled >> HWIF(drive)->channel) & 1))
-		return;
-
-	if (pio == 255) {
-		via_set_drive(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO));
-		return;
-	}
-
-	via_set_drive(drive, XFER_PIO_0 + MIN(pio, 5));
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-
-/*
- * via82cxxx_dmaproc() is a callback from upper layers that can do
- * a lot, but we use it for DMA/PIO tuning only, delegating everything
- * else to the default ide_dmaproc().
- */
-
-int via82cxxx_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-
-	if (func == ide_dma_check) {
-
-		short w80 = HWIF(drive)->udma_four;
-
-		short speed = ide_find_best_mode(drive,
-			XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
-			(via_config->flags & VIA_UDMA ? XFER_UDMA : 0) |
-			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) |
-			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) |
-			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0));
-
-		via_set_drive(drive, speed);
-
-		func = (HWIF(drive)->autodma && (speed & XFER_MODE) != XFER_PIO)
-			? ide_dma_on : ide_dma_off_quietly;
-	}
-
-	return ide_dmaproc(func, drive);
-}
-
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * The initialization callback. Here we determine the IDE chip type
- * and initialize its drive independent registers.
- */
-
-unsigned int __init pci_init_via82cxxx(struct pci_dev *dev, const char *name)
-{
-	struct pci_dev *isa = NULL;
-	unsigned char t, v;
-	unsigned int u;
-	int i;
-
-/*
- * Find the ISA bridge to see how good the IDE is.
- */
-
-	for (via_config = via_isa_bridges; via_config->id; via_config++)
-		if ((isa = pci_find_device(PCI_VENDOR_ID_VIA +
-			!!(via_config->flags & VIA_BAD_ID), via_config->id, NULL))) {
-
-			pci_read_config_byte(isa, PCI_REVISION_ID, &t);
-			if (t >= via_config->rev_min && t <= via_config->rev_max)
-				break;
-		}
-
-	if (!via_config->id) {
-		printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, contact Vojtech Pavlik <vojtech@ucw.cz>\n");
-		return -ENODEV;
-	}
-
-/*
- * Check 80-wire cable presence and setup Clk66.
- */
-
-	switch (via_config->flags & VIA_UDMA) {
-
-		case VIA_UDMA_66:
-			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);	/* Enable Clk66 */
-			pci_write_config_dword(dev, VIA_UDMA_TIMING, u | 0x80008);
-			for (i = 24; i >= 0; i -= 8)
-				if (((u >> (i & 16)) & 8) && ((u >> i) & 0x20) && (((u >> i) & 7) < 2))
-					via_80w |= (1 << (1 - (i >> 4)));	/* 2x PCI clock and UDMA w/ < 3T/cycle */
-			break;
-
-		case VIA_UDMA_100:
-			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
-			for (i = 24; i >= 0; i -= 8)
-				if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 4)))
-					via_80w |= (1 << (1 - (i >> 4)));	/* BIOS 80-wire bit or UDMA w/ < 60ns/cycle */
-			break;
-
-		case VIA_UDMA_133:
-			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
-			for (i = 24; i >= 0; i -= 8)
-				if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 8)))
-					via_80w |= (1 << (1 - (i >> 4)));	/* BIOS 80-wire bit or UDMA w/ < 60ns/cycle */
-			break;
-
-	}
-
-	if (via_config->flags & VIA_BAD_CLK66) {			/* Disable Clk66 */
-		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);	/* Would cause trouble on 596a and 686 */
-		pci_write_config_dword(dev, VIA_UDMA_TIMING, u & ~0x80008);
-	}
-
-/*
- * Check whether interfaces are enabled.
- */
-
-	pci_read_config_byte(dev, VIA_IDE_ENABLE, &v);
-	via_enabled = ((v & 1) ? 2 : 0) | ((v & 2) ? 1 : 0);
-
-/*
- * Set up FIFO sizes and thresholds.
- */
-
-	pci_read_config_byte(dev, VIA_FIFO_CONFIG, &t);
-
-	if (via_config->flags & VIA_BAD_PREQ)				/* Disable PREQ# till DDACK# */
-		t &= 0x7f;						/* Would crash on 586b rev 41 */
-
-	if (via_config->flags & VIA_SET_FIFO) {				/* Fix FIFO split between channels */
-		t &= (t & 0x9f);
-		switch (via_enabled) {
-			case 1: t |= 0x00; break;			/* 16 on primary */
-			case 2: t |= 0x60; break;			/* 16 on secondary */
-			case 3: t |= 0x20; break;			/* 8 pri 8 sec */
-		}
-	}
-
-	pci_write_config_byte(dev, VIA_FIFO_CONFIG, t);
-
-/*
- * Determine system bus clock.
- */
-
-	via_clock = system_bus_clock() * 1000;
-
-	switch (via_clock) {
-		case 33000: via_clock = 33333; break;
-		case 37000: via_clock = 37500; break;
-		case 41000: via_clock = 41666; break;
-	}
-
-	if (via_clock < 20000 || via_clock > 50000) {
-		printk(KERN_WARNING "VP_IDE: User given PCI clock speed impossible (%d), using 33 MHz instead.\n", via_clock);
-		printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want to assume 80-wire cable.\n");
-		via_clock = 33333;
-	}
-
-/*
- * Print the boot message.
- */
-
-	pci_read_config_byte(isa, PCI_REVISION_ID, &t);
-	printk(KERN_INFO "VP_IDE: VIA %s (rev %02x) IDE %s controller on pci%s\n",
-		via_config->name, t, via_dma[via_config->flags & VIA_UDMA], dev->slot_name);
-
-/*
- * Setup /proc/ide/via entry.
- */
-
-#ifdef CONFIG_PROC_FS
-	if (!via_proc) {
-		via_base = pci_resource_start(dev, 4);
-		bmide_dev = dev;
-		isa_dev = isa;
-		via_display_info = &via_get_info;
-		via_proc = 1;
-	}
-#endif
-
-	return 0;
-}
-
-unsigned int __init ata66_via82cxxx(ide_hwif_t *hwif)
-{
-	return ((via_enabled & via_80w) >> hwif->channel) & 1;
-}
-
-void __init ide_init_via82cxxx(ide_hwif_t *hwif)
-{
-	int i;
-
-	hwif->tuneproc = &via82cxxx_tune_drive;
-	hwif->speedproc = &via_set_drive;
-	hwif->autodma = 0;
-
-	for (i = 0; i < 2; i++) {
-		hwif->drives[i].io_32bit = 1;
-		hwif->drives[i].unmask = (via_config->flags & VIA_NO_UNMASK) ? 0 : 1;
-		hwif->drives[i].autotune = 1;
-		hwif->drives[i].dn = hwif->channel * 2 + i;
-	}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		hwif->dmaproc = &via82cxxx_dmaproc;
-#ifdef CONFIG_IDEDMA_AUTO
-		if (!noautodma)
-			hwif->autodma = 1;
-#endif
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-/*
- * We allow the BM-DMA driver to only work on enabled interfaces.
- */
-
-void __init ide_dmacapable_via82cxxx(ide_hwif_t *hwif, unsigned long dmabase)
-{
-	if ((via_enabled >> hwif->channel) & 1)
-		ide_setup_dma(hwif, dmabase, 8);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/Makefile linux-2.4.21/drivers/ieee1394/Makefile
--- linux-2.4.20/drivers/ieee1394/Makefile	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/Makefile	2002-12-18 18:58:12.000000000 +0000
@@ -2,11 +2,8 @@
 # Makefile for the Linux IEEE 1394 implementation
 #
 
-O_TARGET := ieee1394drv.o
-
 export-objs := ieee1394_core.o ohci1394.o cmp.o
 
-list-multi := ieee1394.o
 ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
 		 highlevel.o csr.o nodemgr.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/amdtp.c linux-2.4.21/drivers/ieee1394/amdtp.c
--- linux-2.4.20/drivers/ieee1394/amdtp.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/amdtp.c	2002-12-18 18:58:10.000000000 +0000
@@ -834,7 +834,8 @@
 
 	max_packet_size = max_nevents * s->dimension * 4 + 8;
 	s->packet_pool = pci_pool_create("packet pool", s->host->ohci->dev,
-					 max_packet_size, 0, 0, SLAB_KERNEL);
+					 max_packet_size, 0, 0 ,SLAB_KERNEL);
+
 	if (s->packet_pool == NULL)
 		return -1;
 
@@ -1021,6 +1022,7 @@
 	s->descriptor_pool = pci_pool_create("descriptor pool", host->ohci->dev,
 					     sizeof(struct descriptor_block),
 					     16, 0, SLAB_KERNEL);
+
 	if (s->descriptor_pool == NULL) {
 		kfree(s->input);
 		kfree(s);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/cmp.c linux-2.4.21/drivers/ieee1394/cmp.c
--- linux-2.4.20/drivers/ieee1394/cmp.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/cmp.c	2002-12-18 18:58:04.000000000 +0000
@@ -199,7 +199,7 @@
 }
 
 static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf,
-		    u64 addr, unsigned int length)
+		    u64 addr, unsigned int length, u16 flags)
 {
 	int csraddr = addr - CSR_REGISTER_BASE;
 	int plug;
@@ -235,7 +235,7 @@
 }
 
 static int pcr_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
-		    u64 addr, quadlet_t data, quadlet_t arg, int extcode)
+		    u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 flags)
 {
 	int csraddr = addr - CSR_REGISTER_BASE;
 	int plug;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/csr.c linux-2.4.21/drivers/ieee1394/csr.c
--- linux-2.4.20/drivers/ieee1394/csr.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/csr.c	2002-12-18 18:58:04.000000000 +0000
@@ -4,20 +4,33 @@
  * CSR implementation, iso/bus manager implementation.
  *
  * Copyright (C) 1999 Andreas E. Bombe
+ *               2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
  *
  * This code is licensed under the GPL.  See the file COPYING in the root
  * directory of the kernel sources for details.
+ *
+ *
+ * Contributions:
+ *
+ * Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *        configuration ROM manipulation
+ *
  */
 
 #include <linux/string.h>
+#include <linux/module.h> /* needed for MODULE_PARM */
 
 #include "ieee1394_types.h"
 #include "hosts.h"
 #include "ieee1394.h"
 #include "highlevel.h"
 
+/* Module Parameters */
+/* this module parameter can be used to disable mapping of the FCP registers */
+MODULE_PARM(fcp,"i");
+MODULE_PARM_DESC(fcp, "FCP-registers");
+static int fcp = 1;
 
-/* FIXME: this one won't work on little endian with big endian data */
 static u16 csr_crc16(unsigned *data, int length)
 {
         int check=0, i;
@@ -25,7 +38,7 @@
 
         for (i = length; i; i--) {
                 for (next = check, shift = 28; shift >= 0; shift -= 4 ) {
-                        sum = ((next >> 12) ^ (*data >> shift)) & 0xf;
+                        sum = ((next >> 12) ^ (be32_to_cpu(*data) >> shift)) & 0xf;
                         next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
                 }
                 check = next & 0xffff;
@@ -60,6 +73,8 @@
                             | csr_crc16(host->csr.topology_map + 1,
                                         host->selfid_count + 2));
 
+        host->csr.speed_map[1] = 
+                cpu_to_be32(be32_to_cpu(host->csr.speed_map[1]) + 1);
         host->csr.speed_map[0] = cpu_to_be32(0x3f1 << 16 
                                              | csr_crc16(host->csr.speed_map+1,
                                                          0x3f1));
@@ -71,7 +86,7 @@
         host->csr.lock = SPIN_LOCK_UNLOCKED;
 
         host->csr.rom_size = host->driver->get_rom(host, &host->csr.rom);
-
+        host->csr.rom_version           = 0;
         host->csr.state                 = 0;
         host->csr.node_ids              = 0;
         host->csr.split_timeout_hi      = 0;
@@ -84,13 +99,52 @@
         host->csr.channels_available_lo = ~0;
 }
 
+int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom, 
+	size_t size, unsigned char rom_version)
+{
+        int ret,flags;
+        spin_lock_irqsave(&host->csr.lock, flags); 
+        if (rom_version != host->csr.rom_version)
+                 ret = -1;
+        else if (size > (CSR_CONFIG_ROM_SIZE << 2))
+                 ret = -2;
+        else {
+                 memcpy(host->csr.rom,new_rom,size);
+                 host->csr.rom_size=size;
+                 host->csr.rom_version++;
+                 ret=0;
+        }
+        spin_unlock_irqrestore(&host->csr.lock, flags);
+        return ret;
+}
+
+int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer, 
+	size_t buffersize, size_t *rom_size, unsigned char *rom_version)
+{
+        int ret,flags;
+        spin_lock_irqsave(&host->csr.lock, flags); 
+        *rom_version=host->csr.rom_version;
+        *rom_size=host->csr.rom_size;
+        if (buffersize < host->csr.rom_size)
+                 ret = -1;
+        else {
+                 memcpy(buffer,host->csr.rom,host->csr.rom_size);
+                 ret=0;
+        }
+        spin_unlock_irqrestore(&host->csr.lock, flags);
+        return ret;
+}
+
 
 /* Read topology / speed maps and configuration ROM */
 static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                     u64 addr, unsigned int length)
+                     u64 addr, unsigned int length, u16 fl)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
         const char *src;
+        int flags;
+
+        spin_lock_irqsave(&host->csr.lock, flags); 
 
         if (csraddr < CSR_TOPOLOGY_MAP) {
                 if (csraddr + length > CSR_CONFIG_ROM + host->csr.rom_size) {
@@ -105,6 +159,7 @@
         }
 
         memcpy(buffer, src, length);
+        spin_unlock_irqrestore(&host->csr.lock, flags);
         return RCODE_COMPLETE;
 }
 
@@ -112,7 +167,7 @@
 #define out if (--length == 0) break
 
 static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
-                     u64 addr, unsigned int length)
+                     u64 addr, unsigned int length, u16 flags)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
         int oldcycle;
@@ -222,7 +277,7 @@
 }
 
 static int write_regs(struct hpsb_host *host, int nodeid, int destid,
-		      quadlet_t *data, u64 addr, unsigned int length)
+		      quadlet_t *data, u64 addr, unsigned int length, u16 flags)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
         
@@ -302,7 +357,7 @@
 
 
 static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
-                     u64 addr, quadlet_t data, quadlet_t arg, int extcode)
+                     u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
         unsigned long flags;
@@ -379,7 +434,7 @@
 }
 
 static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
-		     quadlet_t *data, u64 addr, unsigned int length)
+		     quadlet_t *data, u64 addr, unsigned int length, u16 flags)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
 
@@ -436,9 +491,11 @@
         hpsb_register_addrspace(hl, &map_ops, 
                                 CSR_REGISTER_BASE + CSR_CONFIG_ROM,
                                 CSR_REGISTER_BASE + CSR_CONFIG_ROM_END);
-        hpsb_register_addrspace(hl, &fcp_ops,
+        if (fcp) {
+		hpsb_register_addrspace(hl, &fcp_ops,
                                 CSR_REGISTER_BASE + CSR_FCP_COMMAND,
                                 CSR_REGISTER_BASE + CSR_FCP_END);
+	}
         hpsb_register_addrspace(hl, &map_ops,
                                 CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP,
                                 CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP_END);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/csr.h linux-2.4.21/drivers/ieee1394/csr.h
--- linux-2.4.20/drivers/ieee1394/csr.h	2001-03-02 00:57:11.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/csr.h	2002-12-18 18:58:02.000000000 +0000
@@ -41,8 +41,10 @@
         quadlet_t bandwidth_available;
         quadlet_t channels_available_hi, channels_available_lo;
 
-        const quadlet_t *rom;
+        quadlet_t *rom;
         size_t rom_size;
+        unsigned char rom_version;
+
 
         quadlet_t topology_map[256];
         quadlet_t speed_map[1024];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/dv1394.c linux-2.4.21/drivers/ieee1394/dv1394.c
--- linux-2.4.20/drivers/ieee1394/dv1394.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/dv1394.c	2002-12-18 18:58:04.000000000 +0000
@@ -97,7 +97,6 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/proc_fs.h>
-#include <linux/tqueue.h>
 #include <linux/delay.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -2587,6 +2586,7 @@
 	return p;
 }
 
+#ifdef CONFIG_DEVFS_FS
 static int dv1394_devfs_add_entry(struct video_card *video)
 {
 	char buf[32];
@@ -2694,6 +2694,7 @@
 		kfree(p);
 	}
 }
+#endif /* CONFIG_DEVFS_FS */
 
 /*** IEEE1394 HPSB CALLBACKS ***********************************************/
 
@@ -2852,7 +2853,6 @@
 {
 	struct ti_ohci *ohci;
 	char buf[16];
-	struct dv1394_devfs_entry *devfs_entry;
 
 	/* We only work with the OHCI-1394 driver */
 	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
@@ -2874,13 +2874,15 @@
 #endif
 
 #ifdef CONFIG_DEVFS_FS
-	devfs_entry = dv1394_devfs_find("dv");
+{
+	struct dv1394_devfs_entry *devfs_entry = dv1394_devfs_find("dv");
 	if (devfs_entry != NULL) {
 		snprintf(buf, sizeof(buf), "host%d", ohci->id);
 		dv1394_devfs_add_dir(buf, devfs_entry, &devfs_entry);
 		dv1394_devfs_add_dir("NTSC", devfs_entry, NULL);
 		dv1394_devfs_add_dir("PAL", devfs_entry, NULL);
 	}
+}
 #endif
 	
 	dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/eth1394.c linux-2.4.21/drivers/ieee1394/eth1394.c
--- linux-2.4.20/drivers/ieee1394/eth1394.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/eth1394.c	2002-12-18 18:58:11.000000000 +0000
@@ -77,7 +77,7 @@
 	printk(KERN_ERR fmt, ## args)
 
 static char version[] __devinitdata =
-	"$Rev: 546 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 601 $ Ben Collins <bcollins@debian.org>";
 
 /* Our ieee1394 highlevel driver */
 #define ETHER1394_DRIVER_NAME "ether1394"
@@ -522,7 +522,7 @@
  * ethernet header, and fill it with some of our other fields. This is
  * an incoming packet from the 1394 bus.  */
 static int ether1394_write (struct hpsb_host *host, int srcid, int destid,
-			    quadlet_t *data, u64 addr, unsigned int len)
+			    quadlet_t *data, u64 addr, unsigned int len, u16 fl)
 {
 	struct sk_buff *skb;
 	char *buf = (char *)data;
@@ -682,8 +682,8 @@
 	ptask->skb = skb;
 	ptask->addr = addr;
 	ptask->dest_node = dest_node;
-	INIT_TQUEUE(&ptask->tq, hpsb_write_sched, ptask);
-	schedule_task(&ptask->tq);
+	HPSB_INIT_WORK(&ptask->tq, hpsb_write_sched, ptask);
+	hpsb_schedule_work(&ptask->tq);
 
 	return 0;
 fail:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/eth1394.h linux-2.4.21/drivers/ieee1394/eth1394.h
--- linux-2.4.20/drivers/ieee1394/eth1394.h	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/eth1394.h	2002-12-18 18:58:04.000000000 +0000
@@ -56,7 +56,7 @@
 	struct sk_buff *skb;	/* Socket buffer we are sending */
 	nodeid_t dest_node;	/* Destination of the packet */
 	u64 addr;		/* Address */
-	struct tq_struct tq;	/* The task */
+	struct hpsb_queue_struct tq;	/* The task */
 };
 
 /* IP1394 headers */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/highlevel.c linux-2.4.21/drivers/ieee1394/highlevel.c
--- linux-2.4.20/drivers/ieee1394/highlevel.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/highlevel.c	2002-12-18 18:58:06.000000000 +0000
@@ -5,6 +5,16 @@
  *
  * This code is licensed under the GPL.  See the file COPYING in the root
  * directory of the kernel sources for details.
+ *
+ *
+ * Contributions:
+ *
+ * Christian Toegel <christian.toegel@gmx.at>
+ *        unregister address space
+ *
+ * Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *        unregister address space
+ *
  */
 
 #include <linux/config.h>
@@ -129,6 +139,32 @@
         return retval;
 }
 
+int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, u64 start)
+{
+        int retval = 0;
+        struct hpsb_address_serve *as;
+        struct list_head *entry;
+
+        write_lock_irq(&addr_space_lock);
+
+        entry = hl->addr_list.next;
+
+        while (entry != &hl->addr_list) {
+                as = list_entry(entry, struct hpsb_address_serve, addr_list);
+                entry = entry->next;
+                if (as->start == start) {
+                        list_del(&as->as_list);
+                        list_del(&as->addr_list);
+                        kfree(as);
+                        retval = 1;
+                        break;
+                }
+        }
+
+        write_unlock_irq(&addr_space_lock);
+
+        return retval;
+}
 
 void hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
                          unsigned int channel)
@@ -243,7 +279,7 @@
 }
 
 int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                   u64 addr, unsigned int length)
+                   u64 addr, unsigned int length, u16 flags)
 {
         struct hpsb_address_serve *as;
         struct list_head *entry;
@@ -261,7 +297,7 @@
 
                         if (as->op->read != NULL) {
                                 rcode = as->op->read(host, nodeid, buffer,
-						     addr, partlength);
+						     addr, partlength, flags);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
@@ -288,7 +324,7 @@
 }
 
 int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
-		    quadlet_t *data, u64 addr, unsigned int length)
+		    quadlet_t *data, u64 addr, unsigned int length, u16 flags)
 {
         struct hpsb_address_serve *as;
         struct list_head *entry;
@@ -306,7 +342,7 @@
 
                         if (as->op->write != NULL) {
                                 rcode = as->op->write(host, nodeid, destid,
-						      data, addr, partlength);
+						      data, addr, partlength, flags);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
@@ -334,7 +370,7 @@
 
 
 int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
-                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode)
+                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags)
 {
         struct hpsb_address_serve *as;
         struct list_head *entry;
@@ -349,7 +385,7 @@
                 if (as->end > addr) {
                         if (as->op->lock != NULL) {
                                 rcode = as->op->lock(host, nodeid, store, addr,
-                                                     data, arg, ext_tcode);
+                                                     data, arg, ext_tcode, flags);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
@@ -367,7 +403,7 @@
 }
 
 int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
-                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode)
+                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags)
 {
         struct hpsb_address_serve *as;
         struct list_head *entry;
@@ -383,7 +419,7 @@
                         if (as->op->lock64 != NULL) {
                                 rcode = as->op->lock64(host, nodeid, store,
                                                        addr, data, arg,
-                                                       ext_tcode);
+                                                       ext_tcode, flags);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/highlevel.h linux-2.4.21/drivers/ieee1394/highlevel.h
--- linux-2.4.20/drivers/ieee1394/highlevel.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/highlevel.h	2002-12-18 18:58:06.000000000 +0000
@@ -74,17 +74,22 @@
          */
 
         /* These functions have to implement block reads for themselves. */
+        /* These functions either return a response code
+           or a negative number. In the first case a response will be generated; in the 
+           later case, no response will be sent and the driver, that handled the request
+           will send the response itself
+        */
         int (*read) (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                     u64 addr, unsigned int length);
+                     u64 addr, unsigned int length, u16 flags);
         int (*write) (struct hpsb_host *host, int nodeid, int destid,
-		      quadlet_t *data, u64 addr, unsigned int length);
+		      quadlet_t *data, u64 addr, unsigned int length, u16 flags);
 
         /* Lock transactions: write results of ext_tcode operation into
          * *store. */
         int (*lock) (struct hpsb_host *host, int nodeid, quadlet_t *store,
-                     u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode);
+                     u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags);
         int (*lock64) (struct hpsb_host *host, int nodeid, octlet_t *store,
-                       u64 addr, octlet_t data, octlet_t arg, int ext_tcode);
+                       u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
 };
 
 
@@ -94,14 +99,23 @@
 void highlevel_remove_host(struct hpsb_host *host);
 void highlevel_host_reset(struct hpsb_host *host);
 
+
+/* these functions are called to handle transactions. They are called, when
+   a packet arrives. The flags argument contains the second word of the first header
+   quadlet of the incoming packet (containing transaction label, retry code,
+   transaction code and priority). These functions either return a response code
+   or a negative number. In the first case a response will be generated; in the 
+   later case, no response will be sent and the driver, that handled the request
+   will send the response itself.
+*/
 int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                   u64 addr, unsigned int length);
+                   u64 addr, unsigned int length, u16 flags);
 int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
-		    quadlet_t *data, u64 addr, unsigned int length);
+		    quadlet_t *data, u64 addr, unsigned int length, u16 flags);
 int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
-                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode);
+                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags);
 int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
-                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode);
+                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
 
 void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
                            unsigned int length);
@@ -130,6 +144,8 @@
 int hpsb_register_addrspace(struct hpsb_highlevel *hl,
                             struct hpsb_address_ops *ops, u64 start, u64 end);
 
+int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, u64 start);
+
 /*
  * Enable or disable receving a certain isochronous channel through the
  * iso_receive op.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/hosts.c linux-2.4.21/drivers/ieee1394/hosts.c
--- linux-2.4.20/drivers/ieee1394/hosts.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/hosts.c	2002-12-18 18:58:07.000000000 +0000
@@ -138,7 +138,7 @@
 
 	atomic_set(&h->generation, 0);
 
-	INIT_TQUEUE(&h->timeout_tq, (void (*)(void*))abort_timedouts, h);
+	HPSB_INIT_WORK(&h->timeout_tq, (void (*)(void*))abort_timedouts, h);
 
         h->topology_map = h->csr.topology_map + 3;
         h->speed_map = (u8 *)(h->csr.speed_map + 2);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/hosts.h linux-2.4.21/drivers/ieee1394/hosts.h
--- linux-2.4.20/drivers/ieee1394/hosts.h	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/hosts.h	2002-12-18 18:58:04.000000000 +0000
@@ -2,13 +2,20 @@
 #define _IEEE1394_HOSTS_H
 
 #include <linux/wait.h>
-#include <linux/tqueue.h>
 #include <linux/list.h>
 #include <asm/semaphore.h>
 
 #include "ieee1394_types.h"
 #include "csr.h"
 
+/* size of the array used to store config rom (in quadlets)
+   maximum is 0x100. About 0x40 is needed for the default
+   entries. So 0x80 should provide enough space for additional
+   directories etc. 
+   Note: All lowlevel drivers are required to allocate at least
+         this amount of memory for the configuration rom!
+*/
+#define CSR_CONFIG_ROM_SIZE       0x100
 
 struct hpsb_packet;
 
@@ -23,7 +30,7 @@
 
         struct list_head pending_packets;
         spinlock_t pending_pkt_lock;
-        struct tq_struct timeout_tq;
+        struct hpsb_queue_struct timeout_tq;
 
         /* A bitmask where a set bit means that this tlabel is in use.
          * FIXME - should be handled per node instead of per bus. */
@@ -119,7 +126,7 @@
          * may not fail.  If any allocation is required, it must be done
          * earlier.
          */
-        size_t (*get_rom) (struct hpsb_host *host, const quadlet_t **pointer);
+        size_t (*get_rom) (struct hpsb_host *host, quadlet_t **pointer);
 
         /* This function shall implement packet transmission based on
          * packet->type.  It shall CRC both parts of the packet (unless
@@ -172,4 +179,24 @@
 void hpsb_add_host(struct hpsb_host *host);
 void hpsb_remove_host(struct hpsb_host *h);
 
+/* updates the configuration rom of a host.
+ * rom_version must be the current version,
+ * otherwise it will fail with return value -1.
+ * Return value -2 indicates that the new
+ * rom version is too big.
+ * Return value 0 indicates success
+ */
+int hpsb_update_config_rom(struct hpsb_host *host,
+      const quadlet_t *new_rom, size_t size, unsigned char rom_version);
+
+/* reads the current version of the configuration rom of a host.
+ * buffersize is the size of the buffer, rom_size
+ * returns the size of the current rom image.
+ * rom_version is the version number of the fetched rom.
+ * return value -1 indicates, that the buffer was
+ * too small, 0 indicates success.
+ */
+int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer,
+      size_t buffersize, size_t *rom_size, unsigned char *rom_version);
+
 #endif /* _IEEE1394_HOSTS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/ieee1394_core.c linux-2.4.21/drivers/ieee1394/ieee1394_core.c
--- linux-2.4.20/drivers/ieee1394/ieee1394_core.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/ieee1394_core.c	2002-12-18 18:58:04.000000000 +0000
@@ -5,9 +5,19 @@
  *               highlevel or lowlevel code
  *
  * Copyright (C) 1999, 2000 Andreas E. Bombe
+ *                     2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
  *
  * This code is licensed under the GPL.  See the file COPYING in the root
  * directory of the kernel sources for details.
+ *
+ *
+ * Contributions:
+ *
+ * Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *        loopback functionality in hpsb_send_packet
+ *        allow highlevel drivers to disable automatic response generation
+ *              and to generate responses themselves (deferred)
+ *
  */
 
 #include <linux/config.h>
@@ -19,7 +29,6 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
-#include <linux/tqueue.h>
 #include <asm/bitops.h>
 #include <asm/byteorder.h>
 #include <asm/semaphore.h>
@@ -72,9 +81,10 @@
 	struct list_head *lh, *next;
 
 	list_for_each_safe(lh, next, &packet->complete_tq) {
-		struct tq_struct *tq = list_entry(lh, struct tq_struct, list);
-		list_del(&tq->list);
-		schedule_task(tq);
+		struct hpsb_queue_struct *tq =
+			list_entry(lh, struct hpsb_queue_struct, hpsb_queue_list);
+		list_del(&tq->hpsb_queue_list);
+		hpsb_schedule_work(tq);
 	}
 
 	return;
@@ -83,11 +93,11 @@
 /**
  * hpsb_add_packet_complete_task - add a new task for when a packet completes
  * @packet: the packet whose completion we want the task added to
- * @tq: the tq_struct describing the task to add
+ * @tq: the hpsb_queue_struct describing the task to add
  */
-void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq)
+void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct hpsb_queue_struct *tq)
 {
-	list_add_tail(&tq->list, &packet->complete_tq);
+	list_add_tail(&tq->hpsb_queue_list, &packet->complete_tq);
 	return;
 }
 
@@ -372,12 +382,19 @@
                 build_speed_map(host, host->node_count);
         }
 
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+        HPSB_INFO("selfid_complete called with successful SelfID stage "
+		"... irm_id: 0x%X node_id: 0x%X",host->irm_id,host->node_id);
+#endif
         /* irm_id is kept up to date by check_selfids() */
         if (host->irm_id == host->node_id) {
                 host->is_irm = 1;
                 host->is_busmgr = 1;
                 host->busmgr_id = host->node_id;
                 host->csr.bus_manager_id = host->node_id;
+        } else {
+                host->is_busmgr = 0;
+                host->is_irm = 0;
         }
 
         host->reset_retries = 0;
@@ -420,7 +437,7 @@
         spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
 
         up(&packet->state_change);
-        schedule_task(&host->timeout_tq);
+        hpsb_schedule_work(&host->timeout_tq);
 }
 
 /**
@@ -448,6 +465,45 @@
 
         packet->state = hpsb_queued;
 
+        if (packet->node_id == host->node_id)
+        { /* it is a local request, so handle it locally */
+                quadlet_t *data;
+                size_t size=packet->data_size+packet->header_size;
+
+                int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
+                data = kmalloc(packet->header_size + packet->data_size, kmflags);
+                if (!data) {
+                        HPSB_ERR("unable to allocate memory for concatenating header and data");
+                        return 0;
+                }
+
+                memcpy(data, packet->header, packet->header_size);
+
+                if (packet->data_size)
+                {
+                        if (packet->data_be) {
+                                memcpy(((u8*)data)+packet->header_size, packet->data, packet->data_size);
+                        } else {
+                                int i;
+                                quadlet_t *my_data=(quadlet_t*) ((u8*) data + packet->data_size);
+                                for (i=0; i < packet->data_size/4; i++) {
+                                        my_data[i] = cpu_to_be32(packet->data[i]);
+                                }
+                        }
+                }
+
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+                dump_packet("send packet local:", packet->header,
+                            packet->header_size);
+#endif
+                hpsb_packet_sent(host, packet,  packet->expect_response?ACK_PENDING:ACK_COMPLETE);
+                hpsb_packet_received(host, data, size, 0);
+
+                kfree(data);
+
+                return 1;
+        }
+
         if (packet->type == hpsb_async && packet->node_id != ALL_NODES) {
                 packet->speed_code =
                         host->speed_map[(host->node_id & NODE_MASK) * 64
@@ -600,8 +656,10 @@
 {
         struct hpsb_packet *packet;
         int length, rcode, extcode;
+        quadlet_t buffer;
         nodeid_t source = data[1] >> 16;
-	nodeid_t dest = data[0] >> 16;
+        nodeid_t dest = data[0] >> 16;
+        u16 flags = (u16) data[0];
         u64 addr;
 
         /* big FIXME - no error checking is done for an out of bounds length */
@@ -610,10 +668,11 @@
         case TCODE_WRITEQ:
                 addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
                 rcode = highlevel_write(host, source, dest, data+3,
-					addr, 4);
+					addr, 4, flags);
 
                 if (!write_acked
-                    && ((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
+                    && (((data[0] >> 16) & NODE_MASK) != NODE_MASK)
+                    && (rcode >= 0)) {
                         /* not a broadcast write, reply */
                         PREP_REPLY_PACKET(0);
                         fill_async_write_resp(packet, rcode);
@@ -624,10 +683,11 @@
         case TCODE_WRITEB:
                 addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
                 rcode = highlevel_write(host, source, dest, data+4,
-					addr, data[3]>>16);
+					addr, data[3]>>16, flags);
 
                 if (!write_acked
-                    && ((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
+                    && (((data[0] >> 16) & NODE_MASK) != NODE_MASK)
+                    && (rcode >= 0)) {
                         /* not a broadcast write, reply */
                         PREP_REPLY_PACKET(0);
                         fill_async_write_resp(packet, rcode);
@@ -636,12 +696,14 @@
                 break;
 
         case TCODE_READQ:
-                PREP_REPLY_PACKET(0);
-
                 addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
-                rcode = highlevel_read(host, source, data, addr, 4);
-                fill_async_readquad_resp(packet, rcode, *data);
-                send_packet_nocare(packet);
+                rcode = highlevel_read(host, source, &buffer, addr, 4, flags);
+
+                if (rcode >= 0) {
+                        PREP_REPLY_PACKET(0);
+                        fill_async_readquad_resp(packet, rcode, buffer);
+                        send_packet_nocare(packet);
+                }
                 break;
 
         case TCODE_READB:
@@ -650,9 +712,12 @@
 
                 addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
                 rcode = highlevel_read(host, source, packet->data, addr,
-                                       length);
-                fill_async_readblock_resp(packet, rcode, length);
-                send_packet_nocare(packet);
+                                       length, flags);
+
+                if (rcode >= 0) {
+                        fill_async_readblock_resp(packet, rcode, length);
+                        send_packet_nocare(packet);
+                }
                 break;
 
         case TCODE_LOCK_REQUEST:
@@ -670,7 +735,7 @@
                 switch (length) {
                 case 4:
                         rcode = highlevel_lock(host, source, packet->data, addr,
-                                               data[4], 0, extcode);
+                                               data[4], 0, extcode,flags);
                         fill_async_lock_resp(packet, rcode, extcode, 4);
                         break;
                 case 8:
@@ -679,13 +744,13 @@
                                 rcode = highlevel_lock(host, source,
                                                        packet->data, addr,
                                                        data[5], data[4], 
-                                                       extcode);
+                                                       extcode, flags);
                                 fill_async_lock_resp(packet, rcode, extcode, 4);
                         } else {
                                 rcode = highlevel_lock64(host, source,
                                              (octlet_t *)packet->data, addr,
                                              *(octlet_t *)(data + 4), 0ULL,
-                                             extcode);
+                                             extcode, flags);
                                 fill_async_lock_resp(packet, rcode, extcode, 8);
                         }
                         break;
@@ -694,15 +759,20 @@
                                                  (octlet_t *)packet->data, addr,
                                                  *(octlet_t *)(data + 6),
                                                  *(octlet_t *)(data + 4), 
-                                                 extcode);
+                                                 extcode, flags);
                         fill_async_lock_resp(packet, rcode, extcode, 8);
                         break;
                 default:
-                        fill_async_lock_resp(packet, RCODE_TYPE_ERROR,
+                        rcode = RCODE_TYPE_ERROR;
+                        fill_async_lock_resp(packet, rcode,
                                              extcode, 0);
                 }
 
-                send_packet_nocare(packet);
+                if (rcode >= 0) {
+                        send_packet_nocare(packet);
+                } else {
+                        free_hpsb_packet(packet);
+                }
                 break;
         }
 
@@ -811,7 +881,7 @@
         }
 
         if (!list_empty(&host->pending_packets))
-		schedule_task(&host->timeout_tq);
+		hpsb_schedule_work(&host->timeout_tq);
 
         spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
 
@@ -1109,6 +1179,7 @@
 EXPORT_SYMBOL(hpsb_make_writeqpacket);
 EXPORT_SYMBOL(hpsb_make_writebpacket);
 EXPORT_SYMBOL(hpsb_make_lockpacket);
+EXPORT_SYMBOL(hpsb_make_lock64packet);
 EXPORT_SYMBOL(hpsb_make_phypacket);
 EXPORT_SYMBOL(hpsb_packet_success);
 EXPORT_SYMBOL(hpsb_make_packet);
@@ -1119,6 +1190,7 @@
 EXPORT_SYMBOL(hpsb_register_highlevel);
 EXPORT_SYMBOL(hpsb_unregister_highlevel);
 EXPORT_SYMBOL(hpsb_register_addrspace);
+EXPORT_SYMBOL(hpsb_unregister_addrspace);
 EXPORT_SYMBOL(hpsb_listen_channel);
 EXPORT_SYMBOL(hpsb_unlisten_channel);
 EXPORT_SYMBOL(highlevel_read);
@@ -1135,6 +1207,8 @@
 EXPORT_SYMBOL(hpsb_node_read);
 EXPORT_SYMBOL(hpsb_node_write);
 EXPORT_SYMBOL(hpsb_node_lock);
+EXPORT_SYMBOL(hpsb_update_config_rom);
+EXPORT_SYMBOL(hpsb_get_config_rom);
 EXPORT_SYMBOL(hpsb_register_protocol);
 EXPORT_SYMBOL(hpsb_unregister_protocol);
 EXPORT_SYMBOL(hpsb_release_unit_directory);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/ieee1394_core.h linux-2.4.21/drivers/ieee1394/ieee1394_core.h
--- linux-2.4.20/drivers/ieee1394/ieee1394_core.h	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/ieee1394_core.h	2002-12-18 18:58:04.000000000 +0000
@@ -2,7 +2,6 @@
 #ifndef _IEEE1394_CORE_H
 #define _IEEE1394_CORE_H
 
-#include <linux/tqueue.h>
 #include <linux/slab.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/proc_fs.h>
@@ -78,7 +77,7 @@
 };
 
 /* add a new task for when a packet completes */
-void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq);
+void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct hpsb_queue_struct *tq);
 
 static inline struct hpsb_packet *driver_packet(struct list_head *l)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/ieee1394_transactions.c linux-2.4.21/drivers/ieee1394/ieee1394_transactions.c
--- linux-2.4.20/drivers/ieee1394/ieee1394_transactions.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/ieee1394_transactions.c	2002-12-18 18:58:06.000000000 +0000
@@ -297,14 +297,6 @@
         HPSB_PANIC("reached unreachable code 2 in %s", __FUNCTION__);
 }
 
-
-int hpsb_read_trylocal(struct hpsb_host *host, nodeid_t node, u64 addr, 
-                       quadlet_t *buffer, size_t length)
-{
-        if (host->node_id != node) return -1;
-        return highlevel_read(host, node, buffer, addr, length);
-}
-
 struct hpsb_packet *hpsb_make_readqpacket(struct hpsb_host *host, nodeid_t node,
                                           u64 addr)
 {
@@ -400,6 +392,31 @@
         return p;
 }
 
+struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node,
+                                           u64 addr, int extcode)
+{
+        struct hpsb_packet *p;
+
+        p = alloc_hpsb_packet(16);
+        if (!p) return NULL;
+
+        p->host = host;
+        p->tlabel = get_tlabel(host, node, 1);
+        p->node_id = node;
+
+        switch (extcode) {
+        case EXTCODE_FETCH_ADD:
+        case EXTCODE_LITTLE_ADD:
+                fill_async_lock(p, addr, extcode, 8);
+                break;
+        default:
+                fill_async_lock(p, addr, extcode, 16);
+                break;
+        }
+
+        return p;
+}
+
 struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host,
                                         quadlet_t data) 
 {
@@ -429,18 +446,6 @@
                 return -EINVAL;
         }
 
-        if (host->node_id == node) {
-                switch(highlevel_read(host, node, buffer, addr, length)) {
-                case RCODE_COMPLETE:
-                        return 0;
-                case RCODE_TYPE_ERROR:
-                        return -EACCES;
-                case RCODE_ADDRESS_ERROR:
-                default:
-                        return -EINVAL;
-                }
-        }
-
         if (length == 4) {
                 packet = hpsb_make_readqpacket(host, node, addr);
         } else {
@@ -509,18 +514,6 @@
 	if (length == 0)
 		return -EINVAL;
 
-	if (host->node_id == node) {
-		switch(highlevel_write(host, node, node, buffer, addr, length)) {
-		case RCODE_COMPLETE:
-			return 0;
-		case RCODE_TYPE_ERROR:
-			return -EACCES;
-		case RCODE_ADDRESS_ERROR:
-		default:
-			return -EINVAL;
-		}
-	}
-
 	packet = hpsb_make_packet (host, node, addr, buffer, length);
 
 	if (!packet)
@@ -551,19 +544,6 @@
         struct hpsb_packet *packet;
         int retval = 0, length;
         
-        if (host->node_id == node) {
-                switch(highlevel_lock(host, node, data, addr, *data, arg,
-                                      extcode)) {
-                case RCODE_COMPLETE:
-                        return 0;
-                case RCODE_TYPE_ERROR:
-                        return -EACCES;
-                case RCODE_ADDRESS_ERROR:
-                default:
-                        return -EINVAL;
-                }
-        }
-
         packet = alloc_hpsb_packet(8);
         if (!packet) {
                 return -ENOMEM;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/ieee1394_transactions.h linux-2.4.21/drivers/ieee1394/ieee1394_transactions.h
--- linux-2.4.20/drivers/ieee1394/ieee1394_transactions.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/ieee1394_transactions.h	2002-12-18 18:58:06.000000000 +0000
@@ -42,6 +42,8 @@
                                            size_t length);
 struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
                                          u64 addr, int extcode);
+struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node,
+                                          u64 addr, int extcode);
 struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host,
                                         quadlet_t data) ;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/ieee1394_types.h linux-2.4.21/drivers/ieee1394/ieee1394_types.h
--- linux-2.4.20/drivers/ieee1394/ieee1394_types.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/ieee1394_types.h	2002-12-18 18:58:10.000000000 +0000
@@ -20,23 +20,6 @@
 #define __devexit_p(x) x
 #endif
 
-/* This showed up around this time */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,12)
-
-# ifndef MODULE_LICENSE
-# define MODULE_LICENSE(x)
-# endif
-
-# ifndef min
-# define min(x,y) ({ \
-	const typeof(x) _x = (x);       \
-	const typeof(y) _y = (y);       \
-	(void) (&_x == &_y);            \
-	_x < _y ? _x : _y; })
-# endif
-
-#endif /* Linux version < 2.4.12 */
-
 #include <linux/spinlock.h>
 
 #ifndef list_for_each_safe
@@ -46,9 +29,7 @@
 
 #endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5)
 #define pte_offset_kernel pte_offset
-#endif
 
 #ifndef MIN
 #define MIN(a,b) ((a) < (b) ? (a) : (b))
@@ -58,10 +39,24 @@
 #define MAX(a,b) ((a) > (b) ? (a) : (b))
 #endif
 
+
+/* Use task queue */
+#include <linux/tqueue.h>
+#define hpsb_queue_struct tq_struct
+#define hpsb_queue_list list
+#define hpsb_schedule_work(x) schedule_task(x)
+#define HPSB_INIT_WORK(x,y,z) INIT_TQUEUE(x,y,z)
+#define HPSB_PREPARE_WORK(x,y,z) PREPARE_TQUEUE(x,y,z)
+
+
 typedef u32 quadlet_t;
 typedef u64 octlet_t;
 typedef u16 nodeid_t;
 
+typedef u8  byte_t;
+typedef u64 nodeaddr_t;
+typedef u16 arm_length_t;
+
 #define BUS_MASK  0xffc0
 #define NODE_MASK 0x003f
 #define LOCAL_BUS 0xffc0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/ohci1394.c linux-2.4.21/drivers/ieee1394/ohci1394.c
--- linux-2.4.20/drivers/ieee1394/ohci1394.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/ohci1394.c	2002-12-18 18:58:06.000000000 +0000
@@ -91,7 +91,6 @@
 #include <asm/byteorder.h>
 #include <asm/atomic.h>
 #include <asm/uaccess.h>
-#include <linux/tqueue.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 
@@ -154,7 +153,7 @@
 printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
 
 static char version[] __devinitdata =
-	"$Rev: 578 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 693 $ Ben Collins <bcollins@debian.org>";
 
 /* Module Parameters */
 MODULE_PARM(attempt_root,"i");
@@ -1174,74 +1173,60 @@
 	}
 	if (event & OHCI1394_selfIDComplete) {
 		if (host->in_bus_reset) {
-			node_id = reg_read(ohci, OHCI1394_NodeID); 
+			node_id = reg_read(ohci, OHCI1394_NodeID);
 
-			/* If our nodeid is not valid, give a msec delay
-			 * to let it settle in and try again.  */
 			if (!(node_id & 0x80000000)) {
-				mdelay(1);
-				node_id = reg_read(ohci, OHCI1394_NodeID);
+				PRINT(KERN_ERR, ohci->id,
+				      "SelfID received, but NodeID invalid "
+				      "(probably new bus reset occured): %08X",
+				      node_id);
+				goto selfid_not_valid;
 			}
 
-			if (node_id & 0x80000000) { /* NodeID valid */
-				phyid =  node_id & 0x0000003f;
-				isroot = (node_id & 0x40000000) != 0;
-
-				DBGMSG(ohci->id,
-				      "SelfID interrupt received "
-				      "(phyid %d, %s)", phyid, 
-				      (isroot ? "root" : "not root"));
+			phyid =  node_id & 0x0000003f;
+			isroot = (node_id & 0x40000000) != 0;
+
+			DBGMSG(ohci->id,
+			       "SelfID interrupt received "
+			       "(phyid %d, %s)", phyid,
+			       (isroot ? "root" : "not root"));
+
+			handle_selfid(ohci, host, phyid, isroot);
+
+			/* Clear the bus reset event and re-enable the
+			 * busReset interrupt.  */
+			spin_lock_irqsave(&ohci->event_lock, flags);
+			reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
+			reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
+			spin_unlock_irqrestore(&ohci->event_lock, flags);
+
+			/* Accept Physical requests from all nodes. */
+			reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0xffffffff);
+			reg_write(ohci,OHCI1394_AsReqFilterLoSet, 0xffffffff);
 
-				handle_selfid(ohci, host, 
-					      phyid, isroot);
+			/* Turn on phys dma reception.
+			 *
+			 * TODO: Enable some sort of filtering management.
+			 */
+			if (phys_dma) {
+				reg_write(ohci,OHCI1394_PhyReqFilterHiSet, 0xffffffff);
+				reg_write(ohci,OHCI1394_PhyReqFilterLoSet, 0xffffffff);
+				reg_write(ohci,OHCI1394_PhyUpperBound, 0xffff0000);
 			} else {
-				PRINT(KERN_ERR, ohci->id, 
-				      "SelfID interrupt received, but "
-				      "NodeID is not valid: %08X",
-				      node_id);
+				reg_write(ohci,OHCI1394_PhyReqFilterHiSet, 0x00000000);
+				reg_write(ohci,OHCI1394_PhyReqFilterLoSet, 0x00000000);
 			}
+			DBGMSG(ohci->id, "PhyReqFilter=%08x%08x\n",
+			       reg_read(ohci,OHCI1394_PhyReqFilterHiSet),
+			       reg_read(ohci,OHCI1394_PhyReqFilterLoSet));
 
-			/* Accept Physical requests from all nodes. */
-			reg_write(ohci,OHCI1394_AsReqFilterHiSet, 
-				  0xffffffff);
-			reg_write(ohci,OHCI1394_AsReqFilterLoSet, 
-				  0xffffffff);
+			hpsb_selfid_complete(host, phyid, isroot);
 		} else
-			PRINT(KERN_ERR, ohci->id, 
+			PRINT(KERN_ERR, ohci->id,
 			      "SelfID received outside of bus reset sequence");
 
-		/* Finally, we clear the busReset event and reenable
-		 * the busReset interrupt. */
-		spin_lock_irqsave(&ohci->event_lock, flags);
-		reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
-		reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); 
-		spin_unlock_irqrestore(&ohci->event_lock, flags);
-		event &= ~OHCI1394_selfIDComplete;	
-
-		/* Turn on phys dma reception. We should
-		 * probably manage the filtering somehow, 
-		 * instead of blindly turning it on.  */
-
-		/*
-		 * CAUTION!
-		 * Some chips (TI TSB43AB22) won't take a value in
-		 * the PhyReqFilter register until after the IntEvent
-		 * is cleared for bus reset, and even then a short
-		 * delay is required.
-		 */
-		if (phys_dma) {
-			mdelay(1);
-			reg_write(ohci,OHCI1394_PhyReqFilterHiSet,
-				  0xffffffff);
-			reg_write(ohci,OHCI1394_PhyReqFilterLoSet,
-				  0xffffffff);
-			reg_write(ohci,OHCI1394_PhyUpperBound,
-				  0xffff0000);
-		}
-
-		DBGMSG(ohci->id, "PhyReqFilter=%08x%08x\n",
-		       reg_read(ohci,OHCI1394_PhyReqFilterHiSet),
-		       reg_read(ohci,OHCI1394_PhyReqFilterLoSet));
+		event &= ~OHCI1394_selfIDComplete;
+selfid_not_valid:
 	}
 
 	/* Make sure we handle everything, just in case we accidentally
@@ -1905,7 +1890,7 @@
 	ohci->csr_config_rom_length = cr.data - ohci->csr_config_rom_cpu;
 }
 
-static size_t ohci_get_rom(struct hpsb_host *host, const quadlet_t **ptr)
+static size_t ohci_get_rom(struct hpsb_host *host, quadlet_t **ptr)
 {
 	struct ti_ohci *ohci=host->hostdata;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/pcilynx.c linux-2.4.21/drivers/ieee1394/pcilynx.c
--- linux-2.4.20/drivers/ieee1394/pcilynx.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/pcilynx.c	2002-12-18 18:58:06.000000000 +0000
@@ -1677,7 +1677,7 @@
 
 
 
-static size_t get_lynx_rom(struct hpsb_host *host, const quadlet_t **ptr)
+static size_t get_lynx_rom(struct hpsb_host *host, quadlet_t **ptr)
 {
         struct ti_lynx *lynx = host->hostdata;
         *ptr = lynx->config_rom;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/raw1394.c linux-2.4.21/drivers/ieee1394/raw1394.c
--- linux-2.4.20/drivers/ieee1394/raw1394.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/raw1394.c	2002-12-18 18:58:01.000000000 +0000
@@ -4,9 +4,27 @@
  * Raw interface to the bus
  *
  * Copyright (C) 1999, 2000 Andreas E. Bombe
+ *               2001, 2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *                     2002 Christian Toegel <christian.toegel@gmx.at>
  *
  * This code is licensed under the GPL.  See the file COPYING in the root
  * directory of the kernel sources for details.
+ *
+ *
+ * Contributions:
+ *
+ * Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *        configuration ROM manipulation
+ *        address range mapping
+ *        adaptation for new (transparent) loopback mechanism
+ *        sending of arbitrary async packets
+ * Christian Toegel <christian.toegel@gmx.at>
+ *        address range mapping
+ *        lock64 request
+ *        transmit physical packet
+ *        busreset notification control (switch on/off)
+ *        busreset with selection of type (short/long)
+ *        request_reply
  */
 
 #include <linux/kernel.h>
@@ -40,6 +58,16 @@
 #define ptr2int(x) ((u64)(u32)x)
 #endif
 
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+#define RAW1394_DEBUG
+#endif
+
+#ifdef RAW1394_DEBUG
+#define DBGMSG(fmt, args...) \
+printk(KERN_INFO "raw1394:" fmt "\n" , ## args)
+#else
+#define DBGMSG(fmt, args...)
+#endif
 
 static devfs_handle_t devfs_handle;
 
@@ -53,6 +81,21 @@
 static atomic_t iso_buffer_size;
 static const int iso_buffer_max = 4 * 1024 * 1024; /* 4 MB */
 
+static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+             u64 addr, unsigned int length, u16 flags);
+static int arm_write (struct hpsb_host *host, int nodeid, int destid,
+              quadlet_t *data, u64 addr, unsigned int length, u16 flags);
+static int arm_lock (struct hpsb_host *host, int nodeid, quadlet_t *store,
+             u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags);
+static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store,
+               u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
+static struct hpsb_address_ops arm_ops = {
+        read:     arm_read,
+        write:    arm_write,
+        lock:     arm_lock,
+        lock64:   arm_lock64,
+};
+
 static void queue_complete_cb(struct pending_request *req);
 
 static struct pending_request *__alloc_pending_request(int flags)
@@ -64,7 +107,7 @@
         if (req != NULL) {
                 memset(req, 0, sizeof(struct pending_request));
                 INIT_LIST_HEAD(&req->list);
-		INIT_TQUEUE(&req->tq, (void(*)(void*))queue_complete_cb, NULL);
+                HPSB_INIT_WORK(&req->tq, (void(*)(void*))queue_complete_cb, NULL);
         }
 
         return req;
@@ -128,7 +171,11 @@
                 req->req.length = 0;
         }
 
-        free_tlabel(packet->host, packet->node_id, packet->tlabel);
+	if ((req->req.type == RAW1394_REQ_ASYNC_READ) ||
+	    (req->req.type == RAW1394_REQ_ASYNC_WRITE) ||
+	    (req->req.type == RAW1394_REQ_LOCK) ||
+	    (req->req.type == RAW1394_REQ_LOCK64))
+                free_tlabel(packet->host, packet->node_id, packet->tlabel);
 
         queue_complete_req(req);
 }
@@ -137,6 +184,7 @@
 static void add_host(struct hpsb_host *host)
 {
         struct host_info *hi;
+        unsigned long flags;
 
         hi = (struct host_info *)kmalloc(sizeof(struct host_info), SLAB_KERNEL);
         if (hi != NULL) {
@@ -144,10 +192,10 @@
                 hi->host = host;
                 INIT_LIST_HEAD(&hi->file_info_list);
 
-                spin_lock_irq(&host_info_lock);
+                spin_lock_irqsave(&host_info_lock, flags);
                 list_add_tail(&hi->list, &host_info_list);
                 host_count++;
-                spin_unlock_irq(&host_info_lock);
+                spin_unlock_irqrestore(&host_info_lock, flags);
         }
 
         atomic_inc(&internal_generation);
@@ -172,15 +220,22 @@
 static void remove_host(struct hpsb_host *host)
 {
         struct host_info *hi;
+        unsigned long flags;
 
-        spin_lock_irq(&host_info_lock);
+        spin_lock_irqsave(&host_info_lock, flags);
         hi = find_host_info(host);
 
         if (hi != NULL) {
                 list_del(&hi->list);
                 host_count--;
+                /* 
+                   FIXME: adressranges should be removed 
+                   and fileinfo states should be initialized
+                   (including setting generation to 
+                   internal-generation ...)
+                */
         }
-        spin_unlock_irq(&host_info_lock);
+        spin_unlock_irqrestore(&host_info_lock, flags);
 
         if (hi == NULL) {
                 printk(KERN_ERR "raw1394: attempt to remove unknown host "
@@ -207,20 +262,22 @@
         if (hi != NULL) {
                 list_for_each(lh, &hi->file_info_list) {
                         fi = list_entry(lh, struct file_info, list);
-                        req = __alloc_pending_request(SLAB_ATOMIC);
+                        if (fi->notification == RAW1394_NOTIFY_ON) {
+                                req = __alloc_pending_request(SLAB_ATOMIC);
 
-                        if (req != NULL) {
-                                req->file_info = fi;
-                                req->req.type = RAW1394_REQ_BUS_RESET;
-                                req->req.generation = get_hpsb_generation(host);
-                                req->req.misc = (host->node_id << 16)
-                                        | host->node_count;
-                                if (fi->protocol_version > 3) {
-                                        req->req.misc |= ((host->irm_id
-                                                           & NODE_MASK) << 8);
-                                }
+                                if (req != NULL) {
+                                        req->file_info = fi;
+                                        req->req.type = RAW1394_REQ_BUS_RESET;
+                                        req->req.generation = get_hpsb_generation(host);
+                                        req->req.misc = (host->node_id << 16)
+                                                | host->node_count;
+                                        if (fi->protocol_version > 3) {
+                                                req->req.misc |= ((host->irm_id
+                                                                   & NODE_MASK) << 8);
+                                        }
 
-                                queue_complete_req(req);
+                                        queue_complete_req(req);
+                                }
                         }
                 }
         }
@@ -529,7 +586,7 @@
 {
         int channel = req->req.misc;
 
-        spin_lock(&host_info_lock);
+        spin_lock_irq(&host_info_lock);
         if ((channel > 63) || (channel < -64)) {
                 req->req.error = RAW1394_ERROR_INVALID_ARG;
         } else if (channel >= 0) {
@@ -556,7 +613,7 @@
 
         req->req.length = 0;
         queue_complete_req(req);
-        spin_unlock(&host_info_lock);
+        spin_unlock_irq(&host_info_lock);
 }
 
 static void handle_fcp_listen(struct file_info *fi, struct pending_request *req)
@@ -579,84 +636,9 @@
         queue_complete_req(req);
 }
 
-static int handle_local_request(struct file_info *fi,
-                                struct pending_request *req, int node)
-{
-        u64 addr = req->req.address & 0xffffffffffffULL;
-
-        req->data = kmalloc(req->req.length, SLAB_KERNEL);
-        if (!req->data) return -ENOMEM;
-        req->free_data = 1;
-
-        switch (req->req.type) {
-        case RAW1394_REQ_ASYNC_READ:
-                req->req.error = highlevel_read(fi->host, node, req->data, addr,
-                                                req->req.length);
-                break;
-
-        case RAW1394_REQ_ASYNC_WRITE:
-                if (copy_from_user(req->data, int2ptr(req->req.sendb),
-                                   req->req.length)) {
-                        req->req.error = RAW1394_ERROR_MEMFAULT;
-                        break;
-                }
-
-                req->req.error = highlevel_write(fi->host, node, node, req->data,
-                                                 addr, req->req.length);
-                req->req.length = 0;
-                break;
 
-        case RAW1394_REQ_LOCK:
-                if ((req->req.misc == EXTCODE_FETCH_ADD)
-                    || (req->req.misc == EXTCODE_LITTLE_ADD)) {
-                        if (req->req.length != 4) {
-                                req->req.error = RAW1394_ERROR_INVALID_ARG;
-                                break;
-                        }
-                } else {
-                        if (req->req.length != 8) {
-                                req->req.error = RAW1394_ERROR_INVALID_ARG;
-                                break;
-                        }
-                }
-
-                if (copy_from_user(req->data, int2ptr(req->req.sendb),
-                                   req->req.length)) {
-                        req->req.error = RAW1394_ERROR_MEMFAULT;
-                        break;
-                }
-
-                if (req->req.length == 8) {
-                        req->req.error = highlevel_lock(fi->host, node,
-                                                        req->data, addr,
-                                                        req->data[1],
-                                                        req->data[0],
-                                                        req->req.misc);
-                        req->req.length = 4;
-                } else {
-                        req->req.error = highlevel_lock(fi->host, node,
-                                                        req->data, addr,
-                                                        req->data[0], 0,
-                                                        req->req.misc);
-                }
-                break;
-
-        case RAW1394_REQ_LOCK64:
-        default:
-                req->req.error = RAW1394_ERROR_STATE_ORDER;
-        }
-
-        if (req->req.error)
-                req->req.length = 0;
-        if (req->req.error >= 0)
-                req->req.error |= ACK_PENDING << 16;
-
-        queue_complete_req(req);
-        return sizeof(struct raw1394_request);
-}
-
-static int handle_remote_request(struct file_info *fi,
-                                 struct pending_request *req, int node)
+static int handle_async_request(struct file_info *fi,
+                                struct pending_request *req, int node)
 {
         struct hpsb_packet *packet = NULL;
         u64 addr = req->req.address & 0xffffffffffffULL;
@@ -664,11 +646,13 @@
         switch (req->req.type) {
         case RAW1394_REQ_ASYNC_READ:
                 if (req->req.length == 4) {
+                        DBGMSG("quadlet_read_request called");        
                         packet = hpsb_make_readqpacket(fi->host, node, addr);
                         if (!packet) return -ENOMEM;
 
                         req->data = &packet->header[3];
                 } else {
+                        DBGMSG("block_read_request called");
                         packet = hpsb_make_readbpacket(fi->host, node, addr,
                                                        req->req.length);
                         if (!packet) return -ENOMEM;
@@ -681,6 +665,7 @@
                 if (req->req.length == 4) {
                         quadlet_t x;
 
+                        DBGMSG("quadlet_write_request called");
                         if (copy_from_user(&x, int2ptr(req->req.sendb), 4)) {
                                 req->req.error = RAW1394_ERROR_MEMFAULT;
                         }
@@ -689,6 +674,7 @@
                                                         x);
                         if (!packet) return -ENOMEM;
                 } else {
+                        DBGMSG("block_write_request called");
                         packet = hpsb_make_writebpacket(fi->host, node, addr,
                                                         req->req.length);
                         if (!packet) return -ENOMEM;
@@ -702,6 +688,7 @@
                 break;
 
         case RAW1394_REQ_LOCK:
+                DBGMSG("lock_request called");
                 if ((req->req.misc == EXTCODE_FETCH_ADD)
                     || (req->req.misc == EXTCODE_LITTLE_ADD)) {
                         if (req->req.length != 4) {
@@ -730,6 +717,33 @@
                 break;
 
         case RAW1394_REQ_LOCK64:
+                DBGMSG("lock64_request called");
+                if ((req->req.misc == EXTCODE_FETCH_ADD)
+                    || (req->req.misc == EXTCODE_LITTLE_ADD)) {
+                        if (req->req.length != 8) {
+                                req->req.error = RAW1394_ERROR_INVALID_ARG;
+                                break;
+                        }
+                } else {
+                        if (req->req.length != 16) {
+                                req->req.error = RAW1394_ERROR_INVALID_ARG;
+                                break;
+                        }
+                }
+                packet = hpsb_make_lock64packet(fi->host, node, addr,
+                                                req->req.misc);
+                if (!packet) return -ENOMEM;
+
+                if (copy_from_user(packet->data, int2ptr(req->req.sendb),
+                                   req->req.length)) {
+                        req->req.error = RAW1394_ERROR_MEMFAULT;
+                        break;
+                }
+
+                req->data = packet->data;
+                req->req.length = 8;
+                break;
+
         default:
                 req->req.error = RAW1394_ERROR_STATE_ORDER;
         }
@@ -783,8 +797,7 @@
                 return sizeof(struct raw1394_request);
         }
 
-        req->tq.data = req;
-        req->tq.routine = (void (*)(void*))queue_complete_req;
+	HPSB_PREPARE_WORK(&req->tq, (void (*)(void*))queue_complete_req, req);
         req->req.length = 0;
 	hpsb_add_packet_complete_task(packet, &req->tq);
 
@@ -803,25 +816,1092 @@
         return sizeof(struct raw1394_request);
 }
 
-static int state_connected(struct file_info *fi, struct pending_request *req)
+static int handle_async_send(struct file_info *fi, struct pending_request *req)
 {
-        int node = req->req.address >> 48;
+        struct hpsb_packet *packet;
+        int header_length = req->req.misc & 0xffff;
+        int expect_response = req->req.misc >> 16;
 
-        req->req.error = RAW1394_ERROR_NONE;
+        if ((header_length > req->req.length) ||
+            (header_length  < 12))
+        {
+                req->req.error = RAW1394_ERROR_INVALID_ARG;
+                req->req.length = 0;
+                queue_complete_req(req);
+                return sizeof(struct raw1394_request);
+        } 
 
-        if (req->req.type ==  RAW1394_REQ_ISO_SEND) {
-                return handle_iso_send(fi, req, node);
+        packet = alloc_hpsb_packet(req->req.length-header_length);
+        req->packet = packet;
+        if (!packet) return -ENOMEM;
+
+        if (copy_from_user(packet->header, int2ptr(req->req.sendb),
+                           header_length)) {
+                req->req.error = RAW1394_ERROR_MEMFAULT;
+                req->req.length = 0;
+                queue_complete_req(req);
+                return sizeof(struct raw1394_request);
         }
 
-        if (req->req.generation != get_hpsb_generation(fi->host)) {
-                req->req.error = RAW1394_ERROR_GENERATION;
-                req->req.generation = get_hpsb_generation(fi->host);
+        if (copy_from_user(packet->data, ((u8*) int2ptr(req->req.sendb)) + header_length,
+                           packet->data_size)) {
+                req->req.error = RAW1394_ERROR_MEMFAULT;
                 req->req.length = 0;
                 queue_complete_req(req);
                 return sizeof(struct raw1394_request);
         }
 
+        packet->type = hpsb_async;
+        packet->node_id = packet->header[0] >> 16;
+        packet->tcode = (packet->header[0] >> 4) & 0xf;
+        packet->tlabel = (packet->header[0] >> 10) &0x3f;
+        packet->host = fi->host;
+        packet->expect_response = expect_response;
+        packet->header_size=header_length;
+        packet->data_size=req->req.length-header_length;
+
+	HPSB_PREPARE_WORK(&req->tq, (void (*)(void*))queue_complete_req, req);
+        req->req.length = 0;
+        hpsb_add_packet_complete_task(packet, &req->tq);
+
+        spin_lock_irq(&fi->reqlists_lock);
+        list_add_tail(&req->list, &fi->req_pending);
+        spin_unlock_irq(&fi->reqlists_lock);
+
+        /* Update the generation of the packet just before sending. */
+        packet->generation = get_hpsb_generation(fi->host);
+
+        if (!hpsb_send_packet(packet)) {
+                req->req.error = RAW1394_ERROR_SEND_ERROR;
+                queue_complete_req(req);
+        }
+
+        return sizeof(struct raw1394_request);
+}
+
+static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+             u64 addr, unsigned int length, u16 flags)
+{
+        struct pending_request *req;
+        struct list_head *lh;
+        struct host_info *hi;
+        struct file_info *fi = NULL;
+        struct list_head *entry;
+        struct arm_addr  *arm_addr = NULL;
+        struct arm_request  *arm_req = NULL;
+        struct arm_response *arm_resp = NULL;
+        int found=0, size=0, rcode=-1;
+        struct arm_request_response *arm_req_resp = NULL;
+
+        DBGMSG("arm_read  called by node: %X"
+              "addr: %4.4x %8.8x length: %u", nodeid,
+              (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
+              length);
+        spin_lock(&host_info_lock);
+        hi = find_host_info(host); /* search address-entry */
+        if (hi != NULL) {
+                list_for_each(lh, &hi->file_info_list) {
+                        fi = list_entry(lh, struct file_info, list);
+                        entry = fi->addr_list.next;
+                        while (entry != &(fi->addr_list)) {
+                                arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                                if (((arm_addr->start) <= (addr)) && 
+                                        ((arm_addr->end) >= (addr+length))) {
+                                        found = 1;
+                                        break;
+                                }
+                                entry = entry->next;
+                        }
+                        if (found) {
+                                break;
+                        }
+                }
+        }
+        rcode = -1;
+        if (!found) {
+                printk(KERN_ERR "raw1394: arm_read FAILED addr_entry not found"
+                " -> rcode_address_error\n");
+                spin_unlock(&host_info_lock);
+                return (RCODE_ADDRESS_ERROR);
+        } else {
+                DBGMSG("arm_read addr_entry FOUND");
+        }
+        if (arm_addr->rec_length < length) {
+                DBGMSG("arm_read blocklength too big -> rcode_data_error");
+                rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */
+        }
+        if (rcode == -1) {
+                if (arm_addr->access_rights & ARM_READ) {
+                        if (!(arm_addr->client_transactions & ARM_READ)) {
+                                memcpy(buffer,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), 
+                                       length);
+                                DBGMSG("arm_read -> (rcode_complete)");
+                                rcode = RCODE_COMPLETE;
+                        }
+                } else {
+                        rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                        DBGMSG("arm_read -> rcode_type_error (access denied)");
+                }
+        }
+        if (arm_addr->notification_options & ARM_READ) {
+                DBGMSG("arm_read -> entering notification-section");
+                req = __alloc_pending_request(SLAB_ATOMIC);
+                if (!req) {
+                        DBGMSG("arm_read -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                if (rcode == RCODE_COMPLETE) {
+                        size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
+                                length * sizeof(byte_t) +
+                                sizeof (struct arm_request_response);
+                } else {
+                        size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
+                                sizeof (struct arm_request_response);
+                }
+                req->data = kmalloc(size, SLAB_ATOMIC);
+                if (!(req->data)) {
+                        free_pending_request(req);
+                        DBGMSG("arm_read -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                req->free_data=1;
+                req->file_info = fi;
+                req->req.type = RAW1394_REQ_ARM;
+                req->req.generation = get_hpsb_generation(host);
+                req->req.misc = ( ((length << 16) & (0xFFFF0000)) | (ARM_READ & 0xFF));
+                req->req.tag  = arm_addr->arm_tag;
+                req->req.recvb = arm_addr->recvb;
+                req->req.length = size;
+                arm_req_resp = (struct arm_request_response *) (req->data);
+                arm_req  = (struct arm_request *) ((byte_t *)(req->data) + 
+                        (sizeof (struct arm_request_response)));
+                arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + 
+                        (sizeof(struct arm_request)));
+                arm_req->buffer  = NULL;
+                arm_resp->buffer = NULL;
+                if (rcode == RCODE_COMPLETE) {
+                        arm_resp->buffer = ((byte_t *)(arm_resp) + 
+                                (sizeof(struct arm_response)));
+                        memcpy (arm_resp->buffer,
+                                (arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), 
+                                length);
+                        arm_resp->buffer = int2ptr((arm_addr->recvb) + 
+                                sizeof (struct arm_request_response) +
+                                sizeof (struct arm_request) +
+                                sizeof (struct arm_response));
+                }
+                arm_resp->buffer_length = (rcode == RCODE_COMPLETE) ? length : 0;
+                arm_resp->response_code = rcode;
+                arm_req->buffer_length = 0;
+                arm_req->generation = req->req.generation;
+                arm_req->extended_transaction_code = 0;
+                arm_req->destination_offset = addr;
+                arm_req->source_nodeid = nodeid;
+                arm_req->destination_nodeid = host->node_id;
+                arm_req->tlabel = (flags >> 10) & 0x3f;
+                arm_req->tcode = (flags >> 4) & 0x0f;
+                arm_req_resp->request  = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response));
+                arm_req_resp->response = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request));
+                queue_complete_req(req);
+        }
+        spin_unlock(&host_info_lock);
+        return(rcode);
+}
+
+static int arm_write (struct hpsb_host *host, int nodeid, int destid,
+              quadlet_t *data, u64 addr, unsigned int length, u16 flags)
+{
+        struct pending_request *req;
+        struct list_head *lh;
+        struct host_info *hi;
+        struct file_info *fi = NULL;
+        struct list_head *entry;
+        struct arm_addr  *arm_addr = NULL;
+        struct arm_request  *arm_req = NULL;
+        struct arm_response *arm_resp = NULL;        
+        int found=0, size=0, rcode=-1, length_conflict=0;
+        struct arm_request_response *arm_req_resp = NULL;
+
+        DBGMSG("arm_write called by node: %X"
+              "addr: %4.4x %8.8x length: %u", nodeid,
+              (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
+              length);
+        spin_lock(&host_info_lock);
+        hi = find_host_info(host); /* search address-entry */
+        if (hi != NULL) {
+                list_for_each(lh, &hi->file_info_list) {
+                        fi = list_entry(lh, struct file_info, list);
+                        entry = fi->addr_list.next;
+                        while (entry != &(fi->addr_list)) {
+                                arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                                if (((arm_addr->start) <= (addr)) && 
+                                        ((arm_addr->end) >= (addr+length))) {
+                                        found = 1;
+                                        break;
+                                }
+                                entry = entry->next;
+                        }
+                        if (found) {
+                                break;
+                        }
+                }
+        }
+        rcode = -1;
+        if (!found) {
+                printk(KERN_ERR "raw1394: arm_write FAILED addr_entry not found"
+                " -> rcode_address_error\n");
+                spin_unlock(&host_info_lock);
+                return (RCODE_ADDRESS_ERROR);
+        } else {
+                DBGMSG("arm_write addr_entry FOUND");
+        }
+        if (arm_addr->rec_length < length) {
+                DBGMSG("arm_write blocklength too big -> rcode_data_error");
+                length_conflict = 1;
+                rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */
+        }
+        if (rcode == -1) {
+                if (arm_addr->access_rights & ARM_WRITE) {
+                        if (!(arm_addr->client_transactions & ARM_WRITE)) {
+                                memcpy((arm_addr->addr_space_buffer)+(addr-(arm_addr->start)),
+                                        data, length);
+                                DBGMSG("arm_write -> (rcode_complete)");
+                                rcode = RCODE_COMPLETE;
+                        }
+                } else {
+                        rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                        DBGMSG("arm_write -> rcode_type_error (access denied)");
+                }
+        }
+        if (arm_addr->notification_options & ARM_WRITE) {
+                DBGMSG("arm_write -> entering notification-section");
+                req = __alloc_pending_request(SLAB_ATOMIC);
+                if (!req) {
+                        DBGMSG("arm_write -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request my be retried */
+                }
+                size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
+                        (length) * sizeof(byte_t) +
+                        sizeof (struct arm_request_response);
+                req->data = kmalloc(size, SLAB_ATOMIC);
+                if (!(req->data)) {
+                        free_pending_request(req);
+                        DBGMSG("arm_write -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                req->free_data=1;
+                req->file_info = fi;
+                req->req.type = RAW1394_REQ_ARM;
+                req->req.generation = get_hpsb_generation(host);
+                req->req.misc = ( ((length << 16) & (0xFFFF0000)) | (ARM_WRITE & 0xFF));
+                req->req.tag  = arm_addr->arm_tag;
+                req->req.recvb = arm_addr->recvb;
+                req->req.length = size;
+                arm_req_resp = (struct arm_request_response *) (req->data);
+                arm_req  = (struct arm_request *) ((byte_t *)(req->data) + 
+                        (sizeof (struct arm_request_response)));
+                arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + 
+                        (sizeof(struct arm_request)));
+                arm_req->buffer = ((byte_t *)(arm_resp) + 
+                        (sizeof(struct arm_response)));
+                arm_resp->buffer = NULL;
+                memcpy (arm_req->buffer, data, length);
+                arm_req->buffer = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request) +
+                        sizeof (struct arm_response));
+                arm_req->buffer_length = length;
+                arm_req->generation = req->req.generation;
+                arm_req->extended_transaction_code = 0;
+                arm_req->destination_offset = addr;
+                arm_req->source_nodeid = nodeid;
+                arm_req->destination_nodeid = destid;
+                arm_req->tlabel = (flags >> 10) & 0x3f;
+                arm_req->tcode = (flags >> 4) & 0x0f;
+                arm_resp->buffer_length = 0;
+                arm_resp->response_code = rcode;
+                arm_req_resp->request  = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response));
+                arm_req_resp->response = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request));
+                queue_complete_req(req);
+        }
+        spin_unlock(&host_info_lock);
+        return(rcode);
+}
+
+static int arm_lock (struct hpsb_host *host, int nodeid, quadlet_t *store,
+             u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags)
+{
+        struct pending_request *req;
+        struct list_head *lh;
+        struct host_info *hi;
+        struct file_info *fi = NULL;
+        struct list_head *entry;
+        struct arm_addr  *arm_addr = NULL;
+        struct arm_request  *arm_req = NULL;
+        struct arm_response *arm_resp = NULL;        
+        int found=0, size=0, rcode=-1;
+        quadlet_t old, new;
+        struct arm_request_response *arm_req_resp = NULL;
+
+        if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) ||
+                ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) {
+                DBGMSG("arm_lock  called by node: %X "
+                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X", 
+                      nodeid, (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
+                      ext_tcode & 0xFF , be32_to_cpu(data));
+        } else {
+                DBGMSG("arm_lock  called by node: %X "
+                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X arg: %8.8X", 
+                      nodeid, (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
+                      ext_tcode & 0xFF , be32_to_cpu(data), be32_to_cpu(arg));
+        }
+        spin_lock(&host_info_lock);
+        hi = find_host_info(host); /* search address-entry */
+        if (hi != NULL) {
+                list_for_each(lh, &hi->file_info_list) {
+                        fi = list_entry(lh, struct file_info, list);
+                        entry = fi->addr_list.next;
+                        while (entry != &(fi->addr_list)) {
+                                arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                                if (((arm_addr->start) <= (addr)) && 
+                                        ((arm_addr->end) >= (addr+sizeof(*store)))) {
+                                        found = 1;
+                                        break;
+                                }
+                                entry = entry->next;
+                        }
+                        if (found) {
+                                break;
+                        }
+                }
+        }
+        rcode = -1;
+        if (!found) {
+                printk(KERN_ERR "raw1394: arm_lock FAILED addr_entry not found"
+                " -> rcode_address_error\n");
+                spin_unlock(&host_info_lock);
+                return (RCODE_ADDRESS_ERROR);
+        } else {
+                DBGMSG("arm_lock addr_entry FOUND");
+        }
+        if (rcode == -1) {
+                if (arm_addr->access_rights & ARM_LOCK) {
+                        if (!(arm_addr->client_transactions & ARM_LOCK)) {
+                                memcpy(&old,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)),
+                                        sizeof(old));
+                                switch (ext_tcode) {
+                                        case (EXTCODE_MASK_SWAP):
+                                                new = data | (old & ~arg);
+                                                break;
+                                        case (EXTCODE_COMPARE_SWAP):
+                                                if (old == arg) {
+                                                        new = data;
+                                                } else {
+                                                        new = old;
+                                                }
+                                                break;
+                                        case (EXTCODE_FETCH_ADD):
+                                                new = cpu_to_be32(be32_to_cpu(data) + be32_to_cpu(old));
+                                                break;
+                                        case (EXTCODE_LITTLE_ADD):
+                                                new = cpu_to_le32(le32_to_cpu(data) + le32_to_cpu(old));
+                                                break;
+                                        case (EXTCODE_BOUNDED_ADD):
+                                                if (old != arg) {
+                                                        new = cpu_to_be32(be32_to_cpu(data) + 
+                                                                be32_to_cpu(old));
+                                                } else {
+                                                        new = old;
+                                                }
+                                                break;
+                                        case (EXTCODE_WRAP_ADD):
+                                                if (old != arg) {
+                                                        new = cpu_to_be32(be32_to_cpu(data) + 
+                                                                be32_to_cpu(old));
+                                                } else {
+                                                        new = data;
+                                                }
+                                                break;
+                                        default:
+                                                rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                                                printk(KERN_ERR "raw1394: arm_lock FAILED "
+                                                "ext_tcode not allowed -> rcode_type_error\n");
+                                                break;
+                                } /*switch*/
+                                if (rcode == -1) {
+                                        DBGMSG("arm_lock -> (rcode_complete)");
+                                        rcode = RCODE_COMPLETE;
+                                        memcpy (store, &old, sizeof(*store));
+                                        memcpy ((arm_addr->addr_space_buffer)+
+                                                (addr-(arm_addr->start)), 
+                                                &new, sizeof(*store));
+                                }
+                        }
+                } else {
+                        rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                        DBGMSG("arm_lock -> rcode_type_error (access denied)");
+                }
+        }
+        if (arm_addr->notification_options & ARM_LOCK) {
+                DBGMSG("arm_lock -> entering notification-section");
+                req = __alloc_pending_request(SLAB_ATOMIC);
+                if (!req) {
+                        DBGMSG("arm_lock -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
+                        3 * sizeof(*store) + 
+                        sizeof (struct arm_request_response);  /* maximum */
+                req->data = kmalloc(size, SLAB_ATOMIC);
+                if (!(req->data)) {
+                        free_pending_request(req);
+                        DBGMSG("arm_lock -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                req->free_data=1;
+                arm_req_resp = (struct arm_request_response *) (req->data);
+                arm_req  = (struct arm_request *) ((byte_t *)(req->data) + 
+                        (sizeof (struct arm_request_response)));
+                arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + 
+                        (sizeof(struct arm_request)));
+                arm_req->buffer = ((byte_t *)(arm_resp) + 
+                        (sizeof(struct arm_response)));
+                arm_resp->buffer = ((byte_t *)(arm_req->buffer) + 
+                        (2* sizeof(*store)));
+                if ((ext_tcode == EXTCODE_FETCH_ADD) || 
+                        (ext_tcode == EXTCODE_LITTLE_ADD)) {
+                        arm_req->buffer_length = sizeof(*store);
+                        memcpy (arm_req->buffer, &data, sizeof(*store));
+
+                } else {
+                        arm_req->buffer_length = 2 * sizeof(*store);
+                        memcpy (arm_req->buffer, &arg,  sizeof(*store));
+                        memcpy (((arm_req->buffer) + sizeof(*store)), 
+                                &data, sizeof(*store));
+                }
+                if (rcode == RCODE_COMPLETE) {
+                        arm_resp->buffer_length = sizeof(*store);
+                        memcpy (arm_resp->buffer, &old, sizeof(*store));
+                } else {
+                        arm_resp->buffer = NULL;
+                        arm_resp->buffer_length = 0;
+                }
+                req->file_info = fi;
+                req->req.type = RAW1394_REQ_ARM;
+                req->req.generation = get_hpsb_generation(host);
+                req->req.misc = ( (((sizeof(*store)) << 16) & (0xFFFF0000)) | 
+                        (ARM_LOCK & 0xFF));
+                req->req.tag  = arm_addr->arm_tag;
+                req->req.recvb = arm_addr->recvb;
+                req->req.length = size;
+                arm_req->generation = req->req.generation;
+                arm_req->extended_transaction_code = ext_tcode;
+                arm_req->destination_offset = addr;
+                arm_req->source_nodeid = nodeid;
+                arm_req->destination_nodeid = host->node_id;
+                arm_req->tlabel = (flags >> 10) & 0x3f;
+                arm_req->tcode = (flags >> 4) & 0x0f;
+                arm_resp->response_code = rcode;
+                arm_req_resp->request  = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response));
+                arm_req_resp->response = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request));
+                arm_req->buffer = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request) +
+                        sizeof (struct arm_response));
+                arm_resp->buffer = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request) +
+                        sizeof (struct arm_response) +
+                        2* sizeof (*store));
+                queue_complete_req(req);
+        }
+        spin_unlock(&host_info_lock);
+        return(rcode);
+}
+
+static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store,
+               u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags)
+{
+        struct pending_request *req;
+        struct list_head *lh;
+        struct host_info *hi;
+        struct file_info *fi = NULL;
+        struct list_head *entry;
+        struct arm_addr  *arm_addr = NULL;
+        struct arm_request  *arm_req = NULL;
+        struct arm_response *arm_resp = NULL;
+        int found=0, size=0, rcode=-1;
+        octlet_t old, new;
+        struct arm_request_response *arm_req_resp = NULL;
+
+        if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) ||
+                ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) {
+                DBGMSG("arm_lock64 called by node: %X "
+                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X ",
+                      nodeid, (u16) ((addr >>32) & 0xFFFF),
+                      (u32) (addr & 0xFFFFFFFF), 
+                      ext_tcode & 0xFF , 
+                      (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF), 
+                      (u32) (be64_to_cpu(data) & 0xFFFFFFFF));
+        } else {
+                DBGMSG("arm_lock64 called by node: %X "
+                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X arg: "
+                      "%8.8X %8.8X ",
+                      nodeid, (u16) ((addr >>32) & 0xFFFF),
+                      (u32) (addr & 0xFFFFFFFF), 
+                      ext_tcode & 0xFF , 
+                      (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF), 
+                      (u32) (be64_to_cpu(data) & 0xFFFFFFFF),
+                      (u32) ((be64_to_cpu(arg)  >> 32) & 0xFFFFFFFF), 
+                      (u32) (be64_to_cpu(arg)  & 0xFFFFFFFF));
+        }
+        spin_lock(&host_info_lock);
+        hi = find_host_info(host); /* search addressentry in file_info's for host */
+        if (hi != NULL) {
+                list_for_each(lh, &hi->file_info_list) {
+                        fi = list_entry(lh, struct file_info, list);
+                        entry = fi->addr_list.next;
+                        while (entry != &(fi->addr_list)) {
+                                arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                                if (((arm_addr->start) <= (addr)) && 
+                                        ((arm_addr->end) >= (addr+sizeof(*store)))) {
+                                        found = 1;
+                                        break;
+                                }
+                                entry = entry->next;
+                        }
+                        if (found) {
+                                break;
+                        }
+                }
+        }
+        rcode = -1;
+        if (!found) {
+                printk(KERN_ERR "raw1394: arm_lock64 FAILED addr_entry not found"
+                " -> rcode_address_error\n");
+                spin_unlock(&host_info_lock);
+                return (RCODE_ADDRESS_ERROR);
+        } else {
+                DBGMSG("arm_lock64 addr_entry FOUND");
+        }
+        if (rcode == -1) {
+                if (arm_addr->access_rights & ARM_LOCK) {
+                        if (!(arm_addr->client_transactions & ARM_LOCK)) {
+                                memcpy(&old,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)),
+                                        sizeof(old));
+                                switch (ext_tcode) {
+                                        case (EXTCODE_MASK_SWAP):
+                                                new = data | (old & ~arg);
+                                                break;
+                                        case (EXTCODE_COMPARE_SWAP):
+                                                if (old == arg) {
+                                                        new = data;
+                                                } else {
+                                                        new = old;
+                                                }
+                                                break;
+                                        case (EXTCODE_FETCH_ADD):
+                                                new = cpu_to_be64(be64_to_cpu(data) + be64_to_cpu(old));
+                                                break;
+                                        case (EXTCODE_LITTLE_ADD):
+                                                new = cpu_to_le64(le64_to_cpu(data) + le64_to_cpu(old));
+                                                break;
+                                        case (EXTCODE_BOUNDED_ADD):
+                                                if (old != arg) {
+                                                        new = cpu_to_be64(be64_to_cpu(data) + 
+                                                                be64_to_cpu(old));
+                                                } else {
+                                                        new = old;
+                                                }
+                                                break;
+                                        case (EXTCODE_WRAP_ADD):
+                                                if (old != arg) {
+                                                        new = cpu_to_be64(be64_to_cpu(data) + 
+                                                                be64_to_cpu(old));
+                                                } else {
+                                                        new = data;
+                                                }
+                                                break;
+                                        default:
+                                                printk(KERN_ERR "raw1394: arm_lock64 FAILED "
+                                                "ext_tcode not allowed -> rcode_type_error\n");
+                                                rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                                                break;
+                                } /*switch*/
+                                if (rcode == -1) {
+                                        DBGMSG("arm_lock64 -> (rcode_complete)");
+                                        rcode = RCODE_COMPLETE;
+                                        memcpy (store, &old, sizeof(*store));
+                                        memcpy ((arm_addr->addr_space_buffer)+
+                                                (addr-(arm_addr->start)), 
+                                                &new, sizeof(*store));
+                                } 
+                        }
+                } else {
+                        rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                        DBGMSG("arm_lock64 -> rcode_type_error (access denied)");
+                }
+        }
+        if (arm_addr->notification_options & ARM_LOCK) {
+                DBGMSG("arm_lock64 -> entering notification-section");
+                req = __alloc_pending_request(SLAB_ATOMIC);
+                if (!req) {
+                        spin_unlock(&host_info_lock);
+                        DBGMSG("arm_lock64 -> rcode_conflict_error");
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
+                        3 * sizeof(*store) +
+                        sizeof (struct arm_request_response); /* maximum */
+                req->data = kmalloc(size, SLAB_ATOMIC);
+                if (!(req->data)) {
+                        free_pending_request(req);
+                        spin_unlock(&host_info_lock);
+                        DBGMSG("arm_lock64 -> rcode_conflict_error");
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                req->free_data=1;
+                arm_req_resp = (struct arm_request_response *) (req->data);
+                arm_req  = (struct arm_request *) ((byte_t *)(req->data) + 
+                        (sizeof (struct arm_request_response)));
+                arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + 
+                        (sizeof(struct arm_request)));
+                arm_req->buffer = ((byte_t *)(arm_resp) + 
+                        (sizeof(struct arm_response)));
+                arm_resp->buffer = ((byte_t *)(arm_req->buffer) + 
+                        (2* sizeof(*store)));
+                if ((ext_tcode == EXTCODE_FETCH_ADD) || 
+                        (ext_tcode == EXTCODE_LITTLE_ADD)) {
+                        arm_req->buffer_length = sizeof(*store);
+                        memcpy (arm_req->buffer, &data, sizeof(*store));
+
+                } else {
+                        arm_req->buffer_length = 2 * sizeof(*store);
+                        memcpy (arm_req->buffer, &arg,  sizeof(*store));
+                        memcpy (((arm_req->buffer) + sizeof(*store)), 
+                                &data, sizeof(*store));
+                }
+                if (rcode == RCODE_COMPLETE) {
+                        arm_resp->buffer_length = sizeof(*store);
+                        memcpy (arm_resp->buffer, &old, sizeof(*store));
+                } else {
+                        arm_resp->buffer = NULL;
+                        arm_resp->buffer_length = 0;
+                }
+                req->file_info = fi;
+                req->req.type = RAW1394_REQ_ARM;
+                req->req.generation = get_hpsb_generation(host);
+                req->req.misc = ( (((sizeof(*store)) << 16) & (0xFFFF0000)) | 
+                        (ARM_LOCK & 0xFF));
+                req->req.tag  = arm_addr->arm_tag;
+                req->req.recvb = arm_addr->recvb;
+                req->req.length = size;
+                arm_req->generation = req->req.generation;
+                arm_req->extended_transaction_code = ext_tcode;
+                arm_req->destination_offset = addr;
+                arm_req->source_nodeid = nodeid;
+                arm_req->destination_nodeid = host->node_id;
+                arm_req->tlabel = (flags >> 10) & 0x3f;
+                arm_req->tcode = (flags >> 4) & 0x0f;
+                arm_resp->response_code = rcode;
+                arm_req_resp->request  = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response));
+                arm_req_resp->response = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request));
+                arm_req->buffer = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request) +
+                        sizeof (struct arm_response));
+                arm_resp->buffer = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request) +
+                        sizeof (struct arm_response) +
+                        2* sizeof (*store));
+                queue_complete_req(req);
+        }
+        spin_unlock(&host_info_lock);
+        return(rcode);
+}
+
+static int arm_register(struct file_info *fi, struct pending_request *req)
+{
+        int retval;
+        struct arm_addr *addr;
+        struct list_head *lh, *lh_1, *lh_2;
+        struct host_info *hi;
+        struct file_info *fi_hlp = NULL;
+        struct list_head *entry;
+        struct arm_addr  *arm_addr = NULL;
+        int same_host, another_host;
+        unsigned long flags;
+
+        DBGMSG("arm_register called "
+              "addr(Offset): %8.8x %8.8x length: %u "
+              "rights: %2.2X notify: %2.2X "
+              "max_blk_len: %4.4X",
+              (u32) ((req->req.address >>32) & 0xFFFF),
+              (u32) (req->req.address & 0xFFFFFFFF),
+              req->req.length, ((req->req.misc >> 8) & 0xFF),
+              (req->req.misc & 0xFF),((req->req.misc >> 16) & 0xFFFF));
+        /* check addressrange */
+        if ((((req->req.address) & ~(0xFFFFFFFFFFFF)) != 0) ||
+                (((req->req.address + req->req.length) & ~(0xFFFFFFFFFFFF)) != 0)) {
+                req->req.length = 0;
+                return (-EINVAL);
+        }
+        /* addr-list-entry for fileinfo */
+        addr = (struct arm_addr *)kmalloc(sizeof(struct arm_addr), SLAB_KERNEL); 
+        if (!addr) {
+                req->req.length = 0;
+                return (-ENOMEM);
+        } 
+        /* allocation of addr_space_buffer */
+        addr->addr_space_buffer = (u8 *)kmalloc(req->req.length,SLAB_KERNEL);
+        if (!(addr->addr_space_buffer)) {
+                kfree(addr);
+                req->req.length = 0;
+                return (-ENOMEM);
+        }
+        /* initialization of addr_space_buffer */
+        if ((req->req.sendb)== (unsigned long)NULL) {
+                /* init: set 0 */
+                memset(addr->addr_space_buffer, 0,req->req.length);
+        } else {
+                /* init: user -> kernel */
+                if (copy_from_user(addr->addr_space_buffer,int2ptr(req->req.sendb),
+                        req->req.length)) {
+                        kfree(addr->addr_space_buffer);
+                        kfree(addr);
+                        return (-EFAULT);
+                }
+        }
+        INIT_LIST_HEAD(&addr->addr_list);
+        addr->arm_tag   = req->req.tag;
+        addr->start     = req->req.address;
+        addr->end       = req->req.address + req->req.length;
+        addr->access_rights = (u8) (req->req.misc & 0x0F);
+        addr->notification_options = (u8) ((req->req.misc >> 4) & 0x0F);
+        addr->client_transactions = (u8) ((req->req.misc >> 8) & 0x0F);
+        addr->access_rights |= addr->client_transactions;
+        addr->notification_options |= addr->client_transactions;
+        addr->recvb     = req->req.recvb;
+        addr->rec_length = (u16) ((req->req.misc >> 16) & 0xFFFF);
+        spin_lock_irqsave(&host_info_lock, flags);
+        hi = find_host_info(fi->host);
+        same_host = 0;
+        another_host = 0;
+        /* same host with address-entry containing same addressrange ? */
+        list_for_each(lh, &hi->file_info_list) {
+                fi_hlp = list_entry(lh, struct file_info, list);
+                entry = fi_hlp->addr_list.next;
+                while (entry != &(fi_hlp->addr_list)) {
+                        arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                        if ( (arm_addr->start == addr->start) && 
+                                (arm_addr->end == addr->end)) {
+                                DBGMSG("same host ownes same "
+                                        "addressrange -> EALREADY");
+                                same_host = 1;
+                                break;
+                        }
+                        entry = entry->next;
+                }
+                if (same_host) {
+                        break;
+                }
+        }
+        if (same_host) {
+                /* addressrange occupied by same host */
+                kfree(addr->addr_space_buffer);
+                kfree(addr);
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return (-EALREADY);
+        }
+        /* another host with valid address-entry containing same addressrange */
+        list_for_each(lh_1, &host_info_list) {
+                hi = list_entry(lh_1, struct host_info, list);
+                if (hi->host != fi->host) {
+                        list_for_each(lh_2, &hi->file_info_list) {
+                                fi_hlp = list_entry(lh_2, struct file_info, list);
+                                entry = fi_hlp->addr_list.next;
+                                while (entry != &(fi_hlp->addr_list)) {
+                                        arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                                        if ( (arm_addr->start == addr->start) && 
+                                                (arm_addr->end == addr->end)) {
+                                                DBGMSG("another host ownes same "
+                                                "addressrange");
+                                                another_host = 1;
+                                                break;
+                                        }
+                                        entry = entry->next;
+                                }
+                                if (another_host) {
+                                        break;
+                                }
+                        }
+                }
+        }
+        if (another_host) {
+                DBGMSG("another hosts entry is valid -> SUCCESS");
+                if (copy_to_user(int2ptr(req->req.recvb),
+                        int2ptr(&addr->start),sizeof(u64))) {
+                        printk(KERN_ERR "raw1394: arm_register failed "
+                              " address-range-entry is invalid -> EFAULT !!!\n");
+                        kfree(addr->addr_space_buffer);
+                        kfree(addr);
+                        spin_unlock_irqrestore(&host_info_lock, flags);
+                        return (-EFAULT);
+                }
+                free_pending_request(req); /* immediate success or fail */
+                /* INSERT ENTRY */
+                list_add_tail(&addr->addr_list, &fi->addr_list);
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return sizeof(struct raw1394_request);
+        }
+        retval = hpsb_register_addrspace(hl_handle, &arm_ops, req->req.address,
+                req->req.address + req->req.length);
+        if (retval) {
+               /* INSERT ENTRY */
+               list_add_tail(&addr->addr_list, &fi->addr_list);
+        } else {
+                DBGMSG("arm_register failed errno: %d \n",retval);
+                kfree(addr->addr_space_buffer);
+                kfree(addr);
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return (-EALREADY); 
+        }
+        spin_unlock_irqrestore(&host_info_lock, flags);
+        free_pending_request(req); /* immediate success or fail */
+        return sizeof(struct raw1394_request);
+}
+
+static int arm_unregister(struct file_info *fi, struct pending_request *req)
+{
+        int found  = 0;
+        int retval = 0;
+        struct list_head *entry;
+        struct arm_addr  *addr = NULL;
+        struct list_head *lh_1, *lh_2;
+        struct host_info *hi;
+        struct file_info *fi_hlp = NULL;
+        struct arm_addr  *arm_addr = NULL;
+        int another_host;
+        unsigned long flags;
+
+        DBGMSG("arm_Unregister called addr(Offset): "
+              "%8.8x %8.8x",
+              (u32) ((req->req.address >>32) & 0xFFFF),
+              (u32) (req->req.address & 0xFFFFFFFF));
+        spin_lock_irqsave(&host_info_lock, flags);
+        /* get addr */
+        entry = fi->addr_list.next;
+        while (entry != &(fi->addr_list)) {
+                addr = list_entry(entry, struct arm_addr, addr_list);
+                if (addr->start == req->req.address) {
+                        found = 1;
+                        break;
+                }
+                entry = entry->next;
+        }
+        if (!found) {
+                DBGMSG("arm_Unregister addr not found");
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return (-EINVAL);
+        }
+        DBGMSG("arm_Unregister addr found");
+        another_host = 0;
+        /* another host with valid address-entry containing 
+           same addressrange */
+        list_for_each(lh_1, &host_info_list) {
+                hi = list_entry(lh_1, struct host_info, list);
+                if (hi->host != fi->host) {
+                        list_for_each(lh_2, &hi->file_info_list) {
+                                fi_hlp = list_entry(lh_2, struct file_info, list);
+                                entry = fi_hlp->addr_list.next;
+                                while (entry != &(fi_hlp->addr_list)) {
+                                        arm_addr = list_entry(entry, 
+                                                struct arm_addr, addr_list);
+                                        if (arm_addr->start == 
+                                                addr->start) {
+                                                DBGMSG("another host ownes "
+                                                "same addressrange");
+                                                another_host = 1;
+                                                break;
+                                        }
+                                        entry = entry->next;
+                                }
+                                if (another_host) {
+                                        break;
+                                }
+                        }
+                }
+        }
+        if (another_host) {
+                DBGMSG("delete entry from list -> success");
+                list_del(&addr->addr_list);
+                kfree(addr->addr_space_buffer);
+                kfree(addr);
+                free_pending_request(req); /* immediate success or fail */
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return sizeof(struct raw1394_request);
+        } 
+        retval = hpsb_unregister_addrspace(hl_handle, addr->start);
+        if (!retval) {
+                printk(KERN_ERR "raw1394: arm_Unregister failed -> EINVAL\n");
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return (-EINVAL);
+        }
+        DBGMSG("delete entry from list -> success");
+        list_del(&addr->addr_list);
+        spin_unlock_irqrestore(&host_info_lock, flags);
+        kfree(addr->addr_space_buffer);
+        kfree(addr);
+        free_pending_request(req); /* immediate success or fail */
+        return sizeof(struct raw1394_request);
+}
+
+static int reset_notification(struct file_info *fi, struct pending_request *req)
+{
+        DBGMSG("reset_notification called - switch %s ",
+                (req->req.misc == RAW1394_NOTIFY_OFF)?"OFF":"ON");
+        if ((req->req.misc == RAW1394_NOTIFY_OFF) ||
+                (req->req.misc == RAW1394_NOTIFY_ON)) {
+                fi->notification=(u8)req->req.misc;
+                free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+                return sizeof(struct raw1394_request);
+        } 
+        /* error EINVAL (22) invalid argument */
+        return (-EINVAL);
+}
+
+static int write_phypacket(struct file_info *fi, struct pending_request *req)
+{
+        struct hpsb_packet *packet = NULL;
+        int retval=0;
+        quadlet_t data;
+
+        data = be32_to_cpu((u32)req->req.sendb);
+        DBGMSG("write_phypacket called - quadlet 0x%8.8x ",data);
+        packet = hpsb_make_phypacket (fi->host, data);
+        if (!packet) return -ENOMEM;
+        req->req.length=0;
+        req->packet=packet;
+        req->tq.data=req;
+        hpsb_add_packet_complete_task(packet, &req->tq);
+        spin_lock_irq(&fi->reqlists_lock);
+        list_add_tail(&req->list, &fi->req_pending);
+        spin_unlock_irq(&fi->reqlists_lock);
+        packet->generation = req->req.generation;
+        retval = hpsb_send_packet(packet);
+        DBGMSG("write_phypacket send_packet called => retval: %d ",
+                retval);
+        if (! retval) {
+                req->req.error = RAW1394_ERROR_SEND_ERROR;
+                req->req.length = 0;
+                queue_complete_req(req);
+        }
+        return sizeof(struct raw1394_request);
+}
+
+static int get_config_rom(struct file_info *fi, struct pending_request *req)
+{
+        size_t return_size;
+        unsigned char rom_version;
+        int ret=sizeof(struct raw1394_request);
+        quadlet_t *data = kmalloc(req->req.length, SLAB_KERNEL);
+        int status;
+        if (!data) return -ENOMEM;
+        status = hpsb_get_config_rom(fi->host, data, 
+                req->req.length, &return_size, &rom_version);
+        if (copy_to_user(int2ptr(req->req.recvb), data, 
+                req->req.length))
+                ret = -EFAULT;
+        if (copy_to_user(int2ptr(req->req.tag), &return_size, 
+                sizeof(return_size)))
+                ret = -EFAULT;
+        if (copy_to_user(int2ptr(req->req.address), &rom_version, 
+                sizeof(rom_version)))
+                ret = -EFAULT;
+        if (copy_to_user(int2ptr(req->req.sendb), &status, 
+                sizeof(status)))
+                ret = -EFAULT;
+        kfree(data);
+        if (ret >= 0) {
+                free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+        }
+        return ret;
+}
+
+static int update_config_rom(struct file_info *fi, struct pending_request *req)
+{
+        int ret=sizeof(struct raw1394_request);
+        quadlet_t *data = kmalloc(req->req.length, SLAB_KERNEL);
+        if (!data) return -ENOMEM;
+        if (copy_from_user(data,int2ptr(req->req.sendb), 
+                req->req.length)) {
+                ret= -EFAULT;
+        } else {
+                int status = hpsb_update_config_rom(fi->host, 
+                        data, req->req.length, 
+                        (unsigned char) req->req.misc);
+                if (copy_to_user(int2ptr(req->req.recvb), 
+                        &status, sizeof(status)))
+                        ret = -ENOMEM;
+        }
+        kfree(data);
+        if (ret >= 0) {
+                free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+        }
+        return ret;
+}
+
+static int state_connected(struct file_info *fi, struct pending_request *req)
+{
+        int node = req->req.address >> 48;
+
+        req->req.error = RAW1394_ERROR_NONE;
+
         switch (req->req.type) {
+
+        case RAW1394_REQ_ECHO:
+                queue_complete_req(req);
+                return sizeof(struct raw1394_request);
+
+        case RAW1394_REQ_ISO_SEND:
+                return handle_iso_send(fi, req, node);
+
+        case RAW1394_REQ_ARM_REGISTER:
+                return arm_register(fi, req);
+
+        case RAW1394_REQ_ARM_UNREGISTER:
+                return arm_unregister(fi, req);
+
+        case RAW1394_REQ_RESET_NOTIFY:
+                return reset_notification(fi, req);
+
         case RAW1394_REQ_ISO_LISTEN:
                 handle_iso_listen(fi, req);
                 return sizeof(struct raw1394_request);
@@ -831,21 +1911,49 @@
                 return sizeof(struct raw1394_request);
 
         case RAW1394_REQ_RESET_BUS:
-                hpsb_reset_bus(fi->host, LONG_RESET);
+                if (req->req.misc == RAW1394_LONG_RESET) {
+                        DBGMSG("busreset called (type: LONG)");
+                        hpsb_reset_bus(fi->host, LONG_RESET);
+                        free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+                        return sizeof(struct raw1394_request);
+                }
+                if (req->req.misc == RAW1394_SHORT_RESET) {
+                        DBGMSG("busreset called (type: SHORT)");
+                        hpsb_reset_bus(fi->host, SHORT_RESET);
+                        free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+                        return sizeof(struct raw1394_request);
+                }
+                /* error EINVAL (22) invalid argument */
+                return (-EINVAL);
+        case RAW1394_REQ_GET_ROM:
+                return get_config_rom(fi, req);
+
+        case RAW1394_REQ_UPDATE_ROM:
+                return update_config_rom(fi, req);
+        }
+
+        if (req->req.generation != get_hpsb_generation(fi->host)) {
+                req->req.error = RAW1394_ERROR_GENERATION;
+                req->req.generation = get_hpsb_generation(fi->host);
+                req->req.length = 0;
+                queue_complete_req(req);
                 return sizeof(struct raw1394_request);
         }
 
+        switch (req->req.type) {
+        case RAW1394_REQ_PHYPACKET:
+                return write_phypacket(fi, req);
+        case RAW1394_REQ_ASYNC_SEND:
+                return handle_async_send(fi, req);
+        }
+
         if (req->req.length == 0) {
                 req->req.error = RAW1394_ERROR_INVALID_ARG;
                 queue_complete_req(req);
                 return sizeof(struct raw1394_request);
         }
 
-        if (fi->host->node_id == node) {
-                return handle_local_request(fi, req, node);
-        }
-
-        return handle_remote_request(fi, req, node);
+        return handle_async_request(fi, req, node);
 }
 
 
@@ -921,6 +2029,7 @@
                 return -ENOMEM;
         
         memset(fi, 0, sizeof(struct file_info));
+        fi->notification = (u8) RAW1394_NOTIFY_ON; /* busreset notification */
 
         INIT_LIST_HEAD(&fi->list);
         fi->state = opened;
@@ -929,6 +2038,7 @@
         sema_init(&fi->complete_sem, 0);
         spin_lock_init(&fi->reqlists_lock);
         init_waitqueue_head(&fi->poll_wait_complete);
+        INIT_LIST_HEAD(&fi->addr_list);
 
         file->private_data = fi;
 
@@ -940,7 +2050,15 @@
         struct file_info *fi = file->private_data;
         struct list_head *lh;
         struct pending_request *req;
-        int done = 0, i;
+        int done = 0, i, fail = 0;
+        int retval = 0;
+        struct list_head *entry;
+        struct arm_addr  *addr = NULL;
+        struct list_head *lh_1, *lh_2;
+        struct host_info *hi;
+        struct file_info *fi_hlp = NULL;
+        struct arm_addr  *arm_addr = NULL;
+        int another_host;
 
         for (i = 0; i < 64; i++) {
                 if (fi->listen_channels & (1ULL << i)) {
@@ -948,9 +2066,63 @@
                 }
         }
 
-        spin_lock(&host_info_lock);
+        spin_lock_irq(&host_info_lock);
         fi->listen_channels = 0;
-        spin_unlock(&host_info_lock);
+        spin_unlock_irq(&host_info_lock);
+
+        fail = 0;
+        /* set address-entries invalid */
+        spin_lock_irq(&host_info_lock);
+
+        while (!list_empty(&fi->addr_list)) {
+                another_host = 0;
+                lh = fi->addr_list.next;
+                addr = list_entry(lh, struct arm_addr, addr_list);
+                /* another host with valid address-entry containing 
+                   same addressrange? */
+                list_for_each(lh_1, &host_info_list) {
+                        hi = list_entry(lh_1, struct host_info, list);
+                        if (hi->host != fi->host) {
+                                list_for_each(lh_2, &hi->file_info_list) {
+                                        fi_hlp = list_entry(lh_2, struct file_info, list);
+                                        entry = fi_hlp->addr_list.next;
+                                        while (entry != &(fi_hlp->addr_list)) {
+                                                arm_addr = list_entry(entry, 
+                                                        struct arm_addr, addr_list);
+                                                if (arm_addr->start == 
+                                                        addr->start) {
+                                                        DBGMSG("raw1394_release: "
+                                                        "another host ownes "
+                                                        "same addressrange");
+                                                        another_host = 1;
+                                                        break;
+                                                }
+                                                entry = entry->next;
+                                        }
+                                        if (another_host) {
+                                                break;
+                                        }
+                                }
+                        }
+                }
+                if (!another_host) {
+                        DBGMSG("raw1394_release: call hpsb_arm_unregister");
+                        retval = hpsb_unregister_addrspace(hl_handle, addr->start);
+                        if (!retval) {
+                                ++fail;
+                                printk(KERN_ERR "raw1394_release arm_Unregister failed\n");
+                        }
+                }
+                DBGMSG("raw1394_release: delete addr_entry from list");
+                list_del(&addr->addr_list);
+                kfree(addr->addr_space_buffer);
+                kfree(addr);
+        } /* while */
+        spin_unlock_irq(&host_info_lock);
+        if (fail > 0) {
+                printk(KERN_ERR "raw1394: during addr_list-release "
+                        "error(s) occured \n");
+        }
 
         while (!done) {
                 spin_lock_irq(&fi->reqlists_lock);
@@ -1009,28 +2181,28 @@
                 return -ENOMEM;
         }
 
-	devfs_handle = devfs_register(NULL,
-				      RAW1394_DEVICE_NAME, DEVFS_FL_NONE,
+        devfs_handle = devfs_register(NULL,
+                                      RAW1394_DEVICE_NAME, DEVFS_FL_NONE,
                                       IEEE1394_MAJOR,
-				      IEEE1394_MINOR_BLOCK_RAW1394 * 16,
+                                      IEEE1394_MINOR_BLOCK_RAW1394 * 16,
                                       S_IFCHR | S_IRUSR | S_IWUSR, &file_ops,
                                       NULL);
 
         if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_RAW1394,
-				      THIS_MODULE, &file_ops)) {
+                                      THIS_MODULE, &file_ops)) {
                 HPSB_ERR("raw1394 failed to register minor device block");
-		devfs_unregister(devfs_handle);
-		hpsb_unregister_highlevel(hl_handle);
+                devfs_unregister(devfs_handle);
+                hpsb_unregister_highlevel(hl_handle);
                 return -EBUSY;
         }
-	printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME);
+        printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME);
         return 0;
 }
 
 static void __exit cleanup_raw1394(void)
 {
         ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_RAW1394);
-	devfs_unregister(devfs_handle);
+        devfs_unregister(devfs_handle);
         hpsb_unregister_highlevel(hl_handle);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/raw1394.h linux-2.4.21/drivers/ieee1394/raw1394.h
--- linux-2.4.20/drivers/ieee1394/raw1394.h	2000-10-02 02:53:07.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/raw1394.h	2002-12-18 18:58:02.000000000 +0000
@@ -14,20 +14,32 @@
 #define RAW1394_REQ_SET_CARD      3
 
 /* state: connected */
-#define RAW1394_REQ_ASYNC_READ    100
-#define RAW1394_REQ_ASYNC_WRITE   101
-#define RAW1394_REQ_LOCK          102
-#define RAW1394_REQ_LOCK64        103
-#define RAW1394_REQ_ISO_SEND      104
-
-#define RAW1394_REQ_ISO_LISTEN    200
-#define RAW1394_REQ_FCP_LISTEN    201
-#define RAW1394_REQ_RESET_BUS     202
+#define RAW1394_REQ_ASYNC_READ      100
+#define RAW1394_REQ_ASYNC_WRITE     101
+#define RAW1394_REQ_LOCK            102
+#define RAW1394_REQ_LOCK64          103
+#define RAW1394_REQ_ISO_SEND        104
+#define RAW1394_REQ_ASYNC_SEND      105
+
+#define RAW1394_REQ_ISO_LISTEN      200
+#define RAW1394_REQ_FCP_LISTEN      201
+#define RAW1394_REQ_RESET_BUS       202
+#define RAW1394_REQ_GET_ROM         203
+#define RAW1394_REQ_UPDATE_ROM      204
+#define RAW1394_REQ_ECHO            205
+
+#define RAW1394_REQ_ARM_REGISTER    300
+#define RAW1394_REQ_ARM_UNREGISTER  301
+
+#define RAW1394_REQ_RESET_NOTIFY    400
+
+#define RAW1394_REQ_PHYPACKET       500
 
 /* kernel to user */
 #define RAW1394_REQ_BUS_RESET     10000
 #define RAW1394_REQ_ISO_RECEIVE   10001
 #define RAW1394_REQ_FCP_REQUEST   10002
+#define RAW1394_REQ_ARM           10003
 
 /* error codes */
 #define RAW1394_ERROR_NONE        0
@@ -45,6 +57,17 @@
 #define RAW1394_ERROR_ABORTED     (-1101)
 #define RAW1394_ERROR_TIMEOUT     (-1102)
 
+/* arm_codes */
+#define ARM_READ   1
+#define ARM_WRITE  2
+#define ARM_LOCK   4
+
+#define RAW1394_LONG_RESET  0
+#define RAW1394_SHORT_RESET 1
+
+/* busresetnotify ... */
+#define RAW1394_NOTIFY_OFF 0
+#define RAW1394_NOTIFY_ON  1
 
 #include <asm/types.h>
 
@@ -69,6 +92,29 @@
         __u8 name[32];
 };
 
+typedef struct arm_request {
+        nodeid_t        destination_nodeid;
+        nodeid_t        source_nodeid;
+        nodeaddr_t      destination_offset;
+        u8              tlabel;
+        u8              tcode;
+        u_int8_t        extended_transaction_code;
+        u_int32_t       generation;
+        arm_length_t    buffer_length;
+        byte_t          *buffer;
+} *arm_request_t;
+
+typedef struct arm_response {
+        int             response_code;
+        arm_length_t    buffer_length;
+        byte_t          *buffer;
+} *arm_response_t;
+
+typedef struct arm_request_response {
+        struct arm_request  *request;
+        struct arm_response *response;
+} *arm_request_response_t;
+
 #ifdef __KERNEL__
 
 struct iso_block_store {
@@ -91,18 +137,34 @@
         spinlock_t reqlists_lock;
         wait_queue_head_t poll_wait_complete;
 
+        struct list_head addr_list;           
+
         u8 *fcp_buffer;
 
         u64 listen_channels;
         quadlet_t *iso_buffer;
         size_t iso_buffer_length;
+
+        u8 notification; /* (busreset-notification) RAW1394_NOTIFY_OFF/ON */
+};
+
+struct arm_addr {
+        struct list_head addr_list; /* file_info list */
+        u64    start, end;
+        u64    arm_tag;
+        u8     access_rights;
+        u8     notification_options;
+        u8     client_transactions;
+        u64    recvb;
+        u16    rec_length;
+        u8     *addr_space_buffer; /* accessed by read/write/lock */
 };
 
 struct pending_request {
         struct list_head list;
         struct file_info *file_info;
         struct hpsb_packet *packet;
-        struct tq_struct tq;
+        struct hpsb_queue_struct tq;
         struct iso_block_store *ibs;
         quadlet_t *data;
         int free_data;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/sbp2.c linux-2.4.21/drivers/ieee1394/sbp2.c
--- linux-2.4.20/drivers/ieee1394/sbp2.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/sbp2.c	2002-12-18 18:58:03.000000000 +0000
@@ -320,7 +320,6 @@
 #include <linux/blk.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
-#include <linux/blk.h>
 #include <asm/current.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -351,7 +350,7 @@
 #include "sbp2.h"
 
 static char version[] __devinitdata =
-	"$Rev: 584 $ James Goodwin <jamesg@filanet.com>";
+	"$Rev: 707 $ James Goodwin <jamesg@filanet.com>";
 
 /*
  * Module load parameter definitions
@@ -421,8 +420,9 @@
  * talking to a single sbp2 device at the same time (filesystem coherency,
  * etc.). If you're running an sbp2 device that supports multiple logins,
  * and you're either running read-only filesystems or some sort of special
- * filesystem supporting multiple hosts, then set sbp2_exclusive_login to
- * zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four
+ * filesystem supporting multiple hosts (one such filesystem is OpenGFS,
+ * see opengfs.sourceforge.net for more info), then set sbp2_exclusive_login
+ * to zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four
  * concurrent logins.
  */
 MODULE_PARM(sbp2_exclusive_login,"i");
@@ -800,8 +800,9 @@
 		 * Set up a task queue completion routine, which returns
 		 * the packet to the free list and releases the tlabel.
 		 */
-		request_packet->tq.routine = (void (*)(void*))sbp2util_free_request_packet;
-		request_packet->tq.data = request_packet;
+		HPSB_PREPARE_WORK(&request_packet->tq,
+				  (void (*)(void*))sbp2util_free_request_packet,
+				  request_packet);
 		request_packet->hi_context = hi;
 		hpsb_add_packet_complete_task(packet, &request_packet->tq);
 
@@ -1007,13 +1008,8 @@
 					 command->dma_size, command->dma_dir);
 			SBP2_DMA_FREE("single bulk");
 		} else if (command->dma_type == CMD_DMA_PAGE) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13)
-			pci_unmap_single(hi->host->pdev, command->cmd_dma,
-					 command->dma_size, command->dma_dir);
-#else
 			pci_unmap_page(hi->host->pdev, command->cmd_dma,
 				       command->dma_size, command->dma_dir);
-#endif /* Linux version < 2.4.13 */
 			SBP2_DMA_FREE("single page");
 		} /* XXX: Check for CMD_DMA_NONE bug */
 		command->dma_type = CMD_DMA_NONE;
@@ -2146,17 +2142,11 @@
 			command->dma_dir = dma_dir;
 			command->dma_size = sgpnt[0].length;
 			command->dma_type = CMD_DMA_PAGE;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13)
-			command->cmd_dma = pci_map_single (hi->host->pdev, sgpnt[0].address,
-							   command->dma_size,
-							   command->dma_dir);
-#else
 			command->cmd_dma = pci_map_page(hi->host->pdev,
 							sgpnt[0].page,
 							sgpnt[0].offset,
 							command->dma_size,
 							command->dma_dir);
-#endif /* Linux version < 2.4.13 */
 			SBP2_DMA_ALLOC("single page scatter element");
 
 			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
@@ -2702,7 +2692,7 @@
  * This function deals with status writes from the SBP-2 device
  */
 static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid,
-				    quadlet_t *data, u64 addr, unsigned int length)
+				    quadlet_t *data, u64 addr, unsigned int length, u16 fl)
 {
 	struct sbp2scsi_host_info *hi = NULL;
 	struct scsi_id_instance_data *scsi_id = NULL;
@@ -3063,15 +3053,9 @@
 	/*
 	 * Tell scsi stack that we're done with this command
 	 */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 	spin_lock_irq(&io_request_lock);
 	done (SCpnt);
 	spin_unlock_irq(&io_request_lock);
-#else
-	spin_lock_irq(hi->scsi_host->host_lock);
-	done (SCpnt);
-	spin_unlock_irq(hi->scsi_host->host_lock);
-#endif
 
 	return;
 }
@@ -3148,11 +3132,7 @@
 /*
  * Called by scsi stack to get bios parameters (used by fdisk, and at boot).
  */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,28)
 static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]) 
-#else
-static int sbp2scsi_biosparam (Scsi_Disk *disk, struct block_device *dev, int geom[]) 
-#endif
 {
 	int heads, sectors, cylinders;
 
@@ -3160,12 +3140,12 @@
 
 	heads = 64;
 	sectors = 32;
-	cylinders = disk->capacity / (heads * sectors);
+	cylinders = (int)disk->capacity / (heads * sectors);
 
 	if (cylinders > 1024) {
 		heads = 255;
 		sectors = 63;
-		cylinders = disk->capacity / (heads * sectors);
+		cylinders = (int)disk->capacity / (heads * sectors);
 	}
 
 	geom[0] = heads;
@@ -3189,13 +3169,9 @@
 	 * we register a scsi host with the scsi stack.
 	 */
 	
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 	spin_unlock_irq(&io_request_lock);
 	sbp2_init();
 	spin_lock_irq(&io_request_lock);
-#else
-	sbp2_init();
-#endif
 
 	/* We return the number of hosts registered. */
 	return scsi_driver_template.present;
@@ -3253,9 +3229,7 @@
 	.this_id =		-1,
 	.sg_tablesize =		SBP2_MAX_SG_ELEMENTS,
 	.use_clustering =	SBP2_CLUSTERING,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 	.use_new_eh_code =	TRUE,
-#endif
 	.emulated =		1,
 	.proc_name =	SBP2_DEVICE_NAME,
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/sbp2.h linux-2.4.21/drivers/ieee1394/sbp2.h
--- linux-2.4.20/drivers/ieee1394/sbp2.h	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/sbp2.h	2002-12-18 18:58:04.000000000 +0000
@@ -23,13 +23,8 @@
 #define SBP2_H
 
 /* Some compatibility code */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 #define SCSI_REGISTER_HOST(tmpl)	scsi_register_module(MODULE_SCSI_HA, tmpl)
 #define SCSI_UNREGISTER_HOST(tmpl)	scsi_unregister_module(MODULE_SCSI_HA, tmpl)
-#else
-#define SCSI_REGISTER_HOST(tmpl)	scsi_register_host(tmpl)
-#define SCSI_UNREGISTER_HOST(tmpl)	scsi_unregister_host(tmpl)
-#endif
 
 #define SBP2_DEVICE_NAME		"sbp2"
 #define SBP2_DEVICE_NAME_SIZE		4
@@ -324,7 +319,7 @@
 
 	struct list_head list;
 	struct hpsb_packet *packet;
-	struct tq_struct tq;
+	struct hpsb_queue_struct tq;
 	void *hi_context;
 
 };
@@ -510,9 +505,9 @@
 
 #ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
 static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, int destid, quadlet_t *data,
-                                     u64 addr, unsigned int length);
+                                     u64 addr, unsigned int length, u16 flags);
 static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data,
-                                    u64 addr, unsigned int length);
+                                    u64 addr, unsigned int length, u16 flags);
 #endif
 
 /*
@@ -522,7 +517,7 @@
 static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); 
 static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); 
 static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid,
-				    quadlet_t *data, u64 addr, unsigned int length);
+				    quadlet_t *data, u64 addr, unsigned int length, u16 flags);
 static int sbp2_agent_reset(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 flags);
 static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, 
 				   struct scsi_id_instance_data *scsi_id,
@@ -549,11 +544,7 @@
 static int sbp2scsi_detect (Scsi_Host_Template *tpnt);
 static const char *sbp2scsi_info (struct Scsi_Host *host);
 void sbp2scsi_setup(char *str, int *ints);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,28)
 static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]);
-#else
-static int sbp2scsi_biosparam (Scsi_Disk *disk, struct block_device *dev, int geom[]);
-#endif
 static int sbp2scsi_abort (Scsi_Cmnd *SCpnt); 
 static int sbp2scsi_reset (Scsi_Cmnd *SCpnt); 
 static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/video1394.c linux-2.4.21/drivers/ieee1394/video1394.c
--- linux-2.4.20/drivers/ieee1394/video1394.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/ieee1394/video1394.c	2002-12-18 18:58:03.000000000 +0000
@@ -35,7 +35,6 @@
 #include <linux/poll.h>
 #include <linux/smp_lock.h>
 #include <linux/proc_fs.h>
-#include <linux/tqueue.h>
 #include <linux/delay.h>
 #include <linux/devfs_fs_kernel.h>
 
@@ -65,13 +64,8 @@
 #define vmalloc_32(x) vmalloc(x)
 #endif
 
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,3))
 #define remap_page_range_1394(vma, start, addr, size, prot) \
 	remap_page_range(start, addr, size, prot)
-#else
-#define remap_page_range_1394(vma, start, addr, size, prot) \
-	remap_page_range(vma, start, addr, size, prot)
-#endif
 
 struct it_dma_prg {
 	struct dma_cmd begin;
@@ -559,11 +553,7 @@
 		if (d->ir_prg[i][d->nb_cmd-1].status & cpu_to_le32(0xFFFF0000)) {
 			reset_ir_status(d, i);
 			d->buffer_status[i] = VIDEO1394_BUFFER_READY;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
-			get_fast_time(&d->buffer_time[i]);
-#else
 			do_gettimeofday(&d->buffer_time[i]);
-#endif
 		}
 	}
 
@@ -1455,12 +1445,7 @@
  		return -EIO;
  	}
 	
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-	devfs_handle = devfs_mk_dir(NULL, VIDEO1394_DRIVER_NAME,
-			strlen(VIDEO1394_DRIVER_NAME), NULL);
-#else
 	devfs_handle = devfs_mk_dir(NULL, VIDEO1394_DRIVER_NAME, NULL);
-#endif
 
 	hl_handle = hpsb_register_highlevel (VIDEO1394_DRIVER_NAME, &hl_ops);
 	if (hl_handle == NULL) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/input/input.c linux-2.4.21/drivers/input/input.c
--- linux-2.4.20/drivers/input/input.c	2001-09-30 19:26:05.000000000 +0000
+++ linux-2.4.21/drivers/input/input.c	2002-12-18 18:58:09.000000000 +0000
@@ -130,6 +130,8 @@
 
 			if (code > MSC_MAX || !test_bit(code, dev->mscbit))
 				return;
+
+			if (dev->event) dev->event(dev, type, code, value);	
 	
 			break;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/input/joydev.c linux-2.4.21/drivers/input/joydev.c
--- linux-2.4.20/drivers/input/joydev.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/input/joydev.c	2002-12-18 18:58:08.000000000 +0000
@@ -50,6 +50,8 @@
 #define JOYDEV_MINORS		32
 #define JOYDEV_BUFFER_SIZE	64
 
+#define MSECS(t)	(1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ)
+
 struct joydev {
 	int exist;
 	int open;
@@ -134,7 +136,7 @@
 			return;
 	}  
 
-	event.time = jiffies * (1000 / HZ);
+	event.time = MSECS(jiffies);
 
 	while (list) {
 
@@ -279,7 +281,7 @@
 
 		struct js_event event;
 
-		event.time = jiffies * (1000/HZ);
+		event.time = MSECS(jiffies);
 
 		if (list->startup < joydev->nkey) {
 			event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/isdn_ppp.c linux-2.4.21/drivers/isdn/isdn_ppp.c
--- linux-2.4.20/drivers/isdn/isdn_ppp.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/isdn/isdn_ppp.c	2002-12-18 18:58:10.000000000 +0000
@@ -380,7 +380,7 @@
 	is->slcomp = NULL;
 #endif
 
-/* TODO: if this was the previous master: link the the stuff to the new master */
+/* TODO: if this was the previous master: link the stuff to the new master */
 	if(is->comp_stat)
 		is->compressor->free(is->comp_stat);
 	if(is->link_comp_stat)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/macintosh/nvram.c linux-2.4.21/drivers/macintosh/nvram.c
--- linux-2.4.20/drivers/macintosh/nvram.c	2001-10-15 20:43:24.000000000 +0000
+++ linux-2.4.21/drivers/macintosh/nvram.c	2002-12-18 18:58:03.000000000 +0000
@@ -113,8 +113,7 @@
 {
 	printk(KERN_INFO "Macintosh non-volatile memory driver v%s\n",
 		NVRAM_VERSION);
-	misc_register(&nvram_dev);
-	return 0;
+	return misc_register(&nvram_dev);
 }
 
 void __exit nvram_cleanup(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/md/lvm.c linux-2.4.21/drivers/md/lvm.c
--- linux-2.4.20/drivers/md/lvm.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/md/lvm.c	2002-12-18 18:58:10.000000000 +0000
@@ -2253,7 +2253,7 @@
 
 	if (lv_ptr->lv_access & LV_SNAPSHOT) {
 		/*
-		 * Atomically make the the snapshot invisible
+		 * Atomically make the snapshot invisible
 		 * to the original lv before playing with it.
 		 */
 		lv_t * org = lv_ptr->lv_snapshot_org;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/md/md.c linux-2.4.21/drivers/md/md.c
--- linux-2.4.20/drivers/md/md.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/md/md.c	2002-12-18 18:58:05.000000000 +0000
@@ -445,21 +445,22 @@
 	if (rdev->sb)
 		MD_BUG();
 
-	rdev->sb = (mdp_super_t *) __get_free_page(GFP_KERNEL);
-	if (!rdev->sb) {
+	rdev->sb_page = alloc_page(GFP_KERNEL);
+	if (!rdev->sb_page) {
 		printk(OUT_OF_MEM);
 		return -EINVAL;
 	}
-	md_clear_page(rdev->sb);
+	rdev->sb = (mdp_super_t *) page_address(rdev->sb_page);
 
 	return 0;
 }
 
 static void free_disk_sb(mdk_rdev_t * rdev)
 {
-	if (rdev->sb) {
-		free_page((unsigned long) rdev->sb);
+	if (rdev->sb_page) {
+		page_cache_release(rdev->sb_page);
 		rdev->sb = NULL;
+		rdev->sb_page = NULL;
 		rdev->sb_offset = 0;
 		rdev->size = 0;
 	} else {
@@ -468,12 +469,43 @@
 	}
 }
 
+
+static void bh_complete(struct buffer_head *bh, int uptodate)
+{
+
+	if (uptodate)
+		set_bit(BH_Uptodate, &bh->b_state);
+
+	complete((struct completion*)bh->b_private);
+}
+
+static int sync_page_io(kdev_t dev, unsigned long sector, int size,
+			struct page *page, int rw)
+{
+	struct buffer_head bh;
+	struct completion event;
+
+	init_completion(&event);
+	init_buffer(&bh, bh_complete, &event);
+	bh.b_rdev = dev;
+	bh.b_rsector = sector;
+	bh.b_state	= (1 << BH_Req) | (1 << BH_Mapped);
+	bh.b_size = size;
+	bh.b_page = page;
+	bh.b_reqnext = NULL;
+	bh.b_data = page_address(page);
+	generic_make_request(rw, &bh);
+
+	run_task_queue(&tq_disk);
+	wait_for_completion(&event);
+
+	return test_bit(BH_Uptodate, &bh.b_state);
+}
+
 static int read_disk_sb(mdk_rdev_t * rdev)
 {
 	int ret = -EINVAL;
-	struct buffer_head *bh = NULL;
 	kdev_t dev = rdev->dev;
-	mdp_super_t *sb;
 	unsigned long sb_offset;
 
 	if (!rdev->sb) {
@@ -487,22 +519,14 @@
 	 */
 	sb_offset = calc_dev_sboffset(rdev->dev, rdev->mddev, 1);
 	rdev->sb_offset = sb_offset;
-	fsync_dev(dev);
-	set_blocksize (dev, MD_SB_BYTES);
-	bh = bread (dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES);
-
-	if (bh) {
-		sb = (mdp_super_t *) bh->b_data;
-		memcpy (rdev->sb, sb, MD_SB_BYTES);
-	} else {
-		printk(NO_SB,partition_name(rdev->dev));
-		goto abort;
+
+	if (!sync_page_io(dev, sb_offset<<1, MD_SB_BYTES, rdev->sb_page, READ)) {
+		printk(NO_SB,partition_name(dev));
+		return -EINVAL;
 	}
 	printk(KERN_INFO " [events: %08lx]\n", (unsigned long)rdev->sb->events_lo);
 	ret = 0;
 abort:
-	if (bh)
-		brelse (bh);
 	return ret;
 }
 
@@ -890,10 +914,8 @@
 
 static int write_disk_sb(mdk_rdev_t * rdev)
 {
-	struct buffer_head *bh;
 	kdev_t dev;
 	unsigned long sb_offset, size;
-	mdp_super_t *sb;
 
 	if (!rdev->sb) {
 		MD_BUG();
@@ -928,23 +950,11 @@
 	}
 
 	printk(KERN_INFO "(write) %s's sb offset: %ld\n", partition_name(dev), sb_offset);
-	fsync_dev(dev);
-	set_blocksize(dev, MD_SB_BYTES);
-	bh = getblk(dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES);
-	if (!bh) {
-		printk(GETBLK_FAILED, partition_name(dev));
+
+	if (!sync_page_io(dev, sb_offset<<1, MD_SB_BYTES, rdev->sb_page, WRITE)) {
+		printk("md: write_disk_sb failed for device %s\n", partition_name(dev));
 		return 1;
 	}
-	memset(bh->b_data,0,bh->b_size);
-	sb = (mdp_super_t *) bh->b_data;
-	memcpy(sb, rdev->sb, MD_SB_BYTES);
-
-	mark_buffer_uptodate(bh, 1);
-	mark_buffer_dirty(bh);
-	ll_rw_block(WRITE, 1, &bh);
-	wait_on_buffer(bh);
-	brelse(bh);
-	fsync_dev(dev);
 skip:
 	return 0;
 }
@@ -1038,7 +1048,11 @@
 			printk("(skipping faulty ");
 		if (rdev->alias_device)
 			printk("(skipping alias ");
-
+		if (disk_faulty(&rdev->sb->this_disk)) {
+			printk("(skipping new-faulty %s )\n",
+			       partition_name(rdev->dev));
+			continue;
+		}
 		printk("%s ", partition_name(rdev->dev));
 		if (!rdev->faulty && !rdev->alias_device) {
 			printk("[events: %08lx]",
@@ -1065,7 +1079,6 @@
  *   - the device is nonexistent (zero size)
  *   - the device has no valid superblock
  *
- * a faulty rdev _never_ has rdev->sb set.
  */
 static int md_import_device(kdev_t newdev, int on_disk)
 {
@@ -1137,8 +1150,6 @@
 	md_list_add(&rdev->all, &all_raid_disks);
 	MD_INIT_LIST_HEAD(&rdev->pending);
 
-	if (rdev->faulty && rdev->sb)
-		free_disk_sb(rdev);
 	return 0;
 
 abort_free:
@@ -2337,20 +2348,16 @@
 		return -EINVAL;
 	}
 	disk = &mddev->sb->disks[rdev->desc_nr];
-	if (disk_active(disk)) {
-		MD_BUG();
+	if (disk_active(disk))
 		goto busy;
-	}
-	if (disk_removed(disk)) {
-		MD_BUG();
+
+	if (disk_removed(disk))
 		return -EINVAL;
-	}
 
 	err = mddev->pers->diskop(mddev, &disk, DISKOP_HOT_REMOVE_DISK);
-	if (err == -EBUSY) {
-		MD_BUG();
+	if (err == -EBUSY)
 		goto busy;
-	}
+
 	if (err) {
 		MD_BUG();
 		return -EINVAL;
@@ -3056,7 +3063,6 @@
 		return 0;
 	if (!mddev->pers->error_handler
 			|| mddev->pers->error_handler(mddev,rdev) <= 0) {
-		free_disk_sb(rrdev);
 		rrdev->faulty = 1;
 	} else
 		return 1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/radio/Config.in linux-2.4.21/drivers/media/radio/Config.in
--- linux-2.4.20/drivers/media/radio/Config.in	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/media/radio/Config.in	2002-12-18 18:58:09.000000000 +0000
@@ -30,6 +30,7 @@
 if [ "$CONFIG_ISA" = "y" ]; then
    dep_tristate '    miroSOUND PCM20 radio RDS user interface (EXPERIMENTAL)' CONFIG_RADIO_MIROPCM20_RDS $CONFIG_RADIO_MIROPCM20 $CONFIG_EXPERIMENTAL
    dep_tristate '  SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV
+   dep_tristate '  SF16FMR2 Radio' CONFIG_RADIO_SF16FMR2 $CONFIG_VIDEO_DEV
    dep_tristate '  TerraTec ActiveRadio ISA Standalone' CONFIG_RADIO_TERRATEC $CONFIG_VIDEO_DEV
    if [ "$CONFIG_RADIO_TERRATEC" = "y" ]; then
       hex '    Terratec i/o port (normally 0x590)' CONFIG_RADIO_TERRATEC_PORT 590
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/radio/Makefile linux-2.4.21/drivers/media/radio/Makefile
--- linux-2.4.20/drivers/media/radio/Makefile	2001-08-05 20:15:05.000000000 +0000
+++ linux-2.4.21/drivers/media/radio/Makefile	2002-12-18 18:58:09.000000000 +0000
@@ -30,6 +30,7 @@
 obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o
 obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o
 obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o
+obj-$(CONFIG_RADIO_SF16FMR2) += radio-sf16fmr2.o
 obj-$(CONFIG_RADIO_CADET) += radio-cadet.o
 obj-$(CONFIG_RADIO_TYPHOON) += radio-typhoon.o
 obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/radio/radio-sf16fmr2.c linux-2.4.21/drivers/media/radio/radio-sf16fmr2.c
--- linux-2.4.20/drivers/media/radio/radio-sf16fmr2.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/media/radio/radio-sf16fmr2.c	2002-12-18 18:58:04.000000000 +0000
@@ -0,0 +1,473 @@
+/* SF16FMR2 radio driver for Linux radio support
+ * heavily based on fmi driver...
+ * (c) 2000-2002 Ziglio Frediano, freddy77@angelfire.com
+ *
+ * Notes on the hardware
+ *
+ *  Frequency control is done digitally -- ie out(port,encodefreq(95.8));
+ *  No volume control - only mute/unmute - you have to use line volume
+ *  
+ *  For read stereo/mono you must wait 0.1 sec after set frequency and 
+ *  card unmuted so I set frequency on unmute
+ *  Signal handling seem to work only on autoscanning (not implemented)
+ */
+
+#include <linux/module.h>	/* Modules 			*/
+#include <linux/init.h>		/* Initdata			*/
+#include <linux/ioport.h>	/* check_region, request_region	*/
+#include <linux/delay.h>	/* udelay			*/
+#include <asm/io.h>		/* outb, outb_p			*/
+#include <asm/uaccess.h>	/* copy to/from user		*/
+#include <linux/videodev.h>	/* kernel radio structs		*/
+#include <asm/semaphore.h>
+
+static struct semaphore lock;
+
+#undef DEBUG
+//#define DEBUG 1
+
+#ifdef DEBUG
+# define  debug_print(s) printk s
+#else
+# define  debug_print(s)
+#endif
+
+/* this should be static vars for module size */
+struct fmr2_device
+{
+	int port;
+	int curvol; /* 0-65535, if not volume 0 or 65535 */
+	int mute;
+	int stereo; /* card is producing stereo audio */
+	unsigned long curfreq; /* freq in kHz */
+	int card_type; 
+	__u32 flags;
+};
+
+static int io = 0x384; 
+static int radio_nr = -1;
+static int users = 0;
+
+/* hw precision is 12.5 kHz 
+ * It is only usefull to give freq in intervall of 200 (=0.0125Mhz),
+ * other bits will be truncated
+ */
+#define RSF16_ENCODE(x)	((x)/200+856)
+#define RSF16_MINFREQ 87*16000
+#define RSF16_MAXFREQ 108*16000
+
+/* from radio-aimslab */
+static void sleep_delay(unsigned long n)
+{
+	unsigned d=n/(1000000U/HZ);
+	if (!d)
+		udelay(n);
+	else
+	{
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(d);
+	}
+}
+
+static inline void wait(int n,int port)
+{
+	for (;n;--n) inb(port);
+}
+
+static void outbits(int bits, unsigned int data, int nWait, int port)
+{
+	int bit;
+	for(;--bits>=0;) {
+		bit = (data>>bits) & 1;
+		outb(bit,port);
+		wait(nWait,port);
+		outb(bit|2,port);
+		wait(nWait,port);
+		outb(bit,port);
+		wait(nWait,port);
+	}
+}
+
+static inline void fmr2_mute(int port)
+{
+	outb(0x00, port);
+	wait(4,port);
+}
+
+static inline void fmr2_unmute(int port)
+{
+	outb(0x04, port);
+	wait(4,port);
+}
+
+static inline int fmr2_stereo_mode(int port)
+{
+	int n = inb(port);
+	outb(6,port);
+	inb(port);
+	n = ((n>>3)&1)^1;
+	debug_print((KERN_DEBUG "stereo: %d\n", n));
+	return n;
+}
+
+static int fmr2_product_info(struct fmr2_device *dev)
+{
+	int n = inb(dev->port);
+	n &= 0xC1;
+	if (n == 0)
+	{
+		/* this should support volume set */
+		dev->card_type = 12;
+		return 0;
+	}
+	/* not volume (mine is 11) */
+	dev->card_type = (n==128)?11:0;
+	return n;
+}
+
+static inline int fmr2_getsigstr(struct fmr2_device *dev)
+{
+	/* !!! work only if scanning freq */
+	int port = dev->port, res = 0xffff;
+	outb(5,port);
+	wait(4,port);
+	if (!(inb(port)&1)) res = 0;
+	debug_print((KERN_DEBUG "signal: %d\n", res));
+	return res;
+}
+
+/* set frequency and unmute card */
+static int fmr2_setfreq(struct fmr2_device *dev)
+{
+	int port = dev->port;
+	unsigned long freq = dev->curfreq;
+
+	fmr2_mute(port);
+
+	/* 0x42 for mono output
+	 * 0x102 forward scanning
+	 * 0x182 scansione avanti 
+	 */
+	outbits(9,0x2,3,port);
+	outbits(16,RSF16_ENCODE(freq),2,port);
+
+	fmr2_unmute(port);
+
+	/* wait 0.11 sec */
+	sleep_delay(110000LU);
+
+	/* NOTE if mute this stop radio
+	   you must set freq on unmute */
+	dev->stereo = fmr2_stereo_mode(port);
+	return 0;
+}
+
+/* !!! not tested, in my card this does't work !!! */
+static int fmr2_setvolume(struct fmr2_device *dev)
+{
+	int i,a,n, port = dev->port;
+
+	if (dev->card_type != 11) return 1;
+
+	switch( (dev->curvol+(1<<11)) >> 12 )
+	{
+	case 0: case 1: n = 0x21; break;
+	case 2: n = 0x84; break;
+	case 3: n = 0x90; break;
+	case 4: n = 0x104; break;
+	case 5: n = 0x110; break;
+	case 6: n = 0x204; break;
+	case 7: n = 0x210; break;
+	case 8: n = 0x402; break;
+	case 9: n = 0x404; break;
+	default:
+	case 10: n = 0x408; break;
+	case 11: n = 0x410; break;
+	case 12: n = 0x801; break;
+	case 13: n = 0x802; break;
+	case 14: n = 0x804; break;
+	case 15: n = 0x808; break;
+	case 16: n = 0x810; break;
+	}
+	for(i=12;--i>=0;)
+	{
+		a = ((n >> i) & 1) << 6; /* if (a=0) a= 0; else a= 0x40; */
+		outb(a|4, port);
+		wait(4,port);
+		outb(a|0x24, port);
+		wait(4,port);
+		outb(a|4, port);
+		wait(4,port);
+	}
+	for(i=6;--i>=0;)
+	{
+		a = ((0x18 >> i) & 1) << 6;
+		outb(a|4, port);
+		wait(4,port);
+		outb(a|0x24, port);
+		wait(4,port);
+		outb(a|4, port);
+		wait(4,port);
+	}
+	wait(4,port);
+	outb(0x14, port);
+
+	return 0;
+}
+
+static int fmr2_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+	struct fmr2_device *fmr2=dev->priv;
+	debug_print((KERN_DEBUG "freq %ld flags %d vol %d mute %d "
+		"stereo %d type %d\n",
+		fmr2->curfreq, fmr2->flags, fmr2->curvol, fmr2->mute, 
+		fmr2->stereo, fmr2->card_type));
+	
+	switch(cmd)
+	{
+		case VIDIOCGCAP:
+		{
+			struct video_capability v;
+			strcpy(v.name, "SF16-FMR2 radio");
+			v.type=VID_TYPE_TUNER;
+			v.channels=1;
+			v.audios=1;
+			/* No we don't do pictures */
+			v.maxwidth=0;
+			v.maxheight=0;
+			v.minwidth=0;
+			v.minheight=0;
+			if(copy_to_user(arg,&v,sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCGTUNER:
+		{
+			struct video_tuner v;
+			int mult;
+
+			if(copy_from_user(&v, arg,sizeof(v))!=0)
+				return -EFAULT;
+			if(v.tuner)	/* Only 1 tuner */
+				return -EINVAL;
+			strcpy(v.name, "FM");
+			mult = (fmr2->flags & VIDEO_TUNER_LOW) ? 1 : 1000;
+			v.rangelow = RSF16_MINFREQ/mult;
+			v.rangehigh = RSF16_MAXFREQ/mult;
+			v.flags = fmr2->flags | VIDEO_AUDIO_MUTABLE;
+			if (fmr2->mute)
+				v.flags |= VIDEO_AUDIO_MUTE;
+			v.mode=VIDEO_MODE_AUTO;
+			down(&lock);
+			v.signal = fmr2_getsigstr(fmr2);
+			up(&lock);
+			if(copy_to_user(arg,&v, sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCSTUNER:
+		{
+			struct video_tuner v;
+			if(copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+			if(v.tuner!=0)
+				return -EINVAL;
+			fmr2->flags = v.flags & VIDEO_TUNER_LOW;
+			return 0;
+		}
+		case VIDIOCGFREQ:
+		{
+			unsigned long tmp = fmr2->curfreq;
+			if (!(fmr2->flags & VIDEO_TUNER_LOW))
+				tmp /= 1000;
+			if(copy_to_user(arg, &tmp, sizeof(tmp)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCSFREQ:
+		{
+			unsigned long tmp;
+			if(copy_from_user(&tmp, arg, sizeof(tmp)))
+				return -EFAULT;
+			if (!(fmr2->flags & VIDEO_TUNER_LOW))
+				tmp *= 1000;
+			if ( tmp<RSF16_MINFREQ || tmp>RSF16_MAXFREQ )
+				return -EINVAL;
+			/* rounding in steps of 200 to match th freq
+			 * that will be used 
+			 */
+			fmr2->curfreq = (tmp/200)*200; 
+
+			/* set card freq (if not muted) */
+			if (fmr2->curvol && !fmr2->mute)
+			{
+				down(&lock);
+				fmr2_setfreq(fmr2);
+				up(&lock);
+			}
+			return 0;
+		}
+		case VIDIOCGAUDIO:
+		{
+			struct video_audio v;
+			v.audio=0;
+			v.volume=0;
+			v.bass=0;
+			v.treble=0;
+			/* !!! do not return VIDEO_AUDIO_MUTE */
+			v.flags = VIDEO_AUDIO_MUTABLE;
+			strcpy(v.name, "Radio");
+			/* get current stereo mode */
+			v.mode = fmr2->stereo ? VIDEO_SOUND_STEREO: VIDEO_SOUND_MONO;
+			v.balance = 0;
+			v.step=0; /* No volume, just (un)mute */
+			/* volume supported ? */
+			if (fmr2->card_type == 11)
+			{
+				v.flags |= VIDEO_AUDIO_VOLUME;
+				v.step = 1 << 12;
+				v.volume = fmr2->curvol;
+			}
+			debug_print((KERN_DEBUG "Get flags %d vol %d\n", v.flags, v.volume));
+			if(copy_to_user(arg,&v, sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCSAUDIO:
+		{
+			struct video_audio v;
+			if(copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+			if(v.audio)
+				return -EINVAL;
+			debug_print((KERN_DEBUG "Set flags %d vol %d\n", v.flags, v.volume));
+			/* set volume */
+			if (v.flags & VIDEO_AUDIO_VOLUME)
+				fmr2->curvol = v.volume; /* !!! set with precision */
+			if (fmr2->card_type != 11) fmr2->curvol = 65535;
+			fmr2->mute = 0;
+			if (v.flags&VIDEO_AUDIO_MUTE)
+				fmr2->mute = 1;
+#ifdef DEBUG
+			if (fmr2->curvol && !fmr2->mute)
+				printk(KERN_DEBUG "unmute\n");
+			else
+				printk(KERN_DEBUG "mute\n");
+#endif
+			down(&lock);
+			if (fmr2->curvol && !fmr2->mute)
+			{
+				fmr2_setvolume(fmr2);
+				fmr2_setfreq(fmr2);
+			}
+			else fmr2_mute(fmr2->port);
+			up(&lock);
+			return 0;
+		}
+		case VIDIOCGUNIT:
+		{
+			struct video_unit v;
+			v.video=VIDEO_NO_UNIT;
+			v.vbi=VIDEO_NO_UNIT;
+			v.radio=dev->minor;
+			v.audio=0; /* How do we find out this??? */
+			v.teletext=VIDEO_NO_UNIT;
+			if(copy_to_user(arg, &v, sizeof(v)))
+				return -EFAULT;
+			return 0;			
+		}
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+static int fmr2_open(struct video_device *dev, int flags)
+{
+	if(users)
+		return -EBUSY;
+	users++;
+	return 0;
+}
+
+static void fmr2_close(struct video_device *dev)
+{
+	users--;
+}
+
+static struct fmr2_device fmr2_unit;
+
+static struct video_device fmr2_radio=
+{
+	owner:		THIS_MODULE,
+	name:		"SF16FMR2 radio",
+	type:		VID_TYPE_TUNER,
+	hardware:	VID_HARDWARE_SF16FMR2,
+	open:		fmr2_open,
+	close:		fmr2_close,
+	ioctl:		fmr2_ioctl,
+};
+
+static int __init fmr2_init(void)
+{
+	if (check_region(io, 2)) 
+	{
+		printk(KERN_ERR "fmr2: port 0x%x already in use\n", io);
+		return -EBUSY;
+	}
+
+	fmr2_unit.port = io;
+	fmr2_unit.curvol = 0;
+	fmr2_unit.mute = 0;
+	fmr2_unit.curfreq = 0;
+	fmr2_unit.stereo = 1;
+	fmr2_unit.flags = VIDEO_TUNER_LOW;
+	fmr2_unit.card_type = 0;
+	fmr2_radio.priv = &fmr2_unit;
+
+	init_MUTEX(&lock);
+
+	if(video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr)==-1)
+		return -EINVAL;
+
+	request_region(io, 2, "fmr2");
+	printk(KERN_INFO "SF16FMR2 radio card driver at 0x%x.\n", io);
+	debug_print((KERN_DEBUG "Mute %d Low %d\n",VIDEO_AUDIO_MUTE,VIDEO_TUNER_LOW));
+	/* mute card - prevents noisy bootups */
+	down(&lock);
+	fmr2_mute(io);
+	fmr2_product_info(&fmr2_unit);
+	up(&lock);
+	debug_print((KERN_DEBUG "card_type %d\n", fmr2_unit.card_type));
+	return 0;
+}
+
+MODULE_AUTHOR("Ziglio Frediano, freddy77@angelfire.com");
+MODULE_DESCRIPTION("A driver for the SF16FMR2 radio.");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "I/O address of the SF16FMR2 card (should be 0x384, if do not work try 0x284)");
+MODULE_PARM(radio_nr, "i");
+
+EXPORT_NO_SYMBOLS;
+
+static void __exit fmr2_cleanup_module(void)
+{
+	video_unregister_device(&fmr2_radio);
+	release_region(io,2);
+}
+
+module_init(fmr2_init);
+module_exit(fmr2_cleanup_module);
+
+#ifndef MODULE
+
+static int __init fmr2_setup_io(char *str)
+{
+	get_option(&str, &io);
+	return 1;
+}
+
+__setup("sf16fmr2=", fmr2_setup_io);
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/Config.in linux-2.4.21/drivers/media/video/Config.in
--- linux-2.4.20/drivers/media/video/Config.in	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.21/drivers/media/video/Config.in	2002-12-18 18:58:09.000000000 +0000
@@ -49,7 +49,7 @@
 dep_tristate '  Linux Media Labs LML33 support' CONFIG_VIDEO_ZORAN_LML33 $CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C
 dep_tristate '  Zoran ZR36120/36125 Video For Linux' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  dep_tristate '  Sony Vaio Picturebook Motion Eye Video For Linux' CONFIG_VIDEO_MEYE $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_SONYPI
+  dep_tristate '  Sony Vaio Picturebook Motion Eye Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_MEYE $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_SONYPI
 fi
 
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/bttv-cards.c linux-2.4.21/drivers/media/video/bttv-cards.c
--- linux-2.4.20/drivers/media/video/bttv-cards.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/media/video/bttv-cards.c	2002-12-18 18:58:08.000000000 +0000
@@ -2457,6 +2457,17 @@
 			command |= BT878_EN_VSFX;
                 pci_write_config_byte(btv->dev, BT878_DEVCTRL, command);
         }
+        if(pci_pci_problems & PCIPCI_ALIMAGIK)
+        {
+        	u8 latency;
+        	/* Must cut the latency down */
+        	pci_read_config_byte(btv->dev, PCI_LATENCY_TIMER, &latency);
+        	if(latency > 0x0A)
+        	{
+        		pci_write_config_byte(btv->dev, PCI_LATENCY_TIMER, 0x0A);
+        		printk(KERN_INFO "bttv: reduced PCI latency to 0x0A.\n");
+        	}
+        }
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/meye.c linux-2.4.21/drivers/media/video/meye.c
--- linux-2.4.20/drivers/media/video/meye.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/media/video/meye.c	2002-12-18 18:58:02.000000000 +0000
@@ -1,7 +1,9 @@
 /* 
  * Motion Eye video4linux driver for Sony Vaio PictureBook
  *
- * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ * Copyright (C) 2001-2002 Stelian Pop <stelian@popies.net>
+ *
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
  *
  * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
  *
@@ -169,16 +171,28 @@
 	meye.mchip_ptable[MCHIP_NB_PAGES] = pci_alloc_consistent(meye.mchip_dev, 
 								 PAGE_SIZE, 
 								 &meye.mchip_dmahandle);
-	if (!meye.mchip_ptable[MCHIP_NB_PAGES])
+	if (!meye.mchip_ptable[MCHIP_NB_PAGES]) {
+		meye.mchip_dmahandle = 0;
 		return -1;
+	}
 
 	pt = (u32 *)meye.mchip_ptable[MCHIP_NB_PAGES];
 	for (i = 0; i < MCHIP_NB_PAGES; i++) {
 		meye.mchip_ptable[i] = pci_alloc_consistent(meye.mchip_dev, 
 							    PAGE_SIZE,
 							    pt);
-		if (!meye.mchip_ptable[i])
+		if (!meye.mchip_ptable[i]) {
+			int j;
+			pt = (u32 *)meye.mchip_ptable[MCHIP_NB_PAGES];
+			for (j = 0; j < i; ++j) {
+				pci_free_consistent(meye.mchip_dev,
+						    PAGE_SIZE,
+						    meye.mchip_ptable[j], *pt);
+				pt++;
+			}
+			meye.mchip_dmahandle = 0;
 			return -1;
+		}
 		pt++;
 	}
 	return 0;
@@ -189,11 +203,13 @@
 	int i;
 
 	pt = (u32 *)meye.mchip_ptable[MCHIP_NB_PAGES];
-	for (i = 0; i < MCHIP_NB_PAGES; i++)
+	for (i = 0; i < MCHIP_NB_PAGES; i++) {
 		if (meye.mchip_ptable[i])
 			pci_free_consistent(meye.mchip_dev, 
 					    PAGE_SIZE, 
 					    meye.mchip_ptable[i], *pt);
+		pt++;
+	}
 
 	if (meye.mchip_ptable[MCHIP_NB_PAGES])
 		pci_free_consistent(meye.mchip_dev, 
@@ -569,6 +585,16 @@
 	mchip_load_tables();
 }
 
+/* sets the DMA parameters into the chip */
+static void mchip_dma_setup(u32 dma_addr) {
+	int i;
+
+	mchip_set(MCHIP_MM_PT_ADDR, dma_addr);
+	for (i = 0; i < 4; i++)
+		mchip_set(MCHIP_MM_FIR(i), 0);
+	meye.mchip_fnum = 0;
+}
+
 /* setup for DMA transfers - also zeros the framebuffer */
 static int mchip_dma_alloc(void) {
 	if (!meye.mchip_dmahandle)
@@ -579,18 +605,10 @@
 
 /* frees the DMA buffer */
 static void mchip_dma_free(void) {
-	if (meye.mchip_dmahandle)
+	if (meye.mchip_dmahandle) {
+		mchip_dma_setup(0);
 		ptable_free();
-}
-
-/* sets the DMA parameters into the chip */
-static void mchip_dma_setup(void) {
-	int i;
-
-	mchip_set(MCHIP_MM_PT_ADDR, meye.mchip_dmahandle);
-	for (i = 0; i < 4; i++)
-		mchip_set(MCHIP_MM_FIR(i), 0);
-	meye.mchip_fnum = 0;
+	}
 }
 
 /* stop any existing HIC action and wait for any dma to complete then
@@ -698,7 +716,7 @@
 	
 	mchip_hic_stop();
 	mchip_subsample();
-	mchip_dma_setup();
+	mchip_dma_setup(meye.mchip_dmahandle);
 
 	mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_CAP);
 	mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START);
@@ -741,7 +759,7 @@
 	mchip_hic_stop();
 	mchip_subsample();
 	mchip_set_framerate();
-	mchip_dma_setup();
+	mchip_dma_setup(meye.mchip_dmahandle);
 
 	meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT;
 
@@ -801,7 +819,7 @@
 	mchip_vrj_setup(0x3f);
 	mchip_subsample();
 	mchip_set_framerate();
-	mchip_dma_setup();
+	mchip_dma_setup(meye.mchip_dmahandle);
 
 	meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP;
 
@@ -823,7 +841,7 @@
 	while (1) {
 		v = mchip_get_frame();
 		if (!(v & MCHIP_MM_FIR_RDY))
-			goto out;
+			return;
 		switch (meye.mchip_mode) {
 
 		case MCHIP_HIC_MODE_CONT_OUT:
@@ -856,12 +874,11 @@
 
 		default:
 			/* do not free frame, since it can be a snap */
-			goto out;
+			return;
 		} /* switch */
 
 		mchip_free_frame();
 	}
-out: ;
 }
 
 /****************************************************************************/
@@ -889,6 +906,7 @@
 
 static int meye_release(struct inode *inode, struct file *file) {
 	mchip_hic_stop();
+	mchip_dma_free();
 	video_exclusive_release(inode,file);
 	return 0;
 }
@@ -957,7 +975,6 @@
 
 	case VIDIOCSYNC: {
 		int *i = arg;
-		DECLARE_WAITQUEUE(wait, current);
 
 		if (*i < 0 || *i >= gbuffers)
 			return -EINVAL;
@@ -967,18 +984,9 @@
 		case MEYE_BUF_UNUSED:
 			return -EINVAL;
 		case MEYE_BUF_USING:
-			add_wait_queue(&meye.grabq.proc_list, &wait);
-			current->state = TASK_INTERRUPTIBLE;
-			while (meye.grab_buffer[*i].state == MEYE_BUF_USING) {
-				schedule();
-				if(signal_pending(current)) {
-					remove_wait_queue(&meye.grabq.proc_list, &wait);
-					current->state = TASK_RUNNING;
-					return -EINTR;
-				}
-			}
-			remove_wait_queue(&meye.grabq.proc_list, &wait);
-			current->state = TASK_RUNNING;
+			if (wait_event_interruptible(meye.grabq.proc_list,
+						     (meye.grab_buffer[*i].state != MEYE_BUF_USING)))
+				return -EINTR;
 			/* fall through */
 		case MEYE_BUF_DONE:
 			meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
@@ -1095,7 +1103,6 @@
 
 	case MEYEIOC_SYNC: {
 		int *i = arg;
-		DECLARE_WAITQUEUE(wait, current);
 
 		if (*i < 0 || *i >= gbuffers)
 			return -EINVAL;
@@ -1105,18 +1112,9 @@
 		case MEYE_BUF_UNUSED:
 			return -EINVAL;
 		case MEYE_BUF_USING:
-			add_wait_queue(&meye.grabq.proc_list, &wait);
-			current->state = TASK_INTERRUPTIBLE;
-			while (meye.grab_buffer[*i].state == MEYE_BUF_USING) {
-				schedule();
-				if(signal_pending(current)) {
-					remove_wait_queue(&meye.grabq.proc_list, &wait);
-					current->state = TASK_RUNNING;
-					return -EINTR;
-				}
-			}
-			remove_wait_queue(&meye.grabq.proc_list, &wait);
-			current->state = TASK_RUNNING;
+			if (wait_event_interruptible(meye.grabq.proc_list,
+						     (meye.grab_buffer[*i].state != MEYE_BUF_USING)))
+				return -EINTR;
 			/* fall through */
 		case MEYE_BUF_DONE:
 			meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
@@ -1211,20 +1209,20 @@
 }
 
 static struct file_operations meye_fops = {
-	owner:		THIS_MODULE,
-	open:		meye_open,
-	release:	meye_release,
-	mmap:		meye_mmap,
-	ioctl:		meye_ioctl,
-	llseek:		no_llseek,
+	.owner		= THIS_MODULE,
+	.open		= meye_open,
+	.release	= meye_release,
+	.mmap		= meye_mmap,
+	.ioctl		= meye_ioctl,
+	.llseek		= no_llseek,
 };
 
 static struct video_device meye_template = {
-	owner:		THIS_MODULE,
-	name:		"meye",
-	type:		VID_TYPE_CAPTURE,
-	hardware:	VID_HARDWARE_MEYE,
-	fops:		&meye_fops,
+	.owner		= THIS_MODULE,
+	.name		= "meye",
+	.type		= VID_TYPE_CAPTURE,
+	.hardware	= VID_HARDWARE_MEYE,
+	.fops		= &meye_fops,
 };
 
 static int __devinit meye_probe(struct pci_dev *pcidev, 
@@ -1244,15 +1242,9 @@
 	meye.mchip_dev = pcidev;
 	memcpy(&meye.video_dev, &meye_template, sizeof(meye_template));
 
-	if (mchip_dma_alloc()) {
-		printk(KERN_ERR "meye: mchip framebuffer allocation failed\n");
-		ret = -ENOMEM;
-		goto out2;
-	}
-
 	if ((ret = pci_enable_device(meye.mchip_dev))) {
 		printk(KERN_ERR "meye: pci_enable_device failed\n");
-		goto out3;
+		goto out2;
 	}
 
 	meye.mchip_irq = pcidev->irq;
@@ -1260,14 +1252,14 @@
 	if (!mchip_adr) {
 		printk(KERN_ERR "meye: mchip has no device base address\n");
 		ret = -EIO;
-		goto out4;
+		goto out3;
 	}
 	if (!request_mem_region(pci_resource_start(meye.mchip_dev, 0),
 			        pci_resource_len(meye.mchip_dev, 0),
 				"meye")) {
 		ret = -EIO;
 		printk(KERN_ERR "meye: request_mem_region failed\n");
-		goto out4;
+		goto out3;
 	}
 
 	pci_read_config_byte(meye.mchip_dev, PCI_REVISION_ID, &revision);
@@ -1280,14 +1272,14 @@
 	if ((ret = request_irq(meye.mchip_irq, meye_irq, 
 			       SA_INTERRUPT | SA_SHIRQ, "meye", meye_irq))) {
 		printk(KERN_ERR "meye: request_irq failed (ret=%d)\n", ret);
-		goto out5;
+		goto out4;
 	}
 
 	meye.mchip_mmregs = ioremap(mchip_adr, MCHIP_MM_REGS);
 	if (!meye.mchip_mmregs) {
 		printk(KERN_ERR "meye: ioremap failed\n");
 		ret = -EIO;
-		goto out6;
+		goto out5;
 	}
 	
 	/* Ask the camera to perform a soft reset. */
@@ -1309,7 +1301,7 @@
 
 		printk(KERN_ERR "meye: video_register_device failed\n");
 		ret = -EIO;
-		goto out7;
+		goto out6;
 	}
 	
 	printk(KERN_INFO "meye: Motion Eye Camera Driver v%d.%d.\n",
@@ -1343,17 +1335,15 @@
 	sonypi_camera_command(SONYPI_COMMAND_SETCAMERAAGC, 48);
 
 	return 0;
-out7:
-	iounmap(meye.mchip_mmregs);
 out6:
-	free_irq(meye.mchip_irq, meye_irq);
+	iounmap(meye.mchip_mmregs);
 out5:
+	free_irq(meye.mchip_irq, meye_irq);
+out4:
 	release_mem_region(pci_resource_start(meye.mchip_dev, 0),
 			   pci_resource_len(meye.mchip_dev, 0));
-out4:
-	pci_disable_device(meye.mchip_dev);
 out3:
-	mchip_dma_free();
+	pci_disable_device(meye.mchip_dev);
 out2:
 	sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 0);
 out1:
@@ -1371,7 +1361,6 @@
 
 	free_irq(meye.mchip_irq, meye_irq);
 
-
 	iounmap(meye.mchip_mmregs);
 
 	release_mem_region(pci_resource_start(meye.mchip_dev, 0),
@@ -1398,10 +1387,10 @@
 MODULE_DEVICE_TABLE(pci, meye_pci_tbl);
 
 static struct pci_driver meye_driver = {
-	name:		"meye",
-	id_table:	meye_pci_tbl,
-	probe:		meye_probe,
-	remove:		__devexit_p(meye_remove),
+	.name		= "meye",
+	.id_table	= meye_pci_tbl,
+	.probe		= meye_probe,
+	.remove		= __devexit_p(meye_remove),
 };
 
 static int __init meye_init_module(void) {
@@ -1441,7 +1430,7 @@
 __setup("meye=", meye_setup);
 #endif
 
-MODULE_AUTHOR("Stelian Pop <stelian.pop@fr.alcove.com>");
+MODULE_AUTHOR("Stelian Pop <stelian@popies.net>");
 MODULE_DESCRIPTION("video4linux driver for the MotionEye camera");
 MODULE_LICENSE("GPL");
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/meye.h linux-2.4.21/drivers/media/video/meye.h
--- linux-2.4.20/drivers/media/video/meye.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/media/video/meye.h	2002-12-18 18:58:09.000000000 +0000
@@ -1,7 +1,9 @@
 /* 
  * Motion Eye video4linux driver for Sony Vaio PictureBook
  *
- * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ * Copyright (C) 2001-2002 Stelian Pop <stelian@popies.net>
+ *
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
  *
  * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
  *
@@ -29,7 +31,7 @@
 #define _MEYE_PRIV_H_
 
 #define MEYE_DRIVER_MAJORVERSION	1
-#define MEYE_DRIVER_MINORVERSION	4
+#define MEYE_DRIVER_MINORVERSION	5
 
 /****************************************************************************/
 /* Motion JPEG chip registers                                               */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/pms.c linux-2.4.21/drivers/media/video/pms.c
--- linux-2.4.20/drivers/media/video/pms.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/media/video/pms.c	2002-12-18 18:58:05.000000000 +0000
@@ -622,7 +622,7 @@
 }
 
 
-static int pms_capture(struct pms_device *dev, char *buf, int rgb555, int count)
+static int pms_capture(struct pms_device *dev, char *buf, int rgb555, unsigned long count)
 {
 	int y;
 	int dw = 2*dev->width;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/Config.in linux-2.4.21/drivers/message/fusion/Config.in
--- linux-2.4.20/drivers/message/fusion/Config.in	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/message/fusion/Config.in	2002-12-18 18:58:05.000000000 +0000
@@ -10,6 +10,7 @@
   else
     define_bool CONFIG_FUSION_BOOT n
   fi
+  int  "  Maximum number of scatter gather entries" CONFIG_FUSION_MAX_SGE 40 
 
   if [ "$CONFIG_MODULES" = "y" ]; then
     #  How can we force these options to module or nothing?
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/linux_compat.h linux-2.4.21/drivers/message/fusion/linux_compat.h
--- linux-2.4.20/drivers/message/fusion/linux_compat.h	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/message/fusion/linux_compat.h	2002-12-18 18:58:06.000000000 +0000
@@ -252,6 +252,37 @@
         #define MPT_SCSI_USE_NEW_EH
 #endif
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
+#define mptscsih_lock(iocp, flags) \
+                spin_lock_irqsave(&iocp->FreeQlock, flags)
+#else
+#define mptscsih_lock(iocp, flags) \
+({	save_flags(flags); \
+	cli(); \
+})
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
+#define mptscsih_unlock(iocp, flags) \
+                spin_unlock_irqrestore(&iocp->FreeQlock, flags)
+#else
+#define mptscsih_unlock(iocp, flags)  restore_flags(flags);
+#endif
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
+#define mpt_work_struct work_struct 
+#define MPT_INIT_WORK(_task, _func, _data) INIT_WORK(_task, _func, _data)
+#else
+#define mpt_work_struct tq_struct 
+#define MPT_INIT_WORK(_task, _func, _data) \
+({	(_task)->sync = 0; \
+	(_task)->routine = (_func); \
+	(_task)->data = (void *) (_data); \
+})
+#endif
+
+
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif /* _LINUX_COMPAT_H */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/lsi/mpi.h linux-2.4.21/drivers/message/fusion/lsi/mpi.h
--- linux-2.4.20/drivers/message/fusion/lsi/mpi.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/message/fusion/lsi/mpi.h	2002-12-18 18:58:03.000000000 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
  *
  *
  *           Name:  MPI.H
  *          Title:  MPI Message independent structures and definitions
  *  Creation Date:  July 27, 2000
  *
- *    MPI Version:  01.02.03
+ *    MPI.H Version:  01.02.07
  *
  *  Version History
  *  ---------------
@@ -44,6 +44,10 @@
  *                      Added define MPI_FUNCTION_TOOLBOX.
  *  09-28-01  01.02.02  New function code MPI_SCSI_ENCLOSURE_PROCESSOR.
  *  11-01-01  01.02.03  Changed name to MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR.
+ *  03-14-02  01.02.04  Added MPI_HEADER_VERSION_ defines.
+ *  05-31-02  01.02.05  Bumped MPI_HEADER_VERSION_UNIT.
+ *  07-12-02  01.02.06  Added define for MPI_FUNCTION_MAILBOX.
+ *  09-16-02  01.02.07  Bumped value for MPI_HEADER_VERSION_UNIT.
  *  --------------------------------------------------------------------------
  */
 
@@ -59,10 +63,27 @@
 
 #define MPI_VERSION_MAJOR                   (0x01)
 #define MPI_VERSION_MINOR                   (0x02)
-#define MPI_VERSION            ((MPI_VERSION_MAJOR << 8) | MPI_VERSION_MINOR)
-
+#define MPI_VERSION_MAJOR_MASK              (0xFF00)
+#define MPI_VERSION_MAJOR_SHIFT             (8)
+#define MPI_VERSION_MINOR_MASK              (0x00FF)
+#define MPI_VERSION_MINOR_SHIFT             (0)
+#define MPI_VERSION ((MPI_VERSION_MAJOR << MPI_VERSION_MAJOR_SHIFT) |   \
+                                      MPI_VERSION_MINOR)
+
+#define MPI_VERSION_01_00                   (0x0100)
+#define MPI_VERSION_01_01                   (0x0101)
+#define MPI_VERSION_01_02                   (0x0102)
 /* Note: The major versions of 0xe0 through 0xff are reserved */
 
+/* versioning for this MPI header set */
+#define MPI_HEADER_VERSION_UNIT             (0x09)
+#define MPI_HEADER_VERSION_DEV              (0x00)
+#define MPI_HEADER_VERSION_UNIT_MASK        (0xFF00)
+#define MPI_HEADER_VERSION_UNIT_SHIFT       (8)
+#define MPI_HEADER_VERSION_DEV_MASK         (0x00FF)
+#define MPI_HEADER_VERSION_DEV_SHIFT        (0)
+#define MPI_HEADER_VERSION ((MPI_HEADER_VERSION_UNIT << 8) | MPI_HEADER_VERSION_DEV)
+
 /*****************************************************************************
 *
 *        I O C    S t a t e    D e f i n i t i o n s
@@ -228,6 +249,8 @@
 
 #define MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR       (0x18)
 
+#define MPI_FUNCTION_MAILBOX                        (0x19)
+
 #define MPI_FUNCTION_LAN_SEND                       (0x20)
 #define MPI_FUNCTION_LAN_RECEIVE                    (0x21)
 #define MPI_FUNCTION_LAN_RESET                      (0x22)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/lsi/mpi_cnfg.h linux-2.4.21/drivers/message/fusion/lsi/mpi_cnfg.h
--- linux-2.4.20/drivers/message/fusion/lsi/mpi_cnfg.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/message/fusion/lsi/mpi_cnfg.h	2002-12-18 18:58:09.000000000 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
  *
  *
  *           Name:  MPI_CNFG.H
  *          Title:  MPI Config message, structures, and Pages
  *  Creation Date:  July 27, 2000
  *
- *    MPI Version:  01.02.05
+ *    MPI_CNFG.H Version:  01.02.09
  *
  *  Version History
  *  ---------------
@@ -108,6 +108,26 @@
  *                      Added generic defines for hot spare pools and RAID
  *                      volume types.
  *  11-01-01 01.02.05   Added define for MPI_IOUNITPAGE1_DISABLE_IR.
+ *  03-14-02 01.02.06   Added PCISlotNum field to CONFIG_PAGE_IOC_1 along with
+ *                      related define, and bumped the page version define.
+ *  05-31-02 01.02.07   Added a Flags field to CONFIG_PAGE_IOC_2_RAID_VOL in a
+ *                      reserved byte and added a define.
+ *                      Added define for
+ *                      MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE.
+ *                      Added new config page: CONFIG_PAGE_IOC_5.
+ *                      Added MaxAliases, MaxHardAliases, and NumCurrentAliases
+ *                      fields to CONFIG_PAGE_FC_PORT_0.
+ *                      Added AltConnector and NumRequestedAliases fields to
+ *                      CONFIG_PAGE_FC_PORT_1.
+ *                      Added new config page: CONFIG_PAGE_FC_PORT_10.
+ *  07-12-02 01.02.08   Added more MPI_MANUFACTPAGE_DEVID_ defines.
+ *                      Added additional MPI_SCSIDEVPAGE0_NP_ defines.
+ *                      Added more MPI_SCSIDEVPAGE1_RP_ defines.
+ *                      Added define for
+ *                      MPI_SCSIDEVPAGE1_CONF_EXTENDED_PARAMS_ENABLE.
+ *                      Added new config page: CONFIG_PAGE_SCSI_DEVICE_3.
+ *                      Modified MPI_FCPORTPAGE5_FLAGS_ defines.
+ *  09-16-02 01.02.09   Added more MPI_SCSIDEVPAGE1_CONF_FORCE_PPR_MSG define.
  *  --------------------------------------------------------------------------
  */
 
@@ -266,6 +286,7 @@
 #define MPI_MANUFACTPAGE_DEVICEID_FC929             (0x0622)
 #define MPI_MANUFACTPAGE_DEVICEID_FC919X            (0x0628)
 #define MPI_MANUFACTPAGE_DEVICEID_FC929X            (0x0626)
+
 #define MPI_MANUFACTPAGE_DEVID_53C1030              (0x0030)
 #define MPI_MANUFACTPAGE_DEVID_53C1030ZC            (0x0031)
 #define MPI_MANUFACTPAGE_DEVID_1030_53C1035         (0x0032)
@@ -273,6 +294,12 @@
 #define MPI_MANUFACTPAGE_DEVID_53C1035              (0x0040)
 #define MPI_MANUFACTPAGE_DEVID_53C1035ZC            (0x0041)
 
+#define MPI_MANUFACTPAGE_DEVID_SA2010               (0x0804)
+#define MPI_MANUFACTPAGE_DEVID_SA2010ZC             (0x0805)
+#define MPI_MANUFACTPAGE_DEVID_SA2020               (0x0806)
+#define MPI_MANUFACTPAGE_DEVID_SA2020ZC             (0x0807)
+
+
 typedef struct _CONFIG_PAGE_MANUFACTURING_0
 {
     fCONFIG_PAGE_HEADER      Header;                     /* 00h */
@@ -481,14 +508,17 @@
     U32                     Flags;                      /* 04h */
     U32                     CoalescingTimeout;          /* 08h */
     U8                      CoalescingDepth;            /* 0Ch */
-    U8                      Reserved[3];                /* 0Dh */
+    U8                      PCISlotNum;                 /* 0Dh */
+    U8                      Reserved[2];                /* 0Eh */
 } fCONFIG_PAGE_IOC_1, MPI_POINTER PTR_CONFIG_PAGE_IOC_1,
   IOCPage1_t, MPI_POINTER pIOCPage1_t;
 
-#define MPI_IOCPAGE1_PAGEVERSION                        (0x00)
+#define MPI_IOCPAGE1_PAGEVERSION                        (0x01)
 
 #define MPI_IOCPAGE1_REPLY_COALESCING                   (0x00000001)
 
+#define MPI_IOCPAGE1_PCISLOTNUM_UNKNOWN                 (0xFF)
+
 
 typedef struct _CONFIG_PAGE_IOC_2_RAID_VOL
 {
@@ -497,11 +527,21 @@
     U8                          VolumeIOC;              /* 02h */
     U8                          VolumePageNumber;       /* 03h */
     U8                          VolumeType;             /* 04h */
-    U8                          Reserved2;              /* 05h */
+    U8                          Flags;                  /* 05h */
     U16                         Reserved3;              /* 06h */
 } fCONFIG_PAGE_IOC_2_RAID_VOL, MPI_POINTER PTR_CONFIG_PAGE_IOC_2_RAID_VOL,
   ConfigPageIoc2RaidVol_t, MPI_POINTER pConfigPageIoc2RaidVol_t;
 
+/* IOC Page 2 Volume RAID Type values, also used in RAID Volume pages */
+
+#define MPI_RAID_VOL_TYPE_IS                        (0x00)
+#define MPI_RAID_VOL_TYPE_IME                       (0x01)
+#define MPI_RAID_VOL_TYPE_IM                        (0x02)
+
+/* IOC Page 2 Volume Flags values */
+
+#define MPI_IOCPAGE2_FLAG_VOLUME_INACTIVE           (0x08)
+
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
  * one and check Header.PageLength at runtime.
@@ -522,7 +562,7 @@
 } fCONFIG_PAGE_IOC_2, MPI_POINTER PTR_CONFIG_PAGE_IOC_2,
   IOCPage2_t, MPI_POINTER pIOCPage2_t;
 
-#define MPI_IOCPAGE2_PAGEVERSION                        (0x01)
+#define MPI_IOCPAGE2_PAGEVERSION                        (0x02)
 
 /* IOC Page 2 Capabilities flags */
 
@@ -533,12 +573,6 @@
 #define MPI_IOCPAGE2_CAP_FLAGS_SAFTE_SUPPORT            (0x40000000)
 #define MPI_IOCPAGE2_CAP_FLAGS_CROSS_CHANNEL_SUPPORT    (0x80000000)
 
-/* IOC Page 2 Volume RAID Type values, also used in RAID Volume pages */
-
-#define MPI_RAID_VOL_TYPE_IS                        (0x00)
-#define MPI_RAID_VOL_TYPE_IME                       (0x01)
-#define MPI_RAID_VOL_TYPE_IM                        (0x02)
-
 
 typedef struct _IOC_3_PHYS_DISK
 {
@@ -599,6 +633,41 @@
 #define MPI_IOCPAGE4_PAGEVERSION                        (0x00)
 
 
+typedef struct _IOC_5_HOT_SPARE
+{
+    U8                          PhysDiskNum;            /* 00h */
+    U8                          Reserved;               /* 01h */
+    U8                          HotSparePool;           /* 02h */
+    U8                          Flags;                   /* 03h */
+} IOC_5_HOT_SPARE, MPI_POINTER PTR_IOC_5_HOT_SPARE,
+  Ioc5HotSpare_t, MPI_POINTER pIoc5HotSpare_t;
+
+/* IOC Page 5 HotSpare Flags */
+#define MPI_IOC_PAGE_5_HOT_SPARE_ACTIVE                 (0x01)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_IOC_PAGE_5_HOT_SPARE_MAX
+#define MPI_IOC_PAGE_5_HOT_SPARE_MAX        (1)
+#endif
+
+typedef struct _CONFIG_PAGE_IOC_5
+{
+    fCONFIG_PAGE_HEADER         Header;                         /* 00h */
+    U32                         Reserved1;                      /* 04h */
+    U8                          NumHotSpares;                   /* 08h */
+    U8                          Reserved2;                      /* 09h */
+    U16                         Reserved3;                      /* 0Ah */
+    IOC_5_HOT_SPARE             HotSpare[MPI_IOC_PAGE_5_HOT_SPARE_MAX]; /* 0Ch */
+} fCONFIG_PAGE_IOC_5, MPI_POINTER PTR_CONFIG_PAGE_IOC_5,
+  IOCPage5_t, MPI_POINTER pIOCPage5_t;
+
+#define MPI_IOCPAGE5_PAGEVERSION                        (0x00)
+
+
+
 /****************************************************************************
 *   SCSI Port Config Pages
 ****************************************************************************/
@@ -698,11 +767,16 @@
 } fCONFIG_PAGE_SCSI_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_0,
   SCSIDevicePage0_t, MPI_POINTER pSCSIDevicePage0_t;
 
-#define MPI_SCSIDEVPAGE0_PAGEVERSION                    (0x02)
+#define MPI_SCSIDEVPAGE0_PAGEVERSION                    (0x03)
 
 #define MPI_SCSIDEVPAGE0_NP_IU                          (0x00000001)
 #define MPI_SCSIDEVPAGE0_NP_DT                          (0x00000002)
 #define MPI_SCSIDEVPAGE0_NP_QAS                         (0x00000004)
+#define MPI_SCSIDEVPAGE0_NP_HOLD_MCS                    (0x00000008)
+#define MPI_SCSIDEVPAGE0_NP_WR_FLOW                     (0x00000010)
+#define MPI_SCSIDEVPAGE0_NP_RD_STRM                     (0x00000020)
+#define MPI_SCSIDEVPAGE0_NP_RTI                         (0x00000040)
+#define MPI_SCSIDEVPAGE0_NP_PCOMP_EN                    (0x00000080)
 #define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK        (0x0000FF00)
 #define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK        (0x00FF0000)
 #define MPI_SCSIDEVPAGE0_NP_WIDE                        (0x20000000)
@@ -723,21 +797,25 @@
 } fCONFIG_PAGE_SCSI_DEVICE_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_1,
   SCSIDevicePage1_t, MPI_POINTER pSCSIDevicePage1_t;
 
-#define MPI_SCSIDEVPAGE1_PAGEVERSION                    (0x03)
+#define MPI_SCSIDEVPAGE1_PAGEVERSION                    (0x04)
 
 #define MPI_SCSIDEVPAGE1_RP_IU                          (0x00000001)
 #define MPI_SCSIDEVPAGE1_RP_DT                          (0x00000002)
 #define MPI_SCSIDEVPAGE1_RP_QAS                         (0x00000004)
+#define MPI_SCSIDEVPAGE1_RP_HOLD_MCS                    (0x00000008)
+#define MPI_SCSIDEVPAGE1_RP_WR_FLOW                     (0x00000010)
+#define MPI_SCSIDEVPAGE1_RP_RD_STRM                     (0x00000020)
+#define MPI_SCSIDEVPAGE1_RP_RTI                         (0x00000040)
+#define MPI_SCSIDEVPAGE1_RP_PCOMP_EN                    (0x00000080)
 #define MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK        (0x0000FF00)
 #define MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK        (0x00FF0000)
 #define MPI_SCSIDEVPAGE1_RP_WIDE                        (0x20000000)
 #define MPI_SCSIDEVPAGE1_RP_AIP                         (0x80000000)
 
-#define MPI_SCSIDEVPAGE1_DV_LVD_DRIVE_STRENGTH_MASK     (0x00000003)
-#define MPI_SCSIDEVPAGE1_DV_SE_SLEW_RATE_MASK           (0x00000300)
-
 #define MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED           (0x00000002)
 #define MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED           (0x00000004)
+#define MPI_SCSIDEVPAGE1_CONF_EXTENDED_PARAMS_ENABLE    (0x00000008)
+#define MPI_SCSIDEVPAGE1_CONF_FORCE_PPR_MSG             (0x00000010)
 
 
 typedef struct _CONFIG_PAGE_SCSI_DEVICE_2
@@ -749,7 +827,7 @@
 } fCONFIG_PAGE_SCSI_DEVICE_2, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_2,
   SCSIDevicePage2_t, MPI_POINTER pSCSIDevicePage2_t;
 
-#define MPI_SCSIDEVPAGE2_PAGEVERSION                    (0x00)
+#define MPI_SCSIDEVPAGE2_PAGEVERSION                    (0x01)
 
 #define MPI_SCSIDEVPAGE2_DV_ISI_ENABLE                  (0x00000010)
 #define MPI_SCSIDEVPAGE2_DV_SECONDARY_DRIVER_ENABLE     (0x00000020)
@@ -781,6 +859,22 @@
 #define MPI_SCSIDEVPAGE2_DPS_BIT_15_PL_SELECT_MASK      (0xC0000000)
 
 
+typedef struct _CONFIG_PAGE_SCSI_DEVICE_3
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U16                     MsgRejectCount;             /* 04h */
+    U16                     PhaseErrorCount;            /* 06h */
+    U16                     ParityErrorCount;           /* 08h */
+    U16                     Reserved;                   /* 0Ah */
+} fCONFIG_PAGE_SCSI_DEVICE_3, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_3,
+  SCSIDevicePage3_t, MPI_POINTER pSCSIDevicePage3_t;
+
+#define MPI_SCSIDEVPAGE3_PAGEVERSION                    (0x00)
+
+#define MPI_SCSIDEVPAGE3_MAX_COUNTER                    (0xFFFE)
+#define MPI_SCSIDEVPAGE3_UNSUPPORTED_COUNTER            (0xFFFF)
+
+
 /****************************************************************************
 *   FC Port Config Pages
 ****************************************************************************/
@@ -804,10 +898,14 @@
     U64                     FabricWWPN;                 /* 38h */
     U32                     DiscoveredPortsCount;       /* 40h */
     U32                     MaxInitiators;              /* 44h */
+    U8                      MaxAliasesSupported;        /* 48h */
+    U8                      MaxHardAliasesSupported;    /* 49h */
+    U8                      NumCurrentAliases;          /* 4Ah */
+    U8                      Reserved1;                  /* 4Bh */
 } fCONFIG_PAGE_FC_PORT_0, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_0,
   FCPortPage0_t, MPI_POINTER pFCPortPage0_t;
 
-#define MPI_FCPORTPAGE0_PAGEVERSION                     (0x01)
+#define MPI_FCPORTPAGE0_PAGEVERSION                     (0x02)
 
 #define MPI_FCPORTPAGE0_FLAGS_PROT_MASK                 (0x0000000F)
 #define MPI_FCPORTPAGE0_FLAGS_PROT_FCP_INIT             (MPI_PORTFACTS_PROTOCOL_INITIATOR)
@@ -874,11 +972,14 @@
     U8                      HardALPA;                   /* 18h */
     U8                      LinkConfig;                 /* 19h */
     U8                      TopologyConfig;             /* 1Ah */
-    U8                      Reserved;                   /* 1Bh */
+    U8                      AltConnector;               /* 1Bh */
+    U8                      NumRequestedAliases;        /* 1Ch */
+    U8                      Reserved1;                  /* 1Dh */
+    U16                     Reserved2;                  /* 1Eh */
 } fCONFIG_PAGE_FC_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_1,
   FCPortPage1_t, MPI_POINTER pFCPortPage1_t;
 
-#define MPI_FCPORTPAGE1_PAGEVERSION                     (0x02)
+#define MPI_FCPORTPAGE1_PAGEVERSION                     (0x04)
 
 #define MPI_FCPORTPAGE1_FLAGS_EXT_FCP_STATUS_EN         (0x08000000)
 #define MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY     (0x04000000)
@@ -906,6 +1007,8 @@
 #define MPI_FCPORTPAGE1_TOPOLOGY_NPORT                  (0x02)
 #define MPI_FCPORTPAGE1_TOPOLOGY_AUTO                   (0x0F)
 
+#define MPI_FCPORTPAGE1_ALT_CONN_UNKNOWN                (0x00)
+
 
 typedef struct _CONFIG_PAGE_FC_PORT_2
 {
@@ -998,26 +1101,19 @@
   MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5_ALIAS_INFO,
   FcPortPage5AliasInfo_t, MPI_POINTER pFcPortPage5AliasInfo_t;
 
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength at runtime.
- */
-#ifndef MPI_FC_PORT_PAGE_5_ALIAS_MAX
-#define MPI_FC_PORT_PAGE_5_ALIAS_MAX        (1)
-#endif
-
 typedef struct _CONFIG_PAGE_FC_PORT_5
 {
-    fCONFIG_PAGE_HEADER                  Header;                     /* 00h */
-    fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO    AliasInfo[MPI_FC_PORT_PAGE_5_ALIAS_MAX];/* 04h */
+    fCONFIG_PAGE_HEADER                  Header;         /* 00h */
+    fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO    AliasInfo;      /* 04h */
 } fCONFIG_PAGE_FC_PORT_5, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5,
   FCPortPage5_t, MPI_POINTER pFCPortPage5_t;
 
-#define MPI_FCPORTPAGE5_PAGEVERSION                     (0x00)
-
-#define MPI_FCPORTPAGE5_FLAGS_ALIAS_ALPA_VALID          (0x01)
-#define MPI_FCPORTPAGE5_FLAGS_ALIAS_WWN_VALID           (0x02)
+#define MPI_FCPORTPAGE5_PAGEVERSION                     (0x01)
 
+#define MPI_FCPORTPAGE5_FLAGS_ALPA_ACQUIRED             (0x01)
+#define MPI_FCPORTPAGE5_FLAGS_HARD_ALPA                 (0x02)
+#define MPI_FCPORTPAGE5_FLAGS_HARD_WWNN                 (0x04)
+#define MPI_FCPORTPAGE5_FLAGS_HARD_WWPN                 (0x08)
 
 typedef struct _CONFIG_PAGE_FC_PORT_6
 {
@@ -1086,6 +1182,132 @@
 #define MPI_FCPORTPAGE9_PAGEVERSION                     (0x00)
 
 
+typedef struct _CONFIG_PAGE_FC_PORT_10_BASE_SFP_DATA
+{
+    U8                      Id;                         /* 10h */
+    U8                      ExtId;                      /* 11h */
+    U8                      Connector;                  /* 12h */
+    U8                      Transceiver[8];             /* 13h */
+    U8                      Encoding;                   /* 1Bh */
+    U8                      BitRate_100mbs;             /* 1Ch */
+    U8                      Reserved1;                  /* 1Dh */
+    U8                      Length9u_km;                /* 1Eh */
+    U8                      Length9u_100m;              /* 1Fh */
+    U8                      Length50u_10m;              /* 20h */
+    U8                      Length62p5u_10m;            /* 21h */
+    U8                      LengthCopper_m;             /* 22h */
+    U8                      Reseverved2;                /* 22h */
+    U8                      VendorName[16];             /* 24h */
+    U8                      Reserved3;                  /* 34h */
+    U8                      VendorOUI[3];               /* 35h */
+    U8                      VendorPN[16];               /* 38h */
+    U8                      VendorRev[4];               /* 48h */
+    U16                     Reserved4;                  /* 4Ch */
+    U8                      Reserved5;                  /* 4Eh */
+    U8                      CC_BASE;                    /* 4Fh */
+} fCONFIG_PAGE_FC_PORT_10_BASE_SFP_DATA,
+  MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_10_BASE_SFP_DATA,
+  FCPortPage10BaseSfpData_t, MPI_POINTER pFCPortPage10BaseSfpData_t;
+
+#define MPI_FCPORT10_BASE_ID_UNKNOWN        (0x00)
+#define MPI_FCPORT10_BASE_ID_GBIC           (0x01)
+#define MPI_FCPORT10_BASE_ID_FIXED          (0x02)
+#define MPI_FCPORT10_BASE_ID_SFP            (0x03)
+#define MPI_FCPORT10_BASE_ID_SFP_MIN        (0x04)
+#define MPI_FCPORT10_BASE_ID_SFP_MAX        (0x7F)
+#define MPI_FCPORT10_BASE_ID_VEND_SPEC_MASK (0x80)
+
+#define MPI_FCPORT10_BASE_EXTID_UNKNOWN     (0x00)
+#define MPI_FCPORT10_BASE_EXTID_MODDEF1     (0x01)
+#define MPI_FCPORT10_BASE_EXTID_MODDEF2     (0x02)
+#define MPI_FCPORT10_BASE_EXTID_MODDEF3     (0x03)
+#define MPI_FCPORT10_BASE_EXTID_SEEPROM     (0x04)
+#define MPI_FCPORT10_BASE_EXTID_MODDEF5     (0x05)
+#define MPI_FCPORT10_BASE_EXTID_MODDEF6     (0x06)
+#define MPI_FCPORT10_BASE_EXTID_MODDEF7     (0x07)
+#define MPI_FCPORT10_BASE_EXTID_VNDSPC_MASK (0x80)
+
+#define MPI_FCPORT10_BASE_CONN_UNKNOWN      (0x00)
+#define MPI_FCPORT10_BASE_CONN_SC           (0x01)
+#define MPI_FCPORT10_BASE_CONN_COPPER1      (0x02)
+#define MPI_FCPORT10_BASE_CONN_COPPER2      (0x03)
+#define MPI_FCPORT10_BASE_CONN_BNC_TNC      (0x04)
+#define MPI_FCPORT10_BASE_CONN_COAXIAL      (0x05)
+#define MPI_FCPORT10_BASE_CONN_FIBERJACK    (0x06)
+#define MPI_FCPORT10_BASE_CONN_LC           (0x07)
+#define MPI_FCPORT10_BASE_CONN_MT_RJ        (0x08)
+#define MPI_FCPORT10_BASE_CONN_MU           (0x09)
+#define MPI_FCPORT10_BASE_CONN_SG           (0x0A)
+#define MPI_FCPORT10_BASE_CONN_OPT_PIGT     (0x0B)
+#define MPI_FCPORT10_BASE_CONN_RSV1_MIN     (0x0C)
+#define MPI_FCPORT10_BASE_CONN_RSV1_MAX     (0x1F)
+#define MPI_FCPORT10_BASE_CONN_HSSDC_II     (0x20)
+#define MPI_FCPORT10_BASE_CONN_CPR_PIGT     (0x21)
+#define MPI_FCPORT10_BASE_CONN_RSV2_MIN     (0x22)
+#define MPI_FCPORT10_BASE_CONN_RSV2_MAX     (0x7F)
+#define MPI_FCPORT10_BASE_CONN_VNDSPC_MASK  (0x80)
+
+#define MPI_FCPORT10_BASE_ENCODE_UNSPEC     (0x00)
+#define MPI_FCPORT10_BASE_ENCODE_8B10B      (0x01)
+#define MPI_FCPORT10_BASE_ENCODE_4B5B       (0x02)
+#define MPI_FCPORT10_BASE_ENCODE_NRZ        (0x03)
+#define MPI_FCPORT10_BASE_ENCODE_MANCHESTER (0x04)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_10_EXTENDED_SFP_DATA
+{
+    U8                      Options[2];                 /* 50h */
+    U8                      BitRateMax;                 /* 52h */
+    U8                      BitRateMin;                 /* 53h */
+    U8                      VendorSN[16];               /* 54h */
+    U8                      DateCode[8];                /* 64h */
+    U8                      Reserved5[3];               /* 6Ch */
+    U8                      CC_EXT;                     /* 6Fh */
+} fCONFIG_PAGE_FC_PORT_10_EXTENDED_SFP_DATA,
+  MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_10_EXTENDED_SFP_DATA,
+  FCPortPage10ExtendedSfpData_t, MPI_POINTER pFCPortPage10ExtendedSfpData_t;
+
+#define MPI_FCPORT10_EXT_OPTION1_RATESEL    (0x20)
+#define MPI_FCPORT10_EXT_OPTION1_TX_DISABLE (0x10)
+#define MPI_FCPORT10_EXT_OPTION1_TX_FAULT   (0x08)
+#define MPI_FCPORT10_EXT_OPTION1_LOS_INVERT (0x04)
+#define MPI_FCPORT10_EXT_OPTION1_LOS        (0x02)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_10
+{
+    fCONFIG_PAGE_HEADER                          Header;             /* 00h */
+    U8                                          Flags;              /* 04h */
+    U8                                          Reserved1;          /* 05h */
+    U16                                         Reserved2;          /* 06h */
+    U32                                         HwConfig1;          /* 08h */
+    U32                                         HwConfig2;          /* 0Ch */
+    fCONFIG_PAGE_FC_PORT_10_BASE_SFP_DATA        Base;               /* 10h */
+    fCONFIG_PAGE_FC_PORT_10_EXTENDED_SFP_DATA    Extended;           /* 50h */
+    U8                                          VendorSpecific[32]; /* 70h */
+} fCONFIG_PAGE_FC_PORT_10, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_10,
+  FCPortPage10_t, MPI_POINTER pFCPortPage10_t;
+
+#define MPI_FCPORTPAGE10_PAGEVERSION                    (0x00)
+
+/* standard MODDEF pin definitions (from GBIC spec.) */
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_MASK              (0x00000007)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF2                  (0x00000001)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF1                  (0x00000002)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF0                  (0x00000004)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_NOGBIC            (0x00000007)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_CPR_IEEE_CX       (0x00000006)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_COPPER            (0x00000005)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_OPTICAL_LW        (0x00000004)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_SEEPROM           (0x00000003)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_SW_OPTICAL        (0x00000002)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_LX_IEEE_OPT_LW    (0x00000001)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_SX_IEEE_OPT_SW    (0x00000000)
+
+#define MPI_FCPORTPAGE10_FLAGS_CC_BASE_OK               (0x00000010)
+#define MPI_FCPORTPAGE10_FLAGS_CC_EXT_OK                (0x00000020)
+
+
 /****************************************************************************
 *   FC Device Config Pages
 ****************************************************************************/
@@ -1155,6 +1377,7 @@
 #define MPI_RAIDVOL0_STATUS_FLAG_ENABLED                (0x01)
 #define MPI_RAIDVOL0_STATUS_FLAG_QUIESCED               (0x02)
 #define MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS     (0x04)
+#define MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE        (0x08)
 
 #define MPI_RAIDVOL0_STATUS_STATE_OPTIMAL               (0x00)
 #define MPI_RAIDVOL0_STATUS_STATE_DEGRADED              (0x01)
@@ -1216,7 +1439,7 @@
 } fCONFIG_PAGE_RAID_VOL_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_0,
   RaidVolumePage0_t, MPI_POINTER pRaidVolumePage0_t;
 
-#define MPI_RAIDVOLPAGE0_PAGEVERSION                    (0x00)
+#define MPI_RAIDVOLPAGE0_PAGEVERSION                    (0x01)
 
 
 /****************************************************************************
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/lsi/mpi_fc.h linux-2.4.21/drivers/message/fusion/lsi/mpi_fc.h
--- linux-2.4.20/drivers/message/fusion/lsi/mpi_fc.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/message/fusion/lsi/mpi_fc.h	2002-12-18 18:58:03.000000000 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
  *
  *
  *           Name:  MPI_FC.H
  *          Title:  MPI Fibre Channel messages and structures
  *  Creation Date:  June 12, 2000
  *
- *    MPI Version:  01.02.02
+ *    MPI_FC.H Version:  01.02.03
  *
  *  Version History
  *  ---------------
@@ -35,6 +35,7 @@
  *  08-08-01  01.02.01  Original release for v1.2 work.
  *  09-28-01  01.02.02  Change name of reserved field in
  *                      MSG_LINK_SERVICE_RSP_REPLY.
+ *  05-31-02  01.02.03  Adding AliasIndex to FC Direct Access requests.
  *  --------------------------------------------------------------------------
  */
 
@@ -193,7 +194,7 @@
 typedef struct _MSG_EXLINK_SERVICE_SEND_REQUEST
 {
     U8                      SendFlags;          /* 00h */
-    U8                      Reserved;           /* 01h */
+    U8                      AliasIndex;         /* 01h */
     U8                      ChainOffset;        /* 02h */
     U8                      Function;           /* 03h */
     U32                     MsgFlags_Did;       /* 04h */
@@ -212,7 +213,8 @@
 /* Extended Link Service Send Reply */
 typedef struct _MSG_EXLINK_SERVICE_SEND_REPLY
 {
-    U16                     Reserved;           /* 00h */
+    U8                      Reserved;           /* 00h */
+    U8                      AliasIndex;         /* 01h */
     U8                      MsgLength;          /* 02h */
     U8                      Function;           /* 03h */
     U16                     Reserved1;          /* 04h */
@@ -275,7 +277,7 @@
 typedef struct _MSG_FC_COMMON_TRANSPORT_SEND_REQUEST
 {
     U8                      SendFlags;          /* 00h */
-    U8                      Reserved;           /* 01h */
+    U8                      AliasIndex;         /* 01h */
     U8                      ChainOffset;        /* 02h */
     U8                      Function;           /* 03h */
     U32                     MsgFlags_Did;       /* 04h */
@@ -297,7 +299,8 @@
 /* FC Common Transport Send Reply */
 typedef struct _MSG_FC_COMMON_TRANSPORT_SEND_REPLY
 {
-    U16                     Reserved;           /* 00h */
+    U8                      Reserved;           /* 00h */
+    U8                      AliasIndex;         /* 01h */
     U8                      MsgLength;          /* 02h */
     U8                      Function;           /* 03h */
     U16                     Reserved1;          /* 04h */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/lsi/mpi_init.h linux-2.4.21/drivers/message/fusion/lsi/mpi_init.h
--- linux-2.4.20/drivers/message/fusion/lsi/mpi_init.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/message/fusion/lsi/mpi_init.h	2002-12-18 18:58:02.000000000 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
  *
  *
  *           Name:  MPI_INIT.H
  *          Title:  MPI initiator mode messages and structures
  *  Creation Date:  June 8, 2000
  *
- *    MPI Version:  01.02.04
+ *    MPI_INIT.H Version:  01.02.05
  *
  *  Version History
  *  ---------------
@@ -29,6 +29,8 @@
  *  09-28-01  01.02.03  Added structures and defines for SCSI Enclosure
  *                      Processor messages.
  *  10-04-01  01.02.04  Added defines for SEP request Action field.
+ *  05-31-02  01.02.05  Added MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR define
+ *                      for SCSI IO requests.
  *  --------------------------------------------------------------------------
  */
 
@@ -67,16 +69,17 @@
   SCSIIORequest_t, MPI_POINTER pSCSIIORequest_t;
 
 
-/* SCSIO MsgFlags bits */
+/* SCSI IO MsgFlags bits */
 
-#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH          (0x01)
-#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32       (0x00)
-#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64       (0x01)
-#define MPI_SCSIIO_MSGFLGS_SENSE_LOCATION       (0x02)
-#define MPI_SCSIIO_MSGFLGS_SENSE_LOC_HOST       (0x00)
-#define MPI_SCSIIO_MSGFLGS_SENSE_LOC_IOC        (0x02)
+#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH              (0x01)
+#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32           (0x00)
+#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64           (0x01)
+#define MPI_SCSIIO_MSGFLGS_SENSE_LOCATION           (0x02)
+#define MPI_SCSIIO_MSGFLGS_SENSE_LOC_HOST           (0x00)
+#define MPI_SCSIIO_MSGFLGS_SENSE_LOC_IOC            (0x02)
+#define MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR  (0x04)
 
-/* SCSIIO LUN fields */
+/* SCSI IO LUN fields */
 
 #define MPI_SCSIIO_LUN_FIRST_LEVEL_ADDRESSING   (0x0000FFFF)
 #define MPI_SCSIIO_LUN_SECOND_LEVEL_ADDRESSING  (0xFFFF0000)
@@ -85,7 +88,7 @@
 #define MPI_SCSIIO_LUN_LEVEL_1_WORD             (0xFF00)
 #define MPI_SCSIIO_LUN_LEVEL_1_DWORD            (0x0000FF00)
 
-/* SCSIO Control bits */
+/* SCSI IO Control bits */
 
 #define MPI_SCSIIO_CONTROL_DATADIRECTION_MASK   (0x03000000)
 #define MPI_SCSIIO_CONTROL_NODATATRANSFER       (0x00000000)
@@ -114,7 +117,7 @@
 #define MPI_SCSIIO_CONTROL_RESERVED2            (0x00010000)
 
 
-/* SCSIIO reply structure */
+/* SCSI IO reply structure */
 typedef struct _MSG_SCSI_IO_REPLY
 {
     U8                      TargetID;           /* 00h */
@@ -137,7 +140,7 @@
   SCSIIOReply_t, MPI_POINTER pSCSIIOReply_t;
 
 
-/* SCSIIO Reply SCSIStatus values (SAM-2 status codes) */
+/* SCSI IO Reply SCSIStatus values (SAM-2 status codes) */
 
 #define MPI_SCSI_STATUS_SUCCESS                 (0x00)
 #define MPI_SCSI_STATUS_CHECK_CONDITION         (0x02)
@@ -151,7 +154,7 @@
 #define MPI_SCSI_STATUS_ACA_ACTIVE              (0x30)
 
 
-/* SCSIIO Reply SCSIState values */
+/* SCSI IO Reply SCSIState values */
 
 #define MPI_SCSI_STATE_AUTOSENSE_VALID          (0x01)
 #define MPI_SCSI_STATE_AUTOSENSE_FAILED         (0x02)
@@ -160,7 +163,7 @@
 #define MPI_SCSI_STATE_RESPONSE_INFO_VALID      (0x10)
 #define MPI_SCSI_STATE_QUEUE_TAG_REJECTED       (0x20)
 
-/* SCSIIO Reply ResponseInfo values */
+/* SCSI IO Reply ResponseInfo values */
 /* (FCP-1 RSP_CODE values and SPI-3 Packetized Failure codes) */
 
 #define MPI_SCSI_RSP_INFO_FUNCTION_COMPLETE     (0x00000000)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/lsi/mpi_ioc.h linux-2.4.21/drivers/message/fusion/lsi/mpi_ioc.h
--- linux-2.4.20/drivers/message/fusion/lsi/mpi_ioc.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/message/fusion/lsi/mpi_ioc.h	2002-12-18 18:58:06.000000000 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
  *
  *
  *           Name:  MPI_IOC.H
  *          Title:  MPI IOC, Port, Event, FW Download, and FW Upload messages
  *  Creation Date:  August 11, 2000
  *
- *    MPI Version:  01.02.04
+ *    MPI_IOC.H Version:  01.02.06
  *
  *  Version History
  *  ---------------
@@ -51,6 +51,10 @@
  *                      MPI_FW_UPLOAD_ITYPE_NVDATA.
  *  09-28-01  01.02.03  Modified Event Data for Integrated RAID.
  *  11-01-01  01.02.04  Added defines for MPI_EXT_IMAGE_HEADER ImageType field.
+ *  03-14-02  01.02.05  Added HeaderVersion field to MSG_IOC_FACTS_REPLY.
+ *  05-31-02  01.02.06  Added define for
+ *                      MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID.
+ *                      Added AliasIndex to EVENT_DATA_LOGOUT structure.
  *  --------------------------------------------------------------------------
  */
 
@@ -151,7 +155,7 @@
     U16                     MsgVersion;                 /* 00h */
     U8                      MsgLength;                  /* 02h */
     U8                      Function;                   /* 03h */
-    U16                     Reserved;                   /* 04h */
+    U16                     HeaderVersion;              /* 04h */
     U8                      IOCNumber;                  /* 06h */
     U8                      MsgFlags;                   /* 07h */
     U32                     MsgContext;                 /* 08h */
@@ -183,7 +187,11 @@
 #define MPI_IOCFACTS_MSGVERSION_MAJOR_MASK          (0xFF00)
 #define MPI_IOCFACTS_MSGVERSION_MINOR_MASK          (0x00FF)
 
+#define MPI_IOCFACTS_HEADERVERSION_UNIT_MASK        (0xFF00)
+#define MPI_IOCFACTS_HEADERVERSION_DEV_MASK         (0x00FF)
+
 #define MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL    (0x0001)
+#define MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID     (0x0002)
 
 #define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT         (0x01)
 
@@ -464,12 +472,15 @@
 typedef struct _EVENT_DATA_LOGOUT
 {
     U32                     NPortID;                    /* 00h */
-    U8                      Reserved;                   /* 04h */
+    U8                      AliasIndex;                 /* 04h */
     U8                      Port;                       /* 05h */
     U16                     Reserved1;                  /* 06h */
 } EVENT_DATA_LOGOUT, MPI_POINTER PTR_EVENT_DATA_LOGOUT,
   EventDataLogout_t, MPI_POINTER pEventDataLogout_t;
 
+#define MPI_EVENT_LOGOUT_ALL_ALIASES        (0xFF)
+
+
 /* MPI Integrated RAID Event data */
 
 typedef struct _EVENT_DATA_RAID
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/lsi/mpi_lan.h linux-2.4.21/drivers/message/fusion/lsi/mpi_lan.h
--- linux-2.4.20/drivers/message/fusion/lsi/mpi_lan.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/message/fusion/lsi/mpi_lan.h	2002-12-18 18:58:09.000000000 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
  *
  *
  *           Name:  MPI_LAN.H
  *          Title:  MPI LAN messages and structures
  *  Creation Date:  June 30, 2000
  *
- *    MPI Version:  01.02.01
+ *    MPI_LAN.H Version:  01.02.01
  *
  *  Version History
  *  ---------------
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/lsi/mpi_raid.h linux-2.4.21/drivers/message/fusion/lsi/mpi_raid.h
--- linux-2.4.20/drivers/message/fusion/lsi/mpi_raid.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/message/fusion/lsi/mpi_raid.h	2002-12-18 18:58:04.000000000 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2001 LSI Logic Corporation.
+ *  Copyright (c) 2001-2002 LSI Logic Corporation.
  *
  *
  *           Name:  MPI_RAID.H
  *          Title:  MPI RAID message and structures
  *  Creation Date:  February 27, 2001
  *
- *    MPI Version:  01.02.04
+ *    MPI_RAID.H Version:  01.02.07
  *
  *  Version History
  *  ---------------
@@ -20,6 +20,11 @@
  *  10-04-01  01.02.03  Added ActionData defines for
  *                      MPI_RAID_ACTION_DELETE_VOLUME action.
  *  11-01-01  01.02.04  Added define for MPI_RAID_ACTION_ADATA_DO_NOT_SYNC.
+ *  03-14-02  01.02.05  Added define for MPI_RAID_ACTION_ADATA_LOW_LEVEL_INIT.
+ *  05-07-02  01.02.06  Added define for MPI_RAID_ACTION_ACTIVATE_VOLUME,
+ *                      MPI_RAID_ACTION_INACTIVATE_VOLUME, and
+ *                      MPI_RAID_ACTION_ADATA_INACTIVATE_ALL.
+ *  07-12-02  01.02.07  Added structures for Mailbox request and reply.
  *  --------------------------------------------------------------------------
  */
 
@@ -74,14 +79,20 @@
 #define MPI_RAID_ACTION_DELETE_PHYSDISK             (0x0E)
 #define MPI_RAID_ACTION_FAIL_PHYSDISK               (0x0F)
 #define MPI_RAID_ACTION_REPLACE_PHYSDISK            (0x10)
+#define MPI_RAID_ACTION_ACTIVATE_VOLUME             (0x11)
+#define MPI_RAID_ACTION_INACTIVATE_VOLUME           (0x12)
 
 /* ActionDataWord defines for use with MPI_RAID_ACTION_CREATE_VOLUME action */
 #define MPI_RAID_ACTION_ADATA_DO_NOT_SYNC           (0x00000001)
+#define MPI_RAID_ACTION_ADATA_LOW_LEVEL_INIT        (0x00000002)
 
 /* ActionDataWord defines for use with MPI_RAID_ACTION_DELETE_VOLUME action */
 #define MPI_RAID_ACTION_ADATA_KEEP_PHYS_DISKS       (0x00000000)
 #define MPI_RAID_ACTION_ADATA_DEL_PHYS_DISKS        (0x00000001)
 
+/* ActionDataWord defines for use with MPI_RAID_ACTION_ACTIVATE_VOLUME action */
+#define MPI_RAID_ACTION_ADATA_INACTIVATE_ALL        (0x00000001)
+
 
 /* RAID Action reply message */
 
@@ -172,6 +183,42 @@
   SCSIIORaidPassthroughReply_t, MPI_POINTER pSCSIIORaidPassthroughReply_t;
 
 
+/****************************************************************************/
+/* Mailbox reqeust structure */
+/****************************************************************************/
+
+typedef struct _MSG_MAILBOX_REQUEST
+{
+    U16                     Reserved1;
+    U8                      ChainOffset;
+    U8                      Function;
+    U16                     Reserved2;
+    U8                      Reserved3;
+    U8                      MsgFlags;
+    U8                      Command[10];
+    U16                     Reserved4;
+    SGE_IO_UNION            SGL;
+} MSG_MAILBOX_REQUEST, MPI_POINTER PTR_MSG_MAILBOX_REQUEST,
+  MailboxRequest_t, MPI_POINTER pMailboxRequest_t;
+
+
+/* Mailbox reply structure */
+typedef struct _MSG_MAILBOX_REPLY
+{
+    U16                     Reserved1;          /* 00h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved2;          /* 04h */
+    U8                      Reserved3;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     MailboxStatus;      /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     Reserved4;          /* 14h */
+} MSG_MAILBOX_REPLY, MPI_POINTER PTR_MSG_MAILBOX_REPLY,
+  MailboxReply_t, MPI_POINTER pMailboxReply_t;
+
 #endif
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/lsi/mpi_targ.h linux-2.4.21/drivers/message/fusion/lsi/mpi_targ.h
--- linux-2.4.20/drivers/message/fusion/lsi/mpi_targ.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/message/fusion/lsi/mpi_targ.h	2002-12-18 18:58:03.000000000 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
  *
  *
  *           Name:  MPI_TARG.H
  *          Title:  MPI Target mode messages and structures
  *  Creation Date:  June 22, 2000
  *
- *    MPI Version:  01.02.04
+ *    MPI_TARG.H Version:  01.02.07
  *
  *  Version History
  *  ---------------
@@ -34,6 +34,13 @@
  *                      of MPI.
  *  10-04-01  01.02.03  Added PriorityReason to MSG_TARGET_ERROR_REPLY.
  *  11-01-01  01.02.04  Added define for TARGET_STATUS_SEND_FLAGS_HIGH_PRIORITY.
+ *  03-14-02  01.02.05  Modified MPI_TARGET_FCP_RSP_BUFFER to get the proper
+ *                      byte ordering.
+ *  05-31-02  01.02.06  Modified TARGET_MODE_REPLY_ALIAS_MASK to only include
+ *                      one bit.
+ *                      Added AliasIndex field to MPI_TARGET_FCP_CMD_BUFFER.
+ *  09-16-02  01.02.07  Added flags for confirmed completion.
+ *                      Added PRIORITY_REASON_TARGET_BUSY.
  *  --------------------------------------------------------------------------
  */
 
@@ -133,6 +140,7 @@
 #define PRIORITY_REASON_PROTOCOL_ERR            (0x06)
 #define PRIORITY_REASON_DATA_OUT_PARITY_ERR     (0x07)
 #define PRIORITY_REASON_DATA_OUT_CRC_ERR        (0x08)
+#define PRIORITY_REASON_TARGET_BUSY             (0x09)
 #define PRIORITY_REASON_UNKNOWN                 (0xFF)
 
 
@@ -161,6 +169,9 @@
     U8      FcpCntl[4];                                 /* 08h */
     U8      FcpCdb[16];                                 /* 0Ch */
     U32     FcpDl;                                      /* 1Ch */
+    U8      AliasIndex;                                 /* 20h */
+    U8      Reserved1;                                  /* 21h */
+    U16     Reserved2;                                  /* 22h */
 } MPI_TARGET_FCP_CMD_BUFFER, MPI_POINTER PTR_MPI_TARGET_FCP_CMD_BUFFER,
   MpiTargetFcpCmdBuffer, MPI_POINTER pMpiTargetFcpCmdBuffer;
 
@@ -209,6 +220,7 @@
 #define TARGET_ASSIST_FLAGS_DATA_DIRECTION          (0x01)
 #define TARGET_ASSIST_FLAGS_AUTO_STATUS             (0x02)
 #define TARGET_ASSIST_FLAGS_HIGH_PRIORITY           (0x04)
+#define TARGET_ASSIST_FLAGS_CONFIRMED               (0x08)
 #define TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER       (0x80)
 
 
@@ -253,14 +265,19 @@
 
 #define TARGET_STATUS_SEND_FLAGS_AUTO_GOOD_STATUS   (0x01)
 #define TARGET_STATUS_SEND_FLAGS_HIGH_PRIORITY      (0x04)
+#define TARGET_STATUS_SEND_FLAGS_CONFIRMED          (0x08)
 #define TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER  (0x80)
 
+/*
+ * NOTE: FCP_RSP data is big-endian. When used on a little-endian system, this
+ * structure properly orders the bytes.
+ */
 typedef struct _MPI_TARGET_FCP_RSP_BUFFER
 {
     U8      Reserved0[8];                               /* 00h */
-    U8      FcpStatus;                                  /* 08h */
-    U8      FcpFlags;                                   /* 09h */
-    U8      Reserved1[2];                               /* 0Ah */
+    U8      Reserved1[2];                               /* 08h */
+    U8      FcpFlags;                                   /* 0Ah */
+    U8      FcpStatus;                                  /* 0Bh */
     U32     FcpResid;                                   /* 0Ch */
     U32     FcpSenseLength;                             /* 10h */
     U32     FcpResponseLength;                          /* 14h */
@@ -269,6 +286,10 @@
 } MPI_TARGET_FCP_RSP_BUFFER, MPI_POINTER PTR_MPI_TARGET_FCP_RSP_BUFFER,
   MpiTargetFcpRspBuffer, MPI_POINTER pMpiTargetFcpRspBuffer;
 
+/*
+ * NOTE: The SPI status IU is big-endian. When used on a little-endian system,
+ * this structure properly orders the bytes.
+ */
 typedef struct _MPI_TARGET_SCSI_SPI_STATUS_IU
 {
     U8      Reserved0;                                  /* 00h */
@@ -332,7 +353,7 @@
 #define TARGET_MODE_REPLY_IO_INDEX_SHIFT        (0)
 #define TARGET_MODE_REPLY_INITIATOR_INDEX_MASK  (0x03FFC000)
 #define TARGET_MODE_REPLY_INITIATOR_INDEX_SHIFT (14)
-#define TARGET_MODE_REPLY_ALIAS_MASK            (0x0C000000)
+#define TARGET_MODE_REPLY_ALIAS_MASK            (0x04000000)
 #define TARGET_MODE_REPLY_ALIAS_SHIFT           (26)
 #define TARGET_MODE_REPLY_PORT_MASK             (0x10000000)
 #define TARGET_MODE_REPLY_PORT_SHIFT            (28)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/lsi/mpi_type.h linux-2.4.21/drivers/message/fusion/lsi/mpi_type.h
--- linux-2.4.20/drivers/message/fusion/lsi/mpi_type.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/message/fusion/lsi/mpi_type.h	2002-12-18 18:58:10.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
  *
  *
  *           Name:  MPI_TYPE.H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/mptbase.c linux-2.4.21/drivers/message/fusion/mptbase.c
--- linux-2.4.20/drivers/message/fusion/mptbase.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/message/fusion/mptbase.c	2002-12-18 18:58:04.000000000 +0000
@@ -49,7 +49,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptbase.c,v 1.121 2002/07/23 18:56:59 pdelaney Exp $
+ *  $Id: mptbase.c,v 1.124 2002/11/01 17:58:12 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -1416,10 +1416,30 @@
 	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
 		ioc->chip_type = FC929X;
 		ioc->prod_name = "LSIFC929X";
+		{
+			/* 929X Chip Fix. Set Split transactions level
+			 * for PCIX. Set bits 5 - 6 to zero, turn on bit 4.
+			 */
+			u16 pcixcmd = 0;
+			pci_read_config_word(pdev, 0x6a, &pcixcmd);
+			pcixcmd &= 0xFF9F;
+			pcixcmd |= 0x0010;
+			pci_write_config_word(pdev, 0x6a, pcixcmd);
+		}
 	}
 	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
 		ioc->chip_type = FC919X;
 		ioc->prod_name = "LSIFC919X";
+		{
+			/* 919X Chip Fix. Set Split transactions level
+			 * for PCIX. Set bits 5 - 6 to zero, turn on bit 4.
+			 */
+			u16 pcixcmd = 0;
+			pci_read_config_word(pdev, 0x6a, &pcixcmd);
+			pcixcmd &= 0xFF9F;
+			pcixcmd |= 0x0010;
+			pci_write_config_word(pdev, 0x6a, pcixcmd);
+		}
 	}
 	else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
 		ioc->chip_type = C1030;
@@ -1786,8 +1806,7 @@
 		/* Disable the FW */
 		state = mpt_GetIocState(this, 1);
 		if (state == MPI_IOC_STATE_OPERATIONAL) {
-			if (SendIocReset(this, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, NO_SLEEP) != 0)
-				(void) KickStart(this, 1, NO_SLEEP);
+			SendIocReset(this, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, NO_SLEEP);
 		}
 
 		if (this->cached_fw != NULL) {
@@ -1799,7 +1818,6 @@
 			}
 		}
 
-
 		/* Disable adapter interrupts! */
 		CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF);
 		this->active = 0;
@@ -2006,8 +2024,19 @@
 	}
 
 	/* Is it already READY? */
-	if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
-		return 0;
+	if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY) {
+		if ((int)ioc->chip_type <= (int)FC929)
+			return 0;
+		else {
+			/* Workaround from broken 1030 FW.
+			 * Force a diagnostic reset if fails.
+			 */
+			if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
+				return 0;
+			else
+				statefault = 4;
+		}
+	} 
 
 	/*
 	 *	Check to see if IOC is in FAULT state.
@@ -2860,6 +2889,7 @@
 	 */
 	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
 	while ((diag0val & MPI_DIAG_DRWE) == 0) {
+		CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
 		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
 		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
 		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
@@ -3095,6 +3125,18 @@
 	int cnt = 0;
 
 	dprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
+	if ((int)ioc->chip_type > (int)FC929) {
+		/* Always issue a Msg Unit Reset first. This will clear some
+		 * SCSI bus hang conditions.
+		 */
+		SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
+
+		if (sleepFlag == CAN_SLEEP) {
+			schedule_timeout(HZ);
+		} else {
+			mdelay (1000);
+		}
+	}
 
 	hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
 	if (hard_reset_done < 0)
@@ -3173,6 +3215,7 @@
 			/* Write magic sequence to WriteSequence register
 			 * Loop until in diagnostic mode
 			 */
+			CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
 			CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
 			CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
 			CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
@@ -3208,7 +3251,11 @@
 				ioc->name, diag0val, diag1val));
 #endif
 		/* Write the PreventIocBoot bit */
+#if 1
+		if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) {
+#else
 		if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
+#endif
 			diag0val |= MPI_DIAG_PREVENT_IOC_BOOT;
 			CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
 		}
@@ -3254,7 +3301,11 @@
 			/* FIXME?  Examine results here? */
 		}
 
+#if 1
+		if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) {
+#else
 		if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
+#endif
 			/* If the DownloadBoot operation fails, the
 			 * IOC will be left unusable. This is a fatal error
 			 * case.  _diag_reset will return < 0
@@ -5265,6 +5316,9 @@
 		printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
 			rc, ioc->name);
 	}
+	ioc->reload_fw = 0;
+	if (ioc->alt_ioc)
+		ioc->alt_ioc->reload_fw = 0;
 
 	spin_lock_irqsave(&ioc->diagLock, flags);
 	ioc->diagPending = 0;
@@ -5603,8 +5657,46 @@
 static void
 mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info)
 {
-	/* FIXME! */
-	printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x)\n", ioc->name, log_info);
+	u32 info = log_info & 0x00FF0000;
+	char *desc = "unknown";
+
+	switch (info) {
+	case 0x00010000:
+		desc = "bug! MID not found";
+		if (ioc->reload_fw == 0)
+			ioc->reload_fw++;
+		break;
+
+	case 0x00020000:
+		desc = "Parity Error";
+		break;
+
+	case 0x00030000:
+		desc = "ASYNC Outbound Overrun";
+		break;
+
+	case 0x00040000:
+		desc = "SYNC Offset Error";
+		break;
+
+	case 0x00050000:
+		desc = "BM Change";
+		break;
+
+	case 0x00060000:
+		desc = "Msg In Overflow";
+		break;
+
+	case 0x00070000:
+		desc = "DMA Error";
+		break;
+
+	case 0x00080000:
+		desc = "Outbound DMA Overrun";
+		break;
+	}
+
+	printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -5760,6 +5852,15 @@
 
 	while (! Q_IS_EMPTY(&MptAdapters)) {
 		this = MptAdapters.head;
+
+		/* Disable interrupts! */
+		CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF);
+
+		this->active = 0;
+
+		/* Clear any lingering interrupt */
+		CHIPREG_WRITE32(&this->chip->IntStatus, 0);
+
 		Q_DEL_ITEM(this);
 		mpt_adapter_dispose(this);
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/mptbase.h linux-2.4.21/drivers/message/fusion/mptbase.h
--- linux-2.4.20/drivers/message/fusion/mptbase.h	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/message/fusion/mptbase.h	2002-12-18 18:58:04.000000000 +0000
@@ -13,7 +13,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptbase.h,v 1.133 2002/09/05 22:30:09 pdelaney Exp $
+ *  $Id: mptbase.h,v 1.139 2002/11/11 18:33:40 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -80,8 +80,8 @@
 #define COPYRIGHT	"Copyright (c) 1999-2002 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON	"2.02.01"
-#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-2.02.01"
+#define MPT_LINUX_VERSION_COMMON	"2.03.00"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-2.03.00"
 #define WHAT_MAGIC_STRING		"@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -91,7 +91,7 @@
 /*
  *  Fusion MPT(linux) driver configurable stuff...
  */
-#define MPT_MAX_ADAPTERS		16
+#define MPT_MAX_ADAPTERS		18
 #define MPT_MAX_PROTOCOL_DRIVERS	16
 #define MPT_MAX_BUS			1
 #define MPT_MAX_FC_DEVICES		255
@@ -397,8 +397,10 @@
 	ScsiCmndTracker		 SentQ;
 	ScsiCmndTracker		 DoneQ;
 //--- LUN split here?
+#ifdef MPT_SAVE_AUTOSENSE
 	u8			 sense[SCSI_STD_SENSE_BYTES];		/* 18 */
 	u8			 rsvd2[2];	/* alignment */
+#endif
 	u32			 luns;		/* Max LUNs is 32 */
 	u8			 inq_data[SCSI_STD_INQUIRY_BYTES];	/* 36 */
 	u8			 pad0[4];
@@ -424,8 +426,11 @@
 #define MPT_TARGET_DEFAULT_DV_STATUS	0
 #define MPT_TARGET_FLAGS_VALID_NEGO	0x01
 #define MPT_TARGET_FLAGS_VALID_INQUIRY	0x02
+#ifdef MPT_SAVE_AUTOSENSE
 #define MPT_TARGET_FLAGS_VALID_SENSE	0x04
+#endif
 #define MPT_TARGET_FLAGS_Q_YES		0x08
+#define MPT_TARGET_FLAGS_VALID_56	0x10
 
 #define MPT_TARGET_NO_NEGO_WIDE		0x01
 #define MPT_TARGET_NO_NEGO_SYNC		0x02
@@ -527,7 +532,6 @@
 	int		*nvram;			/* table of device NVRAM values */
 	IOCPage3_t	*pIocPg3;		/* table of physical disks */
 	u8		 dvStatus[MPT_MAX_SCSI_DEVICES];
-	u8		 iocntr[MPT_MAX_SCSI_DEVICES];
 	int		 isRaid;		/* bit field, 1 if RAID */
 	u8		 minSyncFactor;		/* 0xFF if async */
 	u8		 maxSyncOffset;		/* 0 if async */
@@ -627,7 +631,8 @@
 	LANPage1_t		 lan_cnfg_page1;
 	u8			 FirstWhoInit;
 	u8			 upload_fw;	/* If set, do a fw upload */
-	u8			 pad1[6];
+	u8			 reload_fw;	/* Force a FW Reload on next reset */
+	u8			 pad1[5];
 } MPT_ADAPTER;
 
 
@@ -889,6 +894,8 @@
 	MPT_Q_TRACKER		  taskQ;		/* TM request Q */
 	spinlock_t		  freedoneQlock;
 	int			  taskQcnt;
+	int			  num_chain;		/* Number of chain buffers */
+	int			  max_sge;		/* Max No of SGE*/
 	u8			  numTMrequests;
 	u8			  tmPending;
 	u8			  resetPending;
@@ -905,6 +912,9 @@
 	MPT_FRAME_HDR		 *cmdPtr;		/* Ptr to nonOS request */
 	struct scsi_cmnd	 *abortSCpnt;
 	MPT_LOCAL_REPLY		  localReply;		/* internal cmd reply struct */
+	unsigned long		  hard_resets;		/* driver forced bus resets count */
+	unsigned long		  soft_resets;		/* fw/external bus resets count */
+	unsigned long		  timeouts;		/* cmd timeouts */
 } MPT_SCSI_HOST;
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/mptctl.c linux-2.4.21/drivers/message/fusion/mptctl.c
--- linux-2.4.20/drivers/message/fusion/mptctl.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/message/fusion/mptctl.c	2002-12-18 18:58:02.000000000 +0000
@@ -34,7 +34,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptctl.c,v 1.59 2002/09/05 22:30:10 pdelaney Exp $
+ *  $Id: mptctl.c,v 1.62 2002/11/01 17:58:13 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -136,6 +136,8 @@
 static int mptctl_replace_fw (unsigned long arg);
 
 static int mptctl_do_reset(unsigned long arg);
+static int mptctl_hp_hostinfo(unsigned long arg);
+static int mptctl_hp_targetinfo(unsigned long arg);
 
 static int mptctl_compaq_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 static int mptctl_cpq_getpciinfo(unsigned long arg);
@@ -415,7 +417,7 @@
 	/* Send request
 	 */
 	if ((mf = mpt_get_msg_frame(mptctl_id, ioctl->ioc->id)) == NULL) {
-		dtmprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n",
+		dctlprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n",
 				ioctl->ioc->name));
 
 		mptctl_free_tm_flags(ioctl->ioc);
@@ -627,7 +629,7 @@
 	/* Test for Compaq-specific IOCTL's.
 	 */
 	if ((cmd == CPQFCTS_GETPCIINFO) || (cmd == CPQFCTS_CTLR_STATUS) ||
-		(cmd == CPQFCTS_GETDRIVER) || (cmd == CPQFCTS_SCSI_PASSTHRU) ||
+		(cmd == CPQFCTS_GETDRIVVER) || (cmd == CPQFCTS_SCSI_PASSTHRU) ||
 		(cmd == CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS))
 		return mptctl_compaq_ioctl(file, cmd, arg);
 
@@ -637,7 +639,7 @@
 	iocnumX = khdr.iocnum & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnumX));
 		return -ENODEV;
 	}
@@ -683,6 +685,12 @@
 	case MPTHARDRESET:
 		ret = mptctl_do_reset(arg);
 		break;
+	case HP_GETHOSTINFO:
+		ret = mptctl_hp_hostinfo(arg);
+		break;
+	case HP_GETTARGETINFO:
+		ret = mptctl_hp_targetinfo(arg);
+		break;
 	default:
 		ret = -EINVAL;
 	}
@@ -708,7 +716,7 @@
 	}
 
 	if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) {
-		dtmprintk((KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n",
 				__FILE__, __LINE__, krinfo.hdr.iocnum));
 		return -ENODEV; /* (-6) No such device or address */
 	}
@@ -816,7 +824,7 @@
 	dctlprintk((KERN_INFO "DbG: kfwdl.ioc   = %04xh\n", ioc));
 
 	if ((ioc = mpt_verify_adapter(ioc, &iocp)) < 0) {
-		dtmprintk(("%s@%d::_ioctl_fwdl - ioc%d not found!\n",
+		dctlprintk(("%s@%d::_ioctl_fwdl - ioc%d not found!\n",
 				__FILE__, __LINE__, ioc));
 		return -ENODEV; /* (-6) No such device or address */
 	}
@@ -1252,7 +1260,7 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -1379,7 +1387,7 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -1510,7 +1518,7 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_readtest() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_readtest() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -1568,7 +1576,7 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -1606,7 +1614,7 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -1654,7 +1662,7 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -1708,7 +1716,7 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -1794,7 +1802,7 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -1842,7 +1850,7 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -1926,6 +1934,14 @@
 			int target = (int) pScsiReq->TargetID;
 			int dataSize;
 
+			if ((target < 0) || (target >= ioc->sh->max_id)) {
+				printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+					"Target ID out of bounds. \n",
+					__FILE__, __LINE__);
+				rc = -ENODEV;
+				goto done_free_mem;
+			}
+
 			pScsiReq->MsgFlags = mpt_msg_flags();
 
 			/* verify that app has not requested
@@ -2330,7 +2346,7 @@
 			this_sge++;	/* go to next structure */
 			this_alloc = bufOut.len;
 			pci_free_consistent(ioc->pcidev,
-				this_alloc, (void *)bufOut.kptr, dma_addr);
+				this_alloc, (void *) bufOut.kptr, dma_addr);
 		}
 
 		if (bufIn.kptr != NULL ) {
@@ -2338,7 +2354,7 @@
 			this_alloc = bufIn.len;
 
 			pci_free_consistent(ioc->pcidev,
-					this_alloc, (void *)bufIn.kptr, dma_addr);
+					this_alloc, (void *) bufIn.kptr, dma_addr);
 		}
 
 		this_alloc = sgSize * sizeof(MptSge_t);
@@ -2357,6 +2373,317 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Prototype Routine for the HP HOST INFO command.
+ *
+ * Outputs:	None.
+ * Return:	0 if successful
+ *		-EFAULT if data unavailable
+ *		-EBUSY  if previous command timout and IOC reset is not complete.
+ *		-ENODEV if no such device/adapter
+ *		-ETIME	if timer expires
+ *		-ENOMEM if memory allocation error
+ */
+static int
+mptctl_hp_hostinfo(unsigned long arg)
+{
+	hp_host_info_t	*uarg = (hp_host_info_t *) arg;
+	MPT_ADAPTER		*ioc;
+	struct pci_dev		*pdev;
+	char			*pbuf;
+	dma_addr_t		buf_dma;
+	hp_host_info_t		karg;
+	CONFIGPARMS		cfg;
+	ConfigPageHeader_t	hdr;
+	int			iocnum;
+	int			rc;
+
+	dctlprintk((": mptctl_hp_hostinfo called.\n"));
+	if (copy_from_user(&karg, uarg, sizeof(hp_host_info_t))) {
+		printk(KERN_ERR "%s@%d::mptctl_hp_host_info - "
+			"Unable to read in hp_host_info struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+	    (ioc == NULL)) {
+		dctlprintk((KERN_ERR "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
+		return -ENODEV;
+	}
+
+	/* Fill in the data and return the structure to the calling
+	 * program
+	 */
+	pdev = (struct pci_dev *) ioc->pcidev;
+
+	karg.vendor = pdev->vendor;
+	karg.device = pdev->device;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	karg.subsystem_id = pdev->subsystem_device;
+	karg.subsystem_vendor = pdev->subsystem_vendor;
+#endif
+	karg.devfn = pdev->devfn;
+	karg.bus = pdev->bus->number;
+
+	/* Save the SCSI host no. if
+	 * SCSI driver loaded 
+	 */
+	if (ioc->sh != NULL)
+		karg.host_no = ioc->sh->host_no;
+	else
+		karg.host_no =  -1;
+
+	/* Reformat the fw_version into a string
+	 */
+	karg.fw_version[0] = ioc->facts.FWVersion.Struct.Major >= 10 ?
+		((ioc->facts.FWVersion.Struct.Major / 10) + '0') : '0';
+	karg.fw_version[1] = (ioc->facts.FWVersion.Struct.Major % 10 ) + '0';
+	karg.fw_version[2] = '.';
+	karg.fw_version[3] = ioc->facts.FWVersion.Struct.Minor >= 10 ?
+		((ioc->facts.FWVersion.Struct.Minor / 10) + '0') : '0';
+	karg.fw_version[4] = (ioc->facts.FWVersion.Struct.Minor % 10 ) + '0';
+	karg.fw_version[5] = '.';
+	karg.fw_version[6] = ioc->facts.FWVersion.Struct.Unit >= 10 ?
+		((ioc->facts.FWVersion.Struct.Unit / 10) + '0') : '0';
+	karg.fw_version[7] = (ioc->facts.FWVersion.Struct.Unit % 10 ) + '0';
+	karg.fw_version[8] = '.';
+	karg.fw_version[9] = ioc->facts.FWVersion.Struct.Dev >= 10 ?
+		((ioc->facts.FWVersion.Struct.Dev / 10) + '0') : '0';
+	karg.fw_version[10] = (ioc->facts.FWVersion.Struct.Dev % 10 ) + '0';
+	karg.fw_version[11] = '\0';
+
+	/* Issue a config request to get the device serial number
+	 */
+	hdr.PageVersion = 0;
+	hdr.PageLength = 0;
+	hdr.PageNumber = 0;
+	hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
+	cfg.hdr = &hdr;
+	cfg.physAddr = -1;
+	cfg.pageAddr = 0;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.dir = 0;	/* read */
+	cfg.timeout = 10;
+
+	strncpy(karg.serial_number, " ", 24);
+	if (mpt_config(ioc, &cfg) == 0) {
+		if (cfg.hdr->PageLength > 0) {
+			/* Issue the second config page request */
+			cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+			pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
+			if (pbuf) {
+				cfg.physAddr = buf_dma;
+				if (mpt_config(ioc, &cfg) == 0) {
+					ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf;
+					if (strlen(pdata->BoardTracerNumber) > 1)
+						strncpy(karg.serial_number, pdata->BoardTracerNumber, 24);
+				}
+				pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
+				pbuf = NULL;
+			}
+		}
+	}
+	rc = mpt_GetIocState(ioc, 1);
+	switch (rc) {
+	case MPI_IOC_STATE_OPERATIONAL:
+		karg.ioc_status =  HP_STATUS_OK;
+		break;
+
+	case MPI_IOC_STATE_FAULT:
+		karg.ioc_status =  HP_STATUS_FAILED;
+		break;
+
+	case MPI_IOC_STATE_RESET:
+	case MPI_IOC_STATE_READY:
+	default:
+		karg.ioc_status =  HP_STATUS_OTHER;
+		break;
+	}
+
+	karg.base_io_addr = pdev->PCI_BASEADDR_START(0);
+
+	if ((int)ioc->chip_type <= (int) FC929)
+		karg.bus_phys_width = HP_BUS_WIDTH_UNK;
+	else
+		karg.bus_phys_width = HP_BUS_WIDTH_16;
+
+	karg.hard_resets = 0;
+	karg.soft_resets = 0;
+	karg.timeouts = 0;
+	if (ioc->sh != NULL) {
+		MPT_SCSI_HOST *hd =  (MPT_SCSI_HOST *)ioc->sh->hostdata;
+
+		if (hd) {
+			karg.hard_resets = hd->hard_resets;
+			karg.soft_resets = hd->soft_resets;
+			karg.timeouts = hd->timeouts;
+		}
+	}
+
+	/* Copy the data from kernel memory to user memory
+	 */
+	if (copy_to_user((char *)arg, &karg,
+				sizeof(hp_host_info_t))) {
+		printk(KERN_ERR "%s@%d::mptctl_hpgethostinfo - "
+			"Unable to write out hp_host_info @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+	return 0;
+
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Prototype Routine for the HP TARGET INFO command.
+ *
+ * Outputs:	None.
+ * Return:	0 if successful
+ *		-EFAULT if data unavailable
+ *		-EBUSY  if previous command timout and IOC reset is not complete.
+ *		-ENODEV if no such device/adapter
+ *		-ETIME	if timer expires
+ *		-ENOMEM if memory allocation error
+ */
+static int
+mptctl_hp_targetinfo(unsigned long arg)
+{
+	hp_target_info_t	*uarg = (hp_target_info_t *) arg;
+	SCSIDevicePage0_t	*pg0_alloc;
+	SCSIDevicePage3_t	*pg3_alloc;
+	MPT_ADAPTER		*ioc;
+	hp_target_info_t	karg;
+	int			iocnum;
+	int			data_sz;
+	dma_addr_t		page_dma;
+	CONFIGPARMS	 	cfg;
+	ConfigPageHeader_t	hdr;
+	int			tmp, np, rc = 0;
+
+	dctlprintk((": mptctl_hp_targetinfo called.\n"));
+	if (copy_from_user(&karg, uarg, sizeof(hp_target_info_t))) {
+		printk(KERN_ERR "%s@%d::mptctl_hp_targetinfo - "
+			"Unable to read in hp_host_targetinfo struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+	
+	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+		(ioc == NULL)) {
+		dctlprintk((KERN_ERR "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
+		return -ENODEV;
+	}
+
+	/*  There is nothing to do for FCP parts.
+	 */
+	if ((int) ioc->chip_type <= (int) FC929)
+		return 0;
+
+	if ((ioc->spi_data.sdp0length == 0) || (ioc->sh == NULL))
+		return 0;
+
+	if (ioc->sh->host_no != karg.hdr.host)
+		return -ENODEV;
+		
+       /* Get the data transfer speeds
+        */
+	data_sz = ioc->spi_data.sdp0length * 4;
+	pg0_alloc = (SCSIDevicePage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
+	if (pg0_alloc) {
+		hdr.PageVersion = ioc->spi_data.sdp0version;
+		hdr.PageLength = data_sz;
+		hdr.PageNumber = 0;
+		hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+
+		cfg.hdr = &hdr;
+		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+		cfg.dir = 0;
+		cfg.timeout = 0;
+		cfg.physAddr = page_dma;
+
+		cfg.pageAddr = (karg.hdr.channel << 8) | karg.hdr.id;
+
+		if ((rc = mpt_config(ioc, &cfg)) == 0) {
+			np = le32_to_cpu(pg0_alloc->NegotiatedParameters);
+			karg.negotiated_width = np & MPI_SCSIDEVPAGE0_NP_WIDE ? 
+					HP_BUS_WIDTH_16 : HP_BUS_WIDTH_8;
+
+			if (np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) {
+				tmp = (np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
+				if (tmp < 0x09)
+					karg.negotiated_speed = HP_DEV_SPEED_ULTRA320;
+				else if (tmp <= 0x09)
+					karg.negotiated_speed = HP_DEV_SPEED_ULTRA160;
+				else if (tmp <= 0x0A)
+					karg.negotiated_speed = HP_DEV_SPEED_ULTRA2;
+				else if (tmp <= 0x0C)
+					karg.negotiated_speed = HP_DEV_SPEED_ULTRA;
+				else if (tmp <= 0x25)
+					karg.negotiated_speed = HP_DEV_SPEED_FAST;
+				else
+					karg.negotiated_speed = HP_DEV_SPEED_ASYNC;
+			} else
+				karg.negotiated_speed = HP_DEV_SPEED_ASYNC;
+		}
+
+		pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg0_alloc, page_dma);
+	}
+
+	/* Set defaults
+	 */
+	karg.message_rejects = -1;
+	karg.phase_errors = -1;
+	karg.parity_errors = -1;
+	karg.select_timeouts = -1;
+
+	/* Get the target error parameters
+	 */
+	hdr.PageVersion = 0;
+	hdr.PageLength = 0;
+	hdr.PageNumber = 3;
+	hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+
+	cfg.hdr = &hdr;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.dir = 0;
+	cfg.timeout = 0;
+	cfg.physAddr = -1;
+	if ((mpt_config(ioc, &cfg) == 0) && (cfg.hdr->PageLength > 0)) {
+		/* Issue the second config page request */
+		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+		data_sz = (int) cfg.hdr->PageLength * 4;
+		pg3_alloc = (SCSIDevicePage3_t *) pci_alloc_consistent(
+							ioc->pcidev, data_sz, &page_dma);
+		if (pg3_alloc) {
+			cfg.physAddr = page_dma;
+			cfg.pageAddr = (karg.hdr.channel << 8) | karg.hdr.id;
+			if ((rc = mpt_config(ioc, &cfg)) == 0) {
+				karg.message_rejects = (u32) le16_to_cpu(pg3_alloc->MsgRejectCount);
+				karg.phase_errors = (u32) le16_to_cpu(pg3_alloc->PhaseErrorCount);
+				karg.parity_errors = (u32) le16_to_cpu(pg3_alloc->ParityErrorCount);
+			}
+			pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg3_alloc, page_dma);
+		}
+	}
+
+	/* Copy the data from kernel memory to user memory
+	 */
+	if (copy_to_user((char *)arg, &karg, sizeof(hp_target_info_t))) {
+		printk(KERN_ERR "%s@%d::mptctl_hp_target_info - "
+			"Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /* Routine for the Compaq IOCTL commands.
  *
  * Outputs:	None.
@@ -2389,7 +2716,7 @@
 
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_compaq_ioctl() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_compaq_ioctl() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnumX));
 		return -ENODEV;
 	}
@@ -2406,7 +2733,7 @@
 	case CPQFCTS_GETPCIINFO:
 		ret = mptctl_cpq_getpciinfo(arg);
 		break;
-	case CPQFCTS_GETDRIVER:
+	case CPQFCTS_GETDRIVVER:
 		ret = mptctl_cpq_getdriver(arg);
 		break;
 	case CPQFCTS_CTLR_STATUS:
@@ -2462,7 +2789,7 @@
 
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_pciinfo() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_pciinfo() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -2563,7 +2890,7 @@
 
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_cpq_getdriver() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_cpq_getdriver() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -2627,7 +2954,7 @@
 
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_cpq_ctlr_status() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_cpq_ctlr_status() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -2683,7 +3010,7 @@
 
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_cpq_target_address() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_cpq_target_address() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -2786,7 +3113,7 @@
 	iocnumX = karg.lc & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_cpq_passthru() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_cpq_passthru() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -2971,7 +3298,7 @@
 	iocnumX = kfw32.iocnum & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		dtmprintk((KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n",
 				__LINE__, iocnumX));
 		return -ENODEV;
 	}
@@ -3011,7 +3338,7 @@
 	iocnumX = karg32.hdr.iocnum & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		dtmprintk((KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
 				__LINE__, iocnumX));
 		return -ENODEV;
 	}
@@ -3068,7 +3395,7 @@
 	iocnumX = karg32.lc & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
 				__LINE__, iocnumX));
 		return -ENODEV;
 	}
@@ -3180,12 +3507,16 @@
 	if (++where && err) goto out_fail;
 	err = register_ioctl32_conversion(CPQFCTS_CTLR_STATUS, NULL);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(CPQFCTS_GETDRIVER, NULL);
+	err = register_ioctl32_conversion(CPQFCTS_GETDRIVVER, NULL);
 	if (++where && err) goto out_fail;
 	err = register_ioctl32_conversion(CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS, NULL);
 	if (++where && err) goto out_fail;
 	err = register_ioctl32_conversion(CPQFCTS_SCSI_PASSTHRU32, sparc32_mptctl_cpq_passthru);
 	if (++where && err) goto out_fail;
+	err = register_ioctl32_conversion(HP_GETHOSTINFO, NULL);
+	if (++where && err) goto out_fail;
+	err = register_ioctl32_conversion(HP_GETTARGETINFO, NULL);
+	if (++where && err) goto out_fail;
 #endif		/*} linux >= 2.3.x */
 #endif		/*} sparc */
 
@@ -3234,10 +3565,12 @@
 	unregister_ioctl32_conversion(MPTCOMMAND32);
 	unregister_ioctl32_conversion(MPTFWDOWNLOAD32);
 	unregister_ioctl32_conversion(CPQFCTS_GETPCIINFO);
-	unregister_ioctl32_conversion(CPQFCTS_GETDRIVER);
+	unregister_ioctl32_conversion(CPQFCTS_GETDRIVVER);
 	unregister_ioctl32_conversion(CPQFCTS_CTLR_STATUS);
 	unregister_ioctl32_conversion(CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS);
 	unregister_ioctl32_conversion(CPQFCTS_SCSI_PASSTHRU32);
+	unregister_ioctl32_conversion(HP_GETHOSTINFO);
+	unregister_ioctl32_conversion(HP_GETTARGETINFO);
 #endif		/*} linux >= 2.3.x */
 #endif		/*} sparc */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/mptctl.h linux-2.4.21/drivers/message/fusion/mptctl.h
--- linux-2.4.20/drivers/message/fusion/mptctl.h	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/message/fusion/mptctl.h	2002-12-18 18:58:03.000000000 +0000
@@ -20,7 +20,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptctl.h,v 1.10 2002/05/28 15:57:16 pdelaney Exp $
+ *  $Id: mptctl.h,v 1.12 2002/10/17 20:15:58 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -319,12 +319,12 @@
 #define CPQFCTS_IOC_MAGIC 'Z'
 
 #define CPQFCTS_GETPCIINFO		_IOR(CPQFCTS_IOC_MAGIC, 1, cpqfc_pci_info_struct)
-#define CPQFCTS_GETDRIVER		_IOR(CPQFCTS_IOC_MAGIC, 2, int)
+#define CPQFCTS_GETDRIVVER		_IOR(CPQFCTS_IOC_MAGIC, 9, int)
 #define CPQFCTS_CTLR_STATUS		_IOR(CPQFCTS_IOC_MAGIC, 3, struct _cpqfc_ctlr_status)
-#define CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS	_IOR(CPQFCTS_IOC_MAGIC, 4, struct scsi_fctargaddress)
-#define CPQFCTS_SCSI_PASSTHRU		_IOWR(CPQFCTS_IOC_MAGIC, 5, VENDOR_IOCTL_REQ)
+#define CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS	_IOR(CPQFCTS_IOC_MAGIC, 13, struct scsi_fctargaddress)
+#define CPQFCTS_SCSI_PASSTHRU		_IOWR(CPQFCTS_IOC_MAGIC, 11, VENDOR_IOCTL_REQ)
 #if defined(__sparc__) && defined(__sparc_v9__)
-#define CPQFCTS_SCSI_PASSTHRU32		_IOWR(CPQFCTS_IOC_MAGIC, 5, VENDOR_IOCTL_REQ32)
+#define CPQFCTS_SCSI_PASSTHRU32		_IOWR(CPQFCTS_IOC_MAGIC, 11, VENDOR_IOCTL_REQ32)
 #endif
 
 typedef struct {
@@ -401,6 +401,90 @@
 #endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	HP Specific IOCTL Defines and Structures
+ */
+
+#define HP_GETHOSTINFO		_IOR(CPQFCTS_IOC_MAGIC, 20, hp_host_info_t)
+#define HP_GETTARGETINFO	_IOR(CPQFCTS_IOC_MAGIC, 21, hp_target_info_t)
+
+/* All HP IOCTLs must include this header
+ */
+typedef struct _hp_header {
+	unsigned int iocnum;
+	unsigned int host;
+	unsigned int channel;
+	unsigned int id;
+	unsigned int lun;
+} hp_header_t;
+
+/*  
+ *  Header:
+ *  iocnum 	required (input)
+ *  host 	ignored	
+ *  channe	ignored
+ *  id		ignored
+ *  lun		ignored
+ */
+typedef struct _hp_host_info {
+	hp_header_t	 hdr;
+	u16		 vendor;
+	u16		 device;
+	u16		 subsystem_vendor;
+	u16		 subsystem_id;
+	u8		 devfn;
+	u8		 bus;
+	ushort		 host_no;		/* SCSI Host number, if scsi driver not loaded*/
+	u8		 fw_version[16];	/* string */	
+	u8		 serial_number[24];	/* string */
+	u32		 ioc_status;	
+	u32		 bus_phys_width;
+	u32		 base_io_addr;
+	u32		 rsvd;
+	unsigned long	 hard_resets;		/* driver initiated resets */
+	unsigned long	 soft_resets;		/* ioc, external resets */
+	unsigned long	 timeouts;		/* num timeouts */
+} hp_host_info_t;
+
+/*  
+ *  Header:
+ *  iocnum 	required (input)
+ *  host 	required	
+ *  channel	required	(bus number)
+ *  id		required
+ *  lun		ignored
+ *
+ *  All error values between 0 and 0xFFFF in size.
+ */
+typedef struct _hp_target_info {
+	hp_header_t	 hdr;
+	u32 parity_errors;
+	u32 phase_errors;
+	u32 select_timeouts;
+	u32 message_rejects;
+	u32 negotiated_speed;
+	u8  negotiated_width;
+	u8  rsvd[7];				/* 8 byte alignment */
+} hp_target_info_t;
+
+#define HP_STATUS_OTHER		1
+#define HP_STATUS_OK		2
+#define HP_STATUS_FAILED	3
+
+#define HP_BUS_WIDTH_UNK	1
+#define HP_BUS_WIDTH_8		2
+#define HP_BUS_WIDTH_16		3
+#define HP_BUS_WIDTH_32		4
+
+#define HP_DEV_SPEED_ASYNC	2
+#define HP_DEV_SPEED_FAST	3
+#define HP_DEV_SPEED_ULTRA	4
+#define HP_DEV_SPEED_ULTRA2	5
+#define HP_DEV_SPEED_ULTRA160	6
+#define HP_DEV_SPEED_SCSI1	7
+#define HP_DEV_SPEED_ULTRA320	8
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/mptlan.c linux-2.4.21/drivers/message/fusion/mptlan.c
--- linux-2.4.20/drivers/message/fusion/mptlan.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/message/fusion/mptlan.c	2002-12-18 18:58:09.000000000 +0000
@@ -26,7 +26,7 @@
  *  Copyright (c) 2000-2002 LSI Logic Corporation
  *  Originally By: Noah Romer
  *
- *  $Id: mptlan.c,v 1.52 2002/05/06 13:45:07 sshirron Exp $
+ *  $Id: mptlan.c,v 1.53 2002/10/17 20:15:58 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -132,7 +132,7 @@
 	u32 total_received;
 	struct net_device_stats stats;	/* Per device statistics */
 
-	struct tq_struct post_buckets_task;
+	struct mpt_work_struct post_buckets_task;
 	unsigned long post_buckets_active;
 };
 
@@ -876,10 +876,22 @@
 	
 	if (test_and_set_bit(0, &priv->post_buckets_active) == 0) {
 		if (priority) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
+			schedule_work(&priv->post_buckets_task);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,40)
+			schedule_task(&priv->post_buckets_task);
+#else
 			queue_task(&priv->post_buckets_task, &tq_immediate);
 			mark_bh(IMMEDIATE_BH);
+#endif
 		} else {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
+			schedule_delayed_work(&priv->post_buckets_task, 1);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,40)
+			schedule_task(&priv->post_buckets_task);
+#else
 			queue_task(&priv->post_buckets_task, &tq_timer);
+#endif
 			dioprintk((KERN_INFO MYNAM ": post_buckets queued on "
 				   "timer.\n"));
 		}
@@ -1365,9 +1377,8 @@
 	priv->mpt_dev = mpt_dev;
 	priv->pnum = pnum;
 
-	memset(&priv->post_buckets_task, 0, sizeof(struct tq_struct));
-	priv->post_buckets_task.routine = mpt_lan_post_receive_buckets;
-	priv->post_buckets_task.data = dev;
+	memset(&priv->post_buckets_task, 0, sizeof(struct mpt_work_struct));
+	MPT_INIT_WORK(&priv->post_buckets_task, mpt_lan_post_receive_buckets, dev);
 	priv->post_buckets_active = 0;
 
 	dlprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/mptlan.h linux-2.4.21/drivers/message/fusion/mptlan.h
--- linux-2.4.20/drivers/message/fusion/mptlan.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/message/fusion/mptlan.h	2002-12-18 18:58:06.000000000 +0000
@@ -20,7 +20,12 @@
 #include <linux/slab.h>
 #include <linux/miscdevice.h>
 #include <linux/spinlock.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41)
 #include <linux/tqueue.h>
+#else
+#include <linux/workqueue.h>
+#endif
 #include <linux/delay.h>
 // #include <linux/trdevice.h>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/mptscsih.c linux-2.4.21/drivers/message/fusion/mptscsih.c
--- linux-2.4.20/drivers/message/fusion/mptscsih.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/message/fusion/mptscsih.c	2002-12-18 18:58:07.000000000 +0000
@@ -26,7 +26,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptscsih.c,v 1.101 2002/09/05 22:30:11 pdelaney Exp $
+ *  $Id: mptscsih.c,v 1.103 2002/10/17 20:15:59 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -110,6 +110,7 @@
 #define MPT_SCANDV_SENSE		(0x00000002)
 #define MPT_SCANDV_SOME_ERROR		(0x00000004)
 #define MPT_SCANDV_SELECTION_TIMEOUT	(0x00000008)
+#define MPT_SCANDV_ISSUE_SENSE		(0x00000010)
 
 #define MPT_SCANDV_MAX_RETRIES		(10)
 
@@ -163,7 +164,6 @@
 static int	mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex);
 static void	mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx);
 static int	mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init);
-
 static void	copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
 #ifndef MPT_SCSI_USE_NEW_EH
 static void	search_taskQ_for_cmd(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd);
@@ -182,7 +182,9 @@
 
 static VirtDevice	*mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen);
 void		mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56);
+#ifdef MPT_SAVE_AUTOSENSE
 static void	clear_sense_flag(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
+#endif
 static void	mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
 static void	mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags);
 static void	mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id);
@@ -197,8 +199,8 @@
 static int	mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io);
 static void	mptscsih_domainValidation(void *hd);
 static int	mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id);
-static void	mptscsih_qas_check(MPT_SCSI_HOST *hd);
-static void	mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int target);
+static void	mptscsih_qas_check(MPT_SCSI_HOST *hd, int id);
+static int	mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int target);
 static void	mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage);
 static void	mptscsih_fillbuf(char *buffer, int size, int index, int width);
 #endif
@@ -243,7 +245,7 @@
  */
 static spinlock_t mytaskQ_lock = SPIN_LOCK_UNLOCKED;
 static int mytaskQ_bh_active = 0;
-static struct tq_struct	mptscsih_ptaskfoo;
+static struct mpt_work_struct	mptscsih_ptaskfoo;
 static atomic_t	mpt_taskQdepth;
 #endif
 
@@ -254,7 +256,7 @@
 static spinlock_t dvtaskQ_lock = SPIN_LOCK_UNLOCKED;
 static int dvtaskQ_active = 0;
 static int dvtaskQ_release = 0;
-static struct tq_struct	mptscsih_dvTask;
+static struct mpt_work_struct	mptscsih_dvTask;
 #endif
 
 /*
@@ -332,14 +334,6 @@
 	pScsiReq = (SCSIIORequest_t *) mf;
 	pScsiReply = (SCSIIOReply_t *) mr;
 
-#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
-	if (hd->is_spi) {
-		u32 qtag = le32_to_cpu(pScsiReq->Control);
-		if (qtag & MPI_SCSIIO_CONTROL_UNTAGGED)
-			hd->ioc->spi_data.iocntr[sc->target]--;
-	}
-#endif
-
 	if (pScsiReply == NULL) {
 		/* special context reply handling */
 
@@ -358,7 +352,9 @@
 						dlen);
 			}
 		}
+#ifdef MPT_SAVE_AUTOSENSE
 		clear_sense_flag(hd, pScsiReq);
+#endif
 	} else {
 		u32	 xfer_cnt;
 		u16	 status;
@@ -443,17 +439,21 @@
 			 *  precedence!
 			 */
 			sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
+#ifdef MPT_SAVE_AUTOSENSE
 			clear_sense_flag(hd, pScsiReq);
-			if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+#endif
+			if (scsi_state == 0) {
+				;
+			} else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
 				/* Have already saved the status and sense data
 				 */
 				;
-			} else if (pScsiReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
+			} else if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
 				/* What to do?
 				 */
 				sc->result = DID_SOFT_ERROR << 16;
 			}
-			else if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
+			else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
 				/*  Not real sure here either...  */
 				sc->result = DID_RESET << 16;
 			}
@@ -494,9 +494,12 @@
 		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
 		case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */
 			sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
+#ifdef MPT_SAVE_AUTOSENSE
 			clear_sense_flag(hd, pScsiReq);
-
-			if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+#endif
+			if (scsi_state == 0) {
+				;
+			} else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
 				/*
 				 * If running agains circa 200003dd 909 MPT f/w,
 				 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
@@ -527,7 +530,7 @@
 #endif
 
 			}
-			else if (pScsiReply->SCSIState &
+			else if (scsi_state &
 			         (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
 			   ) {
 				/*
@@ -535,11 +538,11 @@
 				 */
 				sc->result = DID_SOFT_ERROR << 16;
 			}
-			else if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
+			else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
 				/*  Not real sure here either...  */
 				sc->result = DID_RESET << 16;
 			}
-			else if (pScsiReply->SCSIState & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
+			else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
 				/* Device Inq. data indicates that it supports
 				 * QTags, but rejects QTag messages.
 				 * This command completed OK.
@@ -946,11 +949,6 @@
 			mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
 		}
 	}
-#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
-	/* Clear untagged counting array */
-	for (ii= 0; ii < MPT_MAX_SCSI_DEVICES; ii++)
-		hd->ioc->spi_data.iocntr[ii] = 0;
-#endif
 
 	return;
 }
@@ -1035,21 +1033,13 @@
 	MPT_FRAME_HDR	*chain;
 	u8		*mem;
 	unsigned long	flags;
-	int		sz, ii, numChain;
-
+	int		sz, ii, num_chain;
+	int 		scale, num_sge;
 
-        /* Chain buffer allocations
-	 * Allocate and initialize tracker structures
+	/* ReqToChain size must equal the req_depth
+	 * index = req_idx
 	 */
-	if (hd->ioc->req_sz <= 64)
-		numChain = MPT_SG_REQ_64_SCALE * hd->ioc->req_depth;
-	else if (hd->ioc->req_sz <= 96)
-		numChain = MPT_SG_REQ_96_SCALE * hd->ioc->req_depth;
-	else
-		numChain = MPT_SG_REQ_128_SCALE * hd->ioc->req_depth;
-
-	sz = numChain * sizeof(int);
-
+	sz = hd->ioc->req_depth * sizeof(int);
 	if (hd->ReqToChain == NULL) {
 		mem = kmalloc(sz, GFP_ATOMIC);
 		if (mem == NULL)
@@ -1061,6 +1051,38 @@
 	}
 	memset(mem, 0xFF, sz);
 
+
+	/* ChainToChain size must equal the total number
+	 * of chain buffers to be allocated.
+	 * index = chain_idx
+	 *
+	 * Calculate the number of chain buffers needed(plus 1) per I/O 
+	 * then multiply the the maximum number of simultaneous cmds
+	 *
+	 * num_sge = num sge in request frame + last chain buffer
+	 * scale = num sge per chain buffer if no chain element
+	 */
+	scale = hd->ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
+	if (sizeof(dma_addr_t) == sizeof(u64))
+		num_sge =  scale + (hd->ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
+	else
+		num_sge =  1+ scale + (hd->ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
+
+	num_chain = 1;
+	while (hd->max_sge - num_sge > 0) {
+		num_chain++;
+		num_sge += (scale - 1);
+	}
+	num_chain++;
+
+	if ((int) hd->ioc->chip_type > (int) FC929)
+		num_chain *= MPT_SCSI_CAN_QUEUE;
+	else
+		num_chain *= MPT_FC_CAN_QUEUE;
+
+	hd->num_chain = num_chain;
+
+	sz = num_chain * sizeof(int);
 	if (hd->ChainToChain == NULL) {
 		mem = kmalloc(sz, GFP_ATOMIC);
 		if (mem == NULL)
@@ -1072,10 +1094,10 @@
 	}
 	memset(mem, 0xFF, sz);
 
+	sz = num_chain * hd->ioc->req_sz;
 	if (hd->ChainBuffer == NULL) {
 		/* Allocate free chain buffer pool
 		 */
-		sz = numChain * hd->ioc->req_sz;
 		mem = pci_alloc_consistent(hd->ioc->pcidev, sz, &hd->ChainBufferDMA);
 		if (mem == NULL)
 			return -1;
@@ -1101,7 +1123,7 @@
 	/* Post the chain buffers to the FreeChainQ.
 	 */
 	mem = (u8 *)hd->ChainBuffer;
-	for (ii=0; ii < numChain; ii++) {
+	for (ii=0; ii < num_chain; ii++) {
 		chain = (MPT_FRAME_HDR *) mem;
 		Q_ADD_TAIL(&hd->FreeChainQ.head, &chain->u.frame.linkage, MPT_FRAME_HDR);
 		mem += hd->ioc->req_sz;
@@ -1238,8 +1260,7 @@
 #endif
 			sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST));
 			if (sh != NULL) {
-				save_flags(flags);
-				cli();
+				mptscsih_lock(this, flags);
 				sh->io_port = 0;
 				sh->n_io_port = 0;
 				sh->irq = 0;
@@ -1266,12 +1287,21 @@
 				}
 				sh->max_lun = MPT_LAST_LUN + 1;
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
+				sh->max_sectors = MPT_SCSI_MAX_SECTORS;
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) || defined CONFIG_HIGHIO
+				sh->highmem_io = 1;
+#endif
 				sh->this_id = this->pfacts[portnum].PortSCSIID;
 
 				/* OS entry to allow host drivers to force
 				 * a queue depth on a per device basis.
 				 */
 				sh->select_queue_depths = mptscsih_select_queue_depths;
+				/* Required entry.
+				 */
+				sh->unique_id = this->id;
 
 				/* Verify that we won't exceed the maximum
 				 * number of chain buffers
@@ -1303,10 +1333,11 @@
 				 */
 				scsi_set_pci_device(sh, this->pcidev);
 
-				restore_flags(flags);
+				mptscsih_unlock(this, flags);
 
 				hd = (MPT_SCSI_HOST *) sh->hostdata;
 				hd->ioc = this;
+				hd->max_sge = sh->sg_tablesize;
 
 				if ((int)this->chip_type > (int)FC929)
 					hd->is_spi = 1;
@@ -1546,7 +1577,6 @@
 		int szc2chain = 0;
 		int szchain = 0;
 		int szQ = 0;
-		int scale;
 
 		/* Synchronize disk caches
 		 */
@@ -1554,13 +1584,6 @@
 
 		sz1 = sz2 = sz3 = 0;
 
-		if (hd->ioc->req_sz <= 64)
-			scale = MPT_SG_REQ_64_SCALE;
-		else if (hd->ioc->req_sz <= 96)
-			scale = MPT_SG_REQ_96_SCALE;
-		else
-			scale = MPT_SG_REQ_128_SCALE;
-
 		if (hd->ScsiLookup != NULL) {
 			sz1 = hd->ioc->req_depth * sizeof(void *);
 			kfree(hd->ScsiLookup);
@@ -1568,19 +1591,19 @@
 		}
 
 		if (hd->ReqToChain != NULL) {
-			szr2chain = scale * hd->ioc->req_depth * sizeof(int);
+			szr2chain = hd->ioc->req_depth * sizeof(int);
 			kfree(hd->ReqToChain);
 			hd->ReqToChain = NULL;
 		}
 
 		if (hd->ChainToChain != NULL) {
-			szc2chain = scale * hd->ioc->req_depth * sizeof(int);
+			szc2chain = hd->num_chain * sizeof(int);
 			kfree(hd->ChainToChain);
 			hd->ChainToChain = NULL;
 		}
 
 		if (hd->ChainBuffer != NULL) {
-			sz2 = scale * hd->ioc->req_depth * hd->ioc->req_sz;
+			sz2 = hd->num_chain * hd->ioc->req_sz;
 			szchain = szr2chain + szc2chain + sz2;
 
 			pci_free_consistent(hd->ioc->pcidev, sz2,
@@ -1603,7 +1626,7 @@
 			if (hd->is_spi) {
 				max = MPT_MAX_SCSI_DEVICES;
 			} else {
-				max = MPT_MAX_FC_DEVICES;
+				max = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
 			}
 			for (ii=0; ii < max; ii++) {
 				if (hd->Targets[ii]) {
@@ -1817,6 +1840,7 @@
 	dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
 			(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
 
+#ifdef MPT_SAVE_AUTOSENSE
 	/* 20000617 -sralston
 	 *  GRRRRR...  Shouldn't have to do this but...
 	 *  Do explicit check for REQUEST_SENSE and cached SenseData.
@@ -1852,6 +1876,7 @@
 			}
 		}
 	}
+#endif
 
 	if (hd->resetPending) {
 		/* Prevent new commands from being issued
@@ -2032,9 +2057,7 @@
 					if (!dvtaskQ_active) {
 						dvtaskQ_active = 1;
 						spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
-						mptscsih_dvTask.sync = 0;
-						mptscsih_dvTask.routine = mptscsih_domainValidation;
-						mptscsih_dvTask.data = (void *) hd;
+						MPT_INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd); 
 
 						SCHEDULE_TASK(&mptscsih_dvTask);
 					} else {
@@ -2051,9 +2074,6 @@
 					issueCmd = 0;
 				}
 
-				if (qtag == MPI_SCSIIO_CONTROL_UNTAGGED)
-					hd->ioc->spi_data.iocntr[target]++;
-
 				/* Set the DV flags.
 				 */
 				if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
@@ -2531,6 +2551,8 @@
 
 		/* Isse the Task Mgmt request.
 		 */
+		if (hd->hard_resets < -1)
+			hd->hard_resets++;
 		rc = mptscsih_IssueTaskMgmt(hd, type, target, lun, ctx2abort, sleepFlag);
 		if (rc) {
 #ifdef MPT_SCSI_USE_NEW_EH
@@ -2549,7 +2571,7 @@
 	}
 #endif
 
-	if (rc) {
+	if (rc || ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw)) {
 		dtmprintk((MYIOC_s_INFO_FMT "Falling through to HardReset! \n",
 			 hd->ioc->name));
 		rc = mpt_HardResetHandler(hd->ioc, sleepFlag);
@@ -2686,6 +2708,9 @@
 	printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n",
 	       hd->ioc->name, atomic_read(&queue_depth));
 
+	if (hd->timeouts < -1)
+		hd->timeouts++;
+
 	/* Find this command
 	 */
 	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
@@ -2908,6 +2933,9 @@
 	printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n",
 	       hd->ioc->name, atomic_read(&queue_depth));
 
+	if (hd->timeouts < -1)
+		hd->timeouts++;
+
 	/*  Wait a fixed amount of time for the TM pending flag to be cleared.
 	 *  If we time out, then we return a FAILED status to the caller.  This
 	 *  call to mptscsih_tm_pending_wait() will set the pending flag if we are
@@ -3064,7 +3092,7 @@
 {
 	MPT_SCSI_HOST		*hd;
 	MPT_FRAME_HDR		*mf;
-	struct tq_struct	*ptaskfoo;
+	struct mpt_work_struct	*ptaskfoo;
 	unsigned long		 flags;
 	int			 scpnt_idx;
 
@@ -3078,6 +3106,9 @@
 		return SCSI_ABORT_NOT_RUNNING;
 	}
 
+	if (hd->timeouts < -1)
+		hd->timeouts++;
+
 	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
 		/* Cmd not found in ScsiLookup.
 		 * If found in doneQ, delete from Q.
@@ -3172,10 +3203,8 @@
 		 *  Oh how cute, no alloc/free/mgmt needed if we use
 		 *  (bottom/unused portion of) MPT request frame.
 		 */
-		ptaskfoo = (struct tq_struct *) &mptscsih_ptaskfoo;
-		ptaskfoo->sync = 0;
-		ptaskfoo->routine = mptscsih_taskmgmt_bh;
-		ptaskfoo->data = SCpnt;
+		ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo;
+		MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt); 
 
 		SCHEDULE_TASK(ptaskfoo);
 	} else  {
@@ -3200,7 +3229,7 @@
 {
 	MPT_SCSI_HOST		*hd;
 	MPT_FRAME_HDR		*mf;
-	struct tq_struct	*ptaskfoo;
+	struct mpt_work_struct	*ptaskfoo;
 	unsigned long		 flags;
 	int			 scpnt_idx;
 
@@ -3213,6 +3242,9 @@
 		return SCSI_RESET_SUCCESS;
 	}
 
+	if (hd->timeouts < -1)
+		hd->timeouts++;
+
 	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
 		/* Cmd not found in ScsiLookup.
 		 * If found in doneQ, delete from Q.
@@ -3302,10 +3334,8 @@
 		 *  Oh how cute, no alloc/free/mgmt needed if we use
 		 *  (bottom/unused portion of) MPT request frame.
 		 */
-		ptaskfoo = (struct tq_struct *) &mptscsih_ptaskfoo;
-		ptaskfoo->sync = 0;
-		ptaskfoo->routine = mptscsih_taskmgmt_bh;
-		ptaskfoo->data = SCpnt;
+		ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo;
+		MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt); 
 
 		SCHEDULE_TASK(ptaskfoo);
 	} else  {
@@ -3626,9 +3656,12 @@
 /*
  *	This is anyones guess quite frankly.
  */
-
 int
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
+mptscsih_bios_param(Disk * disk, struct block_device *dev, int *ip)
+#else
 mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip)
+#endif
 {
 	int size;
 
@@ -3670,7 +3703,7 @@
 			if (hd->is_spi)
 				max = MPT_MAX_SCSI_DEVICES;
 			else
-				max = MPT_MAX_FC_DEVICES;
+				max = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
 
 			for (ii=0; ii < max; ii++) {
 				pTarget = hd->Targets[ii];
@@ -3816,6 +3849,7 @@
 		/* save sense data to the target device
 		 */
 		if (target) {
+#ifdef MPT_SAVE_AUTOSENSE
 			int sz;
 
 			sz = MIN(pReq->SenseBufferLength, sense_count);
@@ -3823,6 +3857,7 @@
 				sz =  SCSI_STD_SENSE_BYTES;
 			memcpy(target->sense, sense_data, sz);
 			target->tflags |= MPT_TARGET_FLAGS_VALID_SENSE;
+#endif
 
 #ifdef ABORT_FIX
 			if (sz >= SCSI_STD_SENSE_BYTES) {
@@ -4166,10 +4201,12 @@
 		/* FIXME! */
 		break;
 	case MPI_EVENT_IOC_BUS_RESET:			/* 04 */
-		/* FIXME! */
-		break;
 	case MPI_EVENT_EXT_BUS_RESET:			/* 05 */
-		/* FIXME! */
+		hd = NULL;
+		if (ioc->sh)
+			hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+		if (hd && (hd->is_spi) && (hd->soft_resets < -1))
+			hd->soft_resets++;
 		break;
 	case MPI_EVENT_LOGOUT:				/* 09 */
 		/* FIXME! */
@@ -4506,6 +4543,7 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#if 0
 static int dump_sd(char *foo, unsigned char *sd)
 {
 	int snsLen = 8 + SD_Additional_Sense_Length(sd);
@@ -4518,6 +4556,7 @@
 
 	return l;
 }
+#endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*  Do ASC/ASCQ lookup/grindage to English readable string(s)  */
@@ -4609,6 +4648,15 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
+ *  SCSI Information Report; desired output format...
+ *---
+SCSI Error: (iocnum:target_id:LUN) Status=02h (CHECK CONDITION)
+  Key=6h (UNIT ATTENTION); FRU=03h
+  ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"
+  CDB: 00 00 00 00 00 00 - TestUnitReady
+ *---
+ */
+/*
  *  SCSI Error Report; desired output format...
  *---
 SCSI Error Report =-=-=-=-=-=-=-=-=-=-=-=-=-= (ioc0,scsi0:0)
@@ -4632,6 +4680,22 @@
 	unsigned char	 ascq		= SD_ASCQ(ioop->sensePtr);
 	int		 l;
 
+	/* Change the error logging to only report errors on
+	 * read and write commands. Ignore errors on other commands.
+	 * Should this be configurable via proc?
+	 */
+	switch (ioop->cdbPtr[0]) {
+	case READ_6:
+	case WRITE_6:
+	case READ_10:
+	case WRITE_10:
+	case READ_12:
+	case WRITE_12:
+		break;
+	default:
+		return 0;
+	}
+
 	/*
 	 *  More quiet mode.
 	 *  Filter out common, repetitive, warning-type errors...  like:
@@ -4642,6 +4706,7 @@
 	if (sk == SK_NO_SENSE) {
 		return 0;
 	}
+
 	if (	(sk==SK_UNIT_ATTENTION	&& asc==0x29 && (ascq==0x00 || ascq==0x01))
 	     || (sk==SK_NOT_READY	&& asc==0x04 && (ascq==0x01 || ascq==0x02))
 	     || (sk==SK_ILLEGAL_REQUEST && asc==0x25 && ascq==0x00)
@@ -4696,20 +4761,12 @@
 	else if (mpt_ScsiOpcodesPtr)
 		opstr = mpt_ScsiOpcodesPtr[ioop->cdbPtr[0]];
 
-	l = sprintf(foo, "SCSI Error Report =-=-= (%s)\n"
-	  "  SCSI_Status=%02Xh (%s)\n"
-	  "  Original_CDB[]:",
-			ioop->DevIDStr,
-			ioop->SCSIStatus,
-			statstr);
-	l += dump_cdb(foo+l, ioop->cdbPtr);
-	if (opstr)
-		l += sprintf(foo+l, " - \"%s\"", opstr);
-	l += sprintf(foo+l, "\n  SenseData[%02Xh]:", 8+SD_Additional_Sense_Length(ioop->sensePtr));
-	l += dump_sd(foo+l, ioop->sensePtr);
-	l += sprintf(foo+l, "\n  SenseKey=%Xh (%s); FRU=%02Xh\n  ASC/ASCQ=%02Xh/%02Xh",
-			sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq );
-
+	l = sprintf(foo, "SCSI Error: (%s) Status=%02Xh (%s)\n",
+			  ioop->DevIDStr,
+			  ioop->SCSIStatus,
+			  statstr);
+	l += sprintf(foo+l, " Key=%Xh (%s); FRU=%02Xh\n ASC/ASCQ=%02Xh/%02Xh",
+		  sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq );
 	{
 		const char	*x1, *x2, *x3, *x4;
 		x1 = x2 = x3 = x4 = "";
@@ -4721,11 +4778,11 @@
 				l += sprintf(foo+l, " %s%s%s%s", x1,x2,x3,x4);
 		}
 	}
-
-#if 0
-	if (SPECIAL_ASCQ(asc,ascq))
-		l += sprintf(foo+l, " (%02Xh)", ascq);
-#endif
+	l += sprintf(foo+l, "\n CDB:");
+	l += dump_cdb(foo+l, ioop->cdbPtr);
+	if (opstr)
+		l += sprintf(foo+l, " - \"%s\"", opstr);
+	l += sprintf(foo+l, "\n");
 
 	PrintF(("%s\n", foo));
 
@@ -4783,14 +4840,16 @@
 	}
 
 	if (vdev) {
-		if (hd->ioc->spi_data.isRaid & (1 << target_id))
+		if (hd->ioc->spi_data.isRaid & (1 << target_id)) {
 			vdev->raidVolume = 1;
-		else
+			ddvtprintk((KERN_INFO "RAID Volume @ id %d\n", target_id));
+		} else
 			vdev->raidVolume = 0;
 	}
 
 	if (vdev && data) {
-		if (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
+		if ((!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) || 
+		((dlen > 56) && (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56)))) {
 
 			/* Copy the inquiry data  - if we haven't yet.
 			*/
@@ -4801,9 +4860,10 @@
 
 			/* Update the target capabilities
 			 */
-			if (dlen > 56)
+			if (dlen > 56) {
 				mptscsih_setTargetNegoParms(hd, vdev, data[56]);
-			else
+				vdev->tflags |= MPT_TARGET_FLAGS_VALID_56;
+			} else
 				mptscsih_setTargetNegoParms(hd, vdev, 0);
 
 			/* If LUN 0, tape and have not done DV, set the DV flag.
@@ -4845,6 +4905,8 @@
 	u8 version, nfactor;
 	u8 noQas = 1;
 
+	ddvtprintk((KERN_INFO "set Target: (id %d) byte56 0x%x\n", id, byte56));
+
 	/* Set flags based on Inquiry data
 	 */
 	if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
@@ -4863,12 +4925,18 @@
 				 */
 				if ((byte56 & 0x04) == 0)
 					factor = MPT_ULTRA2;
+				else if ((byte56 & 0x03) == 0)
+					factor = MPT_ULTRA160;
 				else
 					factor = MPT_ULTRA320;
 
-				/* bit 1 QAS support, non-raid only
+				/* If RAID, never disable QAS
+				 * else if non RAID, do not disable 
+				 *   QAS if bit 1 is set
+				 * bit 1 QAS support, non-raid only
+				 * bit 0 IU support
 				 */
-				if ((target->raidVolume == 0) && (byte56 & 0x02) != 0)
+				if ((target->raidVolume == 1) || ((byte56 & 0x02) != 0))
 					noQas = 0;
 
 				offset = pspi_data->maxSyncOffset;
@@ -4953,6 +5021,7 @@
 			VirtDevice	*vdev;
 			int ii;
 
+			ddvtprintk((KERN_INFO "Disabling QAS!\n"));
 			pspi_data->noQas = MPT_TARGET_NO_NEGO_QAS;
 			for (ii = 0; ii < id; ii++) {
 				vdev = hd->Targets[id];
@@ -4966,6 +5035,7 @@
 	return;
 }
 
+#ifdef MPT_SAVE_AUTOSENSE
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  Clear sense valid flag.
@@ -4981,6 +5051,7 @@
 
 	return;
 }
+#endif
 
 /* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
  * Else set the NEED_DV flag after Read Capacity Issued (disks) 
@@ -5158,6 +5229,7 @@
 				maxfactor = MPT_ASYNC;
 		}
 
+
 		/* Set the negotiation flags.
 		 */
 		negoFlags = ioc->spi_data.noQas;
@@ -5179,6 +5251,17 @@
 			//negoFlags = MPT_TARGET_NO_NEGO_SYNC;
 		}
 
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+		/* Force to async and narrow if DV has not been executed
+		 * for this ID
+		 */
+		if ((hd->ioc->spi_data.dvStatus[id] & MPT_SCSICFG_DV_NOT_DONE) != 0) {
+			width = 0;
+			factor = MPT_ASYNC;
+			offset = 0;
+		}
+#endif
+
 		/* If id is not a raid volume, get the updated
 		 * transmission settings from the target structure.
 		 */
@@ -5339,7 +5422,7 @@
  *
  *	Remark: Sets a completion code and (possibly) saves sense data
  *	in the IOC member localReply structure.
- *	Used ONLY for bus scan, DV and other internal commands.
+ *	Used ONLY for DV and other internal commands.
  */
 static int
 mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
@@ -5375,10 +5458,13 @@
 	atomic_dec(&queue_depth);
 
 	hd->pLocal = &hd->localReply;
+	hd->pLocal->scsiStatus = 0;
 
 	/* If target struct exists, clear sense valid flag.
 	 */
+#ifdef MPT_SAVE_AUTOSENSE
 	clear_sense_flag(hd, pReq);
+#endif
 
 	if (mr == NULL) {
 		completionCode = MPT_SCANDV_GOOD;
@@ -5390,7 +5476,7 @@
 
 		status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
 
-		ddvprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
+		ddvtprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
 			     status, pReply->SCSIState, pReply->SCSIStatus,
 			     le32_to_cpu(pReply->IOCLogInfo)));
 
@@ -5430,7 +5516,9 @@
 					completionCode = MPT_SCANDV_SOME_ERROR;
 
 			} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+#ifdef MPT_SAVE_AUTOSENSE
 				VirtDevice	*target;
+#endif
 				u8		*sense_data;
 				int		 sz;
 
@@ -5445,25 +5533,33 @@
 							SCSI_STD_SENSE_BYTES);
 				memcpy(hd->pLocal->sense, sense_data, sz);
 
+#ifdef MPT_SAVE_AUTOSENSE
 				target = hd->Targets[pReq->TargetID];
 				if (target) {
 					memcpy(target->sense, sense_data, sz);
 					target->tflags
 						|= MPT_TARGET_FLAGS_VALID_SENSE;
 				}
+#endif
 
 				ddvprintk((KERN_NOTICE "  Check Condition, sense ptr %p\n",
 						sense_data));
-			} else if (pReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED |
-							MPI_SCSI_STATE_NO_SCSI_STATUS)) {
+			} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
+				if (pReq->CDB[0] == CMD_Inquiry)
+					completionCode = MPT_SCANDV_ISSUE_SENSE;
+				else
+					completionCode = MPT_SCANDV_DID_RESET;
+			}
+			else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
 				completionCode = MPT_SCANDV_DID_RESET;
-			} else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
+			else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
 				completionCode = MPT_SCANDV_DID_RESET;
-			} else {
+			else {
 				/* If no error, this will be equivalent
 				 * to MPT_SCANDV_GOOD
 				 */
-				completionCode = (int) pReply->SCSIStatus;
+				completionCode = MPT_SCANDV_GOOD;
+				hd->pLocal->scsiStatus = pReply->SCSIStatus;
 			}
 			break;
 
@@ -5480,7 +5576,7 @@
 
 		}	/* switch(status) */
 
-		ddvprintk((KERN_NOTICE "  completionCode set to %08xh\n",
+		ddvtprintk((KERN_NOTICE "  completionCode set to %08xh\n",
 				completionCode));
 	} /* end of address reply case */
 
@@ -5703,6 +5799,14 @@
 		cmdTimeout = 15;
 		break;
 
+	case CMD_RequestSense:
+		cmdLen = 6;
+		CDB[0] = cmd;
+		CDB[4] = io->size;
+		dir = MPI_SCSIIO_CONTROL_READ;
+		cmdTimeout = 10;
+		break;
+
 	case CMD_ReadBuffer:
 		cmdLen = 10;
 		dir = MPI_SCSIIO_CONTROL_READ;
@@ -5807,6 +5911,12 @@
 	else
 		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
 
+	if (cmd == CMD_RequestSense) {
+		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
+		ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
+			hd->ioc->name, cmd));
+	}
+
 	for (ii=0; ii < 16; ii++)
 		pScsiReq->CDB[ii] = CDB[ii];
 
@@ -5988,7 +6098,7 @@
 		/* If target Ptr NULL or if this target is NOT a disk, skip.
 		 */
 	//	if (pTarget && ((pTarget->inq_data[0] & 0x1F) == 0)) {
-		if (pTarget) {
+		if ((pTarget) && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)){
 			for (lun=0; lun <= MPT_LAST_LUN; lun++) {
 				/* If LUN present, issue the command
 				 */
@@ -6093,25 +6203,8 @@
 				dvStatus = hd->ioc->spi_data.dvStatus[id];
 
 				if (dvStatus & MPT_SCSICFG_NEED_DV) {
-					VirtDevice *pTarget = hd->Targets[id];
 					did++;
-					if (pTarget && ((pTarget->tflags & MPT_TARGET_FLAGS_Q_YES) == 0)){
-						if (hd->ioc->spi_data.iocntr[id] == 0) {
-							hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
-						} else {
-							/* Wait until not busy
-							 */
-							ddvtprintk((MYIOC_s_NOTE_FMT 
-							" DV Wait: %d untagged and busy. cntr %d\n",
-							ioc->name, id, 
-							hd->ioc->spi_data.iocntr[id]));
-							continue;
-						}
-					} else {
-						hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
-					}
-
-
+					hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
 					hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV;
 
 					set_current_state(TASK_INTERRUPTIBLE);
@@ -6130,9 +6223,16 @@
 						}
 					}
 
-					mptscsih_doDv(hd, 0, id);
-
-					hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING);
+					if (mptscsih_doDv(hd, 0, id) == 1) {
+						/* Untagged device was busy, try again
+						 */
+						hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_NEED_DV;
+						hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING;
+					} else {
+						/* DV is complete. Clear flags.
+						 */
+						hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING);
+					}
 
 					if (isPhysDisk) {
 						for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
@@ -6148,7 +6248,7 @@
 					post_pendingQ_commands(hd);
 
 					if (hd->ioc->spi_data.noQas)
-						mptscsih_qas_check(hd);
+						mptscsih_qas_check(hd, id);
 				}
 			}
 		}
@@ -6182,7 +6282,7 @@
 
 /* Write SDP1 if no QAS has been enabled
  */
-static void mptscsih_qas_check(MPT_SCSI_HOST *hd)
+static void mptscsih_qas_check(MPT_SCSI_HOST *hd, int id)
 {
 	VirtDevice *pTarget = NULL;
 	int ii;
@@ -6191,6 +6291,9 @@
 		return;
 
 	for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+		if (ii == id)
+			continue;
+
 		if ((hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_NOT_DONE) != 0)
 			continue;
 
@@ -6231,7 +6334,7 @@
  *
  *	Return: None.
  */
-static void
+static int
 mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
 {
 	MPT_ADAPTER		*ioc = hd->ioc;
@@ -6259,6 +6362,7 @@
 	int			 notDone;
 	int			 patt;
 	int			 repeat;
+	int			 retcode = 0;
 	char			 firstPass = 1;
 	char			 doFallback = 0;
 	char			 readPage0;
@@ -6266,13 +6370,13 @@
 	char			 inq0 = 0;
 
 	if (ioc->spi_data.sdp1length == 0)
-		return;
+		return 0;
 
 	if (ioc->spi_data.sdp0length == 0)
-		return;
+		return 0;
 
 	if (id == ioc->pfacts[portnum].PortSCSIID)
-		return;
+		return 0;
 
 	lun = 0;
 	bus = 0;
@@ -6292,7 +6396,7 @@
 	dv.cmd = MPT_GET_NVRAM_VALS;
 	mptscsih_dv_parms(hd, &dv, NULL);
 	if ((!dv.max.width) && (!dv.max.offset))
-		return;
+		return 0;
 
 	/* Prep SCSI IO structure
 	 */
@@ -6303,19 +6407,29 @@
 	iocmd.physDiskNum = -1;
 	iocmd.rsvd = iocmd.rsvd2 = 0;
 
-	/* Use tagged commands if possible.
-	 */
 	pTarget = hd->Targets[id];
-	if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
-		iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
-
 	if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
 		/* Another GEM workaround. Check peripheral device type,
 		 * if PROCESSOR, quit DV.
 		 */
 		if (((pTarget->inq_data[0] & 0x1F) == 0x03) || ((pTarget->inq_data[0] & 0x1F) > 0x08)) {
 			pTarget->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
-			return;
+			return 0;
+		}
+	}
+
+	/* Use tagged commands if possible.
+	 */
+	if (pTarget) {
+		if (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
+			iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
+		else {
+			if (hd->ioc->facts.FWVersion.Word < 0x01000600)
+				return 0;
+
+			if ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
+				(hd->ioc->facts.FWVersion.Word < 0x01010B00))
+				return 0;
 		}
 	}
 
@@ -6345,7 +6459,7 @@
 
 	pDvBuf = pci_alloc_consistent(ioc->pcidev, dv_alloc, &dvbuf_dma);
 	if (pDvBuf == NULL)
-		return;
+		return 0;
 
 	sz = 0;
 	pbuf1 = (u8 *)pDvBuf;
@@ -6427,8 +6541,10 @@
 	hd->pLocal = NULL;
 	readPage0 = 0;
 	sz = SCSI_STD_INQUIRY_BYTES;
+	rc = MPT_SCANDV_GOOD;
 	while (1) {
 		ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test.\n", ioc->name));
+		retcode = 0;
 		dv.cmd = MPT_SET_MIN;
 		mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
 
@@ -6439,12 +6555,61 @@
 		if (mpt_config(hd->ioc, &cfg) != 0)
 			goto target_done;
 
+		/* Wide - narrow - wide workaround case
+		 */
+		if ((rc == MPT_SCANDV_ISSUE_SENSE) && dv.max.width) { 
+			/* Send an untagged command to reset disk Qs corrupted
+			 * when a parity error occurs on a Request Sense.
+			 */
+			if ((hd->ioc->facts.FWVersion.Word >= 0x01000600) || 
+				((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
+				(hd->ioc->facts.FWVersion.Word < 0x01010B00)) ) {
+
+				iocmd.cmd = CMD_RequestSense;
+				iocmd.data_dma = buf1_dma;
+				iocmd.data = pbuf1;
+				iocmd.size = 0x12;
+				if (mptscsih_do_cmd(hd, &iocmd) < 0)
+					goto target_done;
+				else {
+					if (hd->pLocal == NULL)
+						goto target_done;
+					rc = hd->pLocal->completion;
+					if ((rc == MPT_SCANDV_GOOD) || (rc == MPT_SCANDV_SENSE)) {
+						dv.max.width = 0;
+						doFallback = 0;
+					} else
+						goto target_done;
+				}
+			} else
+				goto target_done;
+		}
+
 		iocmd.cmd = CMD_Inquiry;
 		iocmd.data_dma = buf1_dma;
 		iocmd.data = pbuf1;
 		iocmd.size = sz;
 		if (mptscsih_do_cmd(hd, &iocmd) < 0)
 			goto target_done;
+		else {
+			if (hd->pLocal == NULL)
+				goto target_done;
+			rc = hd->pLocal->completion;
+			if (rc == MPT_SCANDV_GOOD) {
+				if (hd->pLocal->scsiStatus == STS_BUSY) {
+					retcode = 1;
+					goto target_done;
+				}
+			} else if  (rc == MPT_SCANDV_SENSE) {
+				;
+			} else {
+				/* If first command doesn't complete
+				 * with a good status or with a check condition,
+				 * exit.
+				 */
+				goto target_done;
+			}
+		}
 
 		/* Another GEM workaround. Check peripheral device type,
 		 * if PROCESSOR, quit DV.
@@ -6528,7 +6693,9 @@
 				}
 
 
-			} else if ((rc == MPT_SCANDV_DID_RESET) || (rc == MPT_SCANDV_SENSE))
+			} else if (rc == MPT_SCANDV_ISSUE_SENSE) 
+				doFallback = 1;	/* set fallback flag */
+			else if ((rc == MPT_SCANDV_DID_RESET) || (rc == MPT_SCANDV_SENSE))
 				doFallback = 1;	/* set fallback flag */
 			else
 				goto target_done;
@@ -6951,8 +7118,7 @@
 
 	/* Set if cfg1_dma_addr contents is valid
 	 */
-	if (cfg.hdr != NULL) {
-
+	if ((cfg.hdr != NULL) && (retcode == 0)){
 		/* If disk, not U320, disable QAS
 		 */
 		if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320))
@@ -6961,6 +7127,10 @@
 		dv.cmd = MPT_SAVE;
 		mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
 
+#if 0	
+	/* Double writes to SDP1 can cause problems, 
+	 * skip here since unnecessary
+	 */
 		/* Save the final negotiated settings to
 		 * SCSI device page 1.
 		 */
@@ -6969,13 +7139,14 @@
 		cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
 		cfg.dir = 1;
 		mpt_config(hd->ioc, &cfg);
+#endif
 	}
 
 	/* If this is a RAID Passthrough, enable internal IOs
 	 */
 	if (iocmd.flags & MPT_ICFLAG_PHYS_DISK) {
 		if (mptscsih_do_raid(hd, MPI_RAID_ACTION_ENABLE_PHYS_IO, &iocmd) < 0)
-			ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name));
+			ddvprintk((MYIOC_s_ERR_FMT "RAID Enable FAILED!\n", ioc->name));
 	}
 
 	/* Done with the DV scan of the current target
@@ -6986,7 +7157,7 @@
 	ddvtprintk((MYIOC_s_INFO_FMT "DV Done. IOs outstanding = %d\n",
 			ioc->name, atomic_read(&queue_depth)));
 
-	return;
+	return retcode;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -7129,8 +7300,7 @@
 			pPage1->Configuration = le32_to_cpu(configuration);
 		}
 		ddvprintk(("width %d, factor %x, offset %x request %x config %x\n",
-				dv->now.width, dv->now.factor,
-				dv->now.offset, val, configuration));
+				width, factor, offset, val, configuration));
 		break;
 
 	case MPT_FALLBACK:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/mptscsih.h linux-2.4.21/drivers/message/fusion/mptscsih.h
--- linux-2.4.20/drivers/message/fusion/mptscsih.h	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/message/fusion/mptscsih.h	2002-12-18 18:58:12.000000000 +0000
@@ -20,7 +20,7 @@
  *  (mailto:netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptscsih.h,v 1.18 2002/06/06 15:32:52 pdelaney Exp $
+ *  $Id: mptscsih.h,v 1.20 2002/10/17 20:16:00 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -77,7 +77,22 @@
 #define MPT_SCSI_CAN_QUEUE	MPT_FC_CAN_QUEUE
 #define MPT_SCSI_CMD_PER_LUN	 7
 
+#define MPT_SCSI_MAX_SECTORS    8192
+
+/*
+ * Set the MAX_SGE value based on user input.
+ */
+#ifdef  CONFIG_FUSION_MAX_SGE
+#if     CONFIG_FUSION_MAX_SGE  < 16
+#define MPT_SCSI_SG_DEPTH	16
+#elif   CONFIG_FUSION_MAX_SGE  > 128
+#define MPT_SCSI_SG_DEPTH	128
+#else
+#define MPT_SCSI_SG_DEPTH	CONFIG_FUSION_MAX_SGE
+#endif
+#else
 #define MPT_SCSI_SG_DEPTH	40
+#endif
 
 /* To disable domain validation, uncomment the
  * following line. No effect for FC devices.
@@ -146,13 +161,25 @@
 /*
  *	tq_scheduler disappeared @ lk-2.4.0-test12
  *	(right when <linux/sched.h> newly defined TQ_ACTIVE)
+ *	tq_struct reworked in 2.5.41. Include workqueue.h.
  */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
+#	include <linux/sched.h>
+#	include <linux/workqueue.h>
+#define SCHEDULE_TASK(x)		\
+	if (schedule_work(x) == 0) {	\
+		/*MOD_DEC_USE_COUNT*/;	\
+	}
+#else
 #define HAVE_TQ_SCHED	1
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 #	include <linux/sched.h>
 #	ifdef TQ_ACTIVE
 #		undef HAVE_TQ_SCHED
 #	endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,40)
+#		undef HAVE_TQ_SCHED
+#endif
 #endif
 #ifdef HAVE_TQ_SCHED
 #define SCHEDULE_TASK(x)		\
@@ -166,6 +193,7 @@
 		/*MOD_DEC_USE_COUNT*/;	\
 	}
 #endif
+#endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
@@ -201,7 +229,11 @@
 extern	int		 x_scsi_old_abort(Scsi_Cmnd *);
 extern	int		 x_scsi_old_reset(Scsi_Cmnd *, unsigned int);
 #endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
+extern	int		 x_scsi_bios_param(Disk *, struct block_device *, int *);
+#else
 extern	int		 x_scsi_bios_param(Disk *, kdev_t, int *);
+#endif
 extern	void		 x_scsi_select_queue_depths(struct Scsi_Host *, Scsi_Device *);
 extern	void		 x_scsi_taskmgmt_bh(void *);
 
@@ -233,6 +265,7 @@
 	can_queue:			MPT_SCSI_CAN_QUEUE,	\
 	this_id:			-1,			\
 	sg_tablesize:			MPT_SCSI_SG_DEPTH,	\
+	max_sectors:			MPT_SCSI_MAX_SECTORS,   \
 	cmd_per_lun:			MPT_SCSI_CMD_PER_LUN,	\
 	unchecked_isa_dma:		0,			\
 	use_clustering:			ENABLE_CLUSTERING,	\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/i2o/i2o_config.c linux-2.4.21/drivers/message/i2o/i2o_config.c
--- linux-2.4.20/drivers/message/i2o/i2o_config.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/message/i2o/i2o_config.c	2002-12-18 18:58:11.000000000 +0000
@@ -918,7 +918,7 @@
 		printk(KERN_ERR "i2o_config: no memory for page buffer.\n");
 		return -ENOBUFS;
 	}
-	if(misc_register(&i2o_miscdev)==-1)
+	if(misc_register(&i2o_miscdev) < 0)
 	{
 		printk(KERN_ERR "i2o_config: can't register device.\n");
 		kfree(page_buf);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/Config.in linux-2.4.21/drivers/mtd/maps/Config.in
--- linux-2.4.20/drivers/mtd/maps/Config.in	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/mtd/maps/Config.in	2002-12-18 18:58:09.000000000 +0000
@@ -30,6 +30,7 @@
    dep_tristate '  JEDEC Flash device mapped on Mixcom piggyback card' CONFIG_MTD_MIXMEM $CONFIG_MTD_JEDEC
    dep_tristate '  JEDEC Flash device mapped on Octagon 5066 SBC' CONFIG_MTD_OCTAGON $CONFIG_MTD_JEDEC
    dep_tristate '  JEDEC Flash device mapped on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC
+   dep_tristate '  Flash device mapped with DOCCS on NatSemi SCx200' CONFIG_MTD_SCx200_DOCFLASH $CONFIG_MTD_CFI
    dep_tristate '  BIOS flash chip on Intel L440GX boards' CONFIG_MTD_L440GX $CONFIG_MTD_JEDECPROBE
    dep_tristate ' ROM connected to AMD766 southbridge' CONFIG_MTD_AMD766ROM $CONFIG_MTD_GEN_PROBE   
    dep_tristate ' ROM connected to Intel Hub Controller 2' CONFIG_MTD_ICH2ROM $CONFIG_MTD_JEDECPROBE
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/Makefile linux-2.4.21/drivers/mtd/maps/Makefile
--- linux-2.4.20/drivers/mtd/maps/Makefile	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/mtd/maps/Makefile	2002-12-18 18:58:01.000000000 +0000
@@ -32,6 +32,7 @@
 obj-$(CONFIG_MTD_NETSC520)	+= netsc520.o
 obj-$(CONFIG_MTD_SUN_UFLASH)    += sun_uflash.o
 obj-$(CONFIG_MTD_VMAX)		+= vmax301.o
+obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o
 obj-$(CONFIG_MTD_DBOX2)		+= dbox2-flash.o
 obj-$(CONFIG_MTD_OCELOT)	+= ocelot.o
 obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/scx200_docflash.c linux-2.4.21/drivers/mtd/maps/scx200_docflash.c
--- linux-2.4.20/drivers/mtd/maps/scx200_docflash.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/mtd/maps/scx200_docflash.c	2002-12-18 18:58:02.000000000 +0000
@@ -0,0 +1,268 @@
+/* linux/drivers/mtd/maps/scx200_docflash.c 
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   National Semiconductor SCx200 flash mapped with DOCCS
+*/
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/pci.h>
+#include <linux/scx200.h>
+
+#define NAME "scx200_docflash"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@hack.org>");
+MODULE_DESCRIPTION("NatSemi SCx200 DOCCS Flash Driver");
+MODULE_LICENSE("GPL");
+
+/* Set this to one if you want to partition the flash */
+#define PARTITION 1
+
+MODULE_PARM(probe, "i");
+MODULE_PARM_DESC(probe, "Probe for a BIOS mapping");
+MODULE_PARM(size, "i");
+MODULE_PARM_DESC(size, "Size of the flash mapping");
+MODULE_PARM(width, "i");
+MODULE_PARM_DESC(width, "Data width of the flash mapping (8/16)");
+MODULE_PARM(flashtype, "s");
+MODULE_PARM_DESC(flashtype, "Type of MTD probe to do");
+
+static int probe = 0;		/* Don't autoprobe */
+static unsigned size = 0x1000000; /* 16 MB the whole ISA address space */
+static unsigned width = 8;	/* Default to 8 bits wide */
+static char *flashtype = "cfi_probe";
+
+static struct resource docmem = {
+	.flags = IORESOURCE_MEM,
+	.name  = "NatSemi SCx200 DOCCS Flash",
+};
+
+static struct mtd_info *mymtd;
+
+#if PARTITION
+static struct mtd_partition partition_info[] = {
+	{ 
+		.name   = "DOCCS Boot kernel", 
+		.offset = 0, 
+		.size   = 0xc0000
+	},
+	{ 
+		.name   = "DOCCS Low BIOS", 
+		.offset = 0xc0000, 
+		.size   = 0x40000
+	},
+	{ 
+		.name   = "DOCCS File system", 
+		.offset = 0x100000, 
+		.size   = ~0	/* calculate from flash size */
+	},
+	{ 
+		.name   = "DOCCS High BIOS", 
+		.offset = ~0, 	/* calculate from flash size */
+		.size   = 0x80000
+	},
+};
+#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
+#endif
+
+static __u8 scx200_docflash_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+static __u16 scx200_docflash_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+static void scx200_docflash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+static void scx200_docflash_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void scx200_docflash_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void scx200_docflash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+static struct map_info scx200_docflash_map = {
+	.name      = "NatSemi SCx200 DOCCS Flash",
+	.read8     = scx200_docflash_read8,
+	.read16    = scx200_docflash_read16,
+	.copy_from = scx200_docflash_copy_from,
+	.write8    = scx200_docflash_write8,
+	.write16   = scx200_docflash_write16,
+	.copy_to   = scx200_docflash_copy_to
+};
+
+int __init init_scx200_docflash(void)
+{
+	unsigned u;
+	unsigned base;
+	unsigned ctrl;
+	unsigned pmr;
+	struct pci_dev *bridge;
+
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 DOCCS Flash Driver\n");
+
+	if ((bridge = pci_find_device(PCI_VENDOR_ID_NS, 
+				      PCI_DEVICE_ID_NS_SCx200_BRIDGE,
+				      NULL)) == NULL)
+		return -ENODEV;
+	
+	if (!scx200_cb_probe(SCx200_CB_BASE)) {
+		printk(KERN_WARNING NAME ": no configuration block found\n");
+		return -ENODEV;
+	}
+
+	if (probe) {
+		/* Try to use the present flash mapping if any */
+		pci_read_config_dword(bridge, SCx200_DOCCS_BASE, &base);
+		pci_read_config_dword(bridge, SCx200_DOCCS_CTRL, &ctrl);
+		pmr = inl(SCx200_CB_BASE + SCx200_PMR);
+
+		if (base == 0
+		    || (ctrl & 0x07000000) != 0x07000000
+		    || (ctrl & 0x0007ffff) == 0)
+			return -ENODEV;
+
+		size = ((ctrl&0x1fff)<<13) + (1<<13);
+
+		for (u = size; u > 1; u >>= 1)
+			;
+		if (u != 1)
+			return -ENODEV;
+
+		if (pmr & (1<<6))
+			width = 16;
+		else
+			width = 8;
+
+		docmem.start = base;
+		docmem.end = base + size;
+
+		if (request_resource(&iomem_resource, &docmem)) {
+			printk(KERN_ERR NAME ": unable to allocate memory for flash mapping\n");
+			return -ENOMEM;
+		}
+	} else {
+		for (u = size; u > 1; u >>= 1)
+			;
+		if (u != 1) {
+			printk(KERN_ERR NAME ": invalid size for flash mapping\n");
+			return -EINVAL;
+		}
+		
+		if (width != 8 && width != 16) {
+			printk(KERN_ERR NAME ": invalid bus width for flash mapping\n");
+			return -EINVAL;
+		}
+		
+		if (allocate_resource(&iomem_resource, &docmem, 
+				      size,
+				      0xc0000000, 0xffffffff, 
+				      size, NULL, NULL)) {
+			printk(KERN_ERR NAME ": unable to allocate memory for flash mapping\n");
+			return -ENOMEM;
+		}
+		
+		ctrl = 0x07000000 | ((size-1) >> 13);
+
+		printk(KERN_INFO "DOCCS BASE=0x%08lx, CTRL=0x%08lx\n", (long)docmem.start, (long)ctrl);
+		
+		pci_write_config_dword(bridge, SCx200_DOCCS_BASE, docmem.start);
+		pci_write_config_dword(bridge, SCx200_DOCCS_CTRL, ctrl);
+		pmr = inl(SCx200_CB_BASE + SCx200_PMR);
+		
+		if (width == 8) {
+			pmr &= ~(1<<6);
+		} else {
+			pmr |= (1<<6);
+		}
+		outl(pmr, SCx200_CB_BASE + SCx200_PMR);
+	}
+	
+       	printk(KERN_INFO NAME ": DOCCS mapped at 0x%lx-0x%lx, width %d\n", 
+	       docmem.start, docmem.end, width);
+
+	scx200_docflash_map.size = size;
+	if (width == 8)
+		scx200_docflash_map.buswidth = 1;
+	else
+		scx200_docflash_map.buswidth = 2;
+
+	scx200_docflash_map.map_priv_1 = (unsigned long)ioremap(docmem.start, scx200_docflash_map.size);
+	if (!scx200_docflash_map.map_priv_1) {
+		printk(KERN_ERR NAME ": failed to ioremap the flash\n");
+		release_resource(&docmem);
+		return -EIO;
+	}
+
+	mymtd = do_map_probe(flashtype, &scx200_docflash_map);
+	if (!mymtd) {
+		printk(KERN_ERR NAME ": unable to detect flash\n");
+		iounmap((void *)scx200_docflash_map.map_priv_1);
+		release_resource(&docmem);
+		return -ENXIO;
+	}
+
+	if (size < mymtd->size)
+		printk(KERN_WARNING NAME ": warning, flash mapping is smaller than flash size\n");
+
+	mymtd->module = THIS_MODULE;
+
+#if PARTITION
+	partition_info[3].offset = mymtd->size-partition_info[3].size;
+	partition_info[2].size = partition_info[3].offset-partition_info[2].offset;
+	add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
+#else
+	add_mtd_device(mymtd);
+#endif
+	return 0;
+}
+
+static void __exit cleanup_scx200_docflash(void)
+{
+	if (mymtd) {
+#if PARTITION
+		del_mtd_partitions(mymtd);
+#else
+		del_mtd_device(mymtd);
+#endif
+		map_destroy(mymtd);
+	}
+	if (scx200_docflash_map.map_priv_1) {
+		iounmap((void *)scx200_docflash_map.map_priv_1);
+		release_resource(&docmem);
+	}
+}
+
+module_init(init_scx200_docflash);
+module_exit(cleanup_scx200_docflash);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../../.. SUBDIRS=drivers/mtd/maps modules"
+        c-basic-offset: 8
+    End:
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/3c509.c linux-2.4.21/drivers/net/3c509.c
--- linux-2.4.20/drivers/net/3c509.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/net/3c509.c	2002-12-18 18:58:02.000000000 +0000
@@ -43,7 +43,7 @@
 		v1.18 12Mar2001 Andrew Morton <andrewm@uow.edu.au>
 			- Avoid bogus detect of 3c590's (Andrzej Krzysztofowicz)
 			- Reviewed against 1.18 from scyld.com
-		v1.18a 17Nov2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+		v1.18a 17Nov2001 Jeff Garzik <jgarzik@pobox.com>
 			- ethtool support
 		v1.18b 1Mar2002 Zwane Mwaikambo <zwane@commfireservices.com>
 			- Power Management support
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/3c515.c linux-2.4.21/drivers/net/3c515.c
--- linux-2.4.20/drivers/net/3c515.c	2002-02-25 19:37:59.000000000 +0000
+++ linux-2.4.21/drivers/net/3c515.c	2002-12-18 18:58:03.000000000 +0000
@@ -91,12 +91,14 @@
 #define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n, instance)
 #define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
 
+#define MAX_UNITS 8
+
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("3Com 3c515 Corkscrew driver");
 MODULE_LICENSE("GPL");
 
 MODULE_PARM(debug, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM_DESC(debug, "3c515 debug level (0-6)");
@@ -421,7 +423,7 @@
 */
 /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
 /* Note: this is the only limit on the number of cards supported!! */
-static int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1, };
+static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1, };
 
 #ifdef MODULE
 static int debug = -1;
@@ -558,9 +560,10 @@
 		printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
 		     inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
 		irq = inw(ioaddr + 0x2002) & 15;
-		corkscrew_found_device(dev, ioaddr, irq, CORKSCREW_ID, dev
-				       && dev->mem_start ? dev->
-				       mem_start : options[cards_found]);
+		corkscrew_found_device(dev, ioaddr, irq, CORKSCREW_ID,
+				       dev && dev->mem_start ?  dev->mem_start :
+				         (cards_found >= MAX_UNITS ? -1 :
+						options[cards_found]));
 		dev = 0;
 		cards_found++;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/3c523.c linux-2.4.21/drivers/net/3c523.c
--- linux-2.4.20/drivers/net/3c523.c	2002-02-25 19:37:59.000000000 +0000
+++ linux-2.4.21/drivers/net/3c523.c	2002-12-18 18:58:08.000000000 +0000
@@ -212,10 +212,11 @@
 	volatile struct iscp_struct *iscp;	/* volatile is important */
 	volatile struct scb_struct *scb;	/* volatile is important */
 	volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS];
-	volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
 #if (NUM_XMIT_BUFFS == 1)
+	volatile struct transmit_cmd_struct *xmit_cmds[2];
 	volatile struct nop_cmd_struct *nop_cmds[2];
 #else
+	volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
 	volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
 #endif
 	volatile int nop_point, num_recv_buffs;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/3c59x.c linux-2.4.21/drivers/net/3c59x.c
--- linux-2.4.20/drivers/net/3c59x.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/net/3c59x.c	2002-12-18 18:58:01.000000000 +0000
@@ -20,7 +20,7 @@
 	Linux Kernel Additions:
 	
  	0.99H+lk0.9 - David S. Miller - softnet, PCI DMA updates
- 	0.99H+lk1.0 - Jeff Garzik <jgarzik@mandrakesoft.com>
+ 	0.99H+lk1.0 - Jeff Garzik <jgarzik@pobox.com>
 		Remove compatibility defines for kernel versions < 2.2.x.
 		Update for new 2.3.x module interface
 	LK1.1.2 (March 19, 2000)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/8139cp.c linux-2.4.21/drivers/net/8139cp.c
--- linux-2.4.20/drivers/net/8139cp.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/net/8139cp.c	2002-12-18 18:58:08.000000000 +0000
@@ -1,6 +1,6 @@
 /* 8139cp.c: A Linux PCI Ethernet driver for the RealTek 8139C+ chips. */
 /*
-	Copyright 2001,2002 Jeff Garzik <jgarzik@mandrakesoft.com>
+	Copyright 2001,2002 Jeff Garzik <jgarzik@pobox.com>
 
 	Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com) [tg3.c]
 	Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) [sungem.c]
@@ -89,7 +89,7 @@
 static char version[] __devinitdata =
 KERN_INFO DRV_NAME ": 10/100 PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n";
 
-MODULE_AUTHOR("Jeff Garzik <jgarzik@mandrakesoft.com>");
+MODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");
 MODULE_DESCRIPTION("RealTek RTL-8139C+ series 10/100 PCI Ethernet driver");
 MODULE_LICENSE("GPL");
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/8139too.c linux-2.4.21/drivers/net/8139too.c
--- linux-2.4.20/drivers/net/8139too.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/net/8139too.c	2002-12-18 18:58:01.000000000 +0000
@@ -2,7 +2,7 @@
 
 	8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux.
 
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000-2002 Jeff Garzik
 
 	Much code comes from Donald Becker's rtl8139.c driver,
@@ -590,7 +590,7 @@
 	unsigned int regs_len;
 };
 
-MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
+MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
 MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver");
 MODULE_LICENSE("GPL");
 
@@ -969,7 +969,12 @@
 	dev->do_ioctl = netdev_ioctl;
 	dev->tx_timeout = rtl8139_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
-	dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
+
+	/* note: the hardware is not capable of sg/csum/highdma, however
+	 * through the use of skb_copy_and_csum_dev we enable these
+	 * features
+	 */
+	dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA;
 
 	dev->irq = pdev->irq;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/Config.in linux-2.4.21/drivers/net/Config.in
--- linux-2.4.20/drivers/net/Config.in	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/net/Config.in	2002-12-18 18:58:02.000000000 +0000
@@ -248,6 +248,7 @@
 dep_tristate 'National Semiconductor DP83820 support' CONFIG_NS83820 $CONFIG_PCI
 dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI
 dep_tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN $CONFIG_PCI $CONFIG_EXPERIMENTAL
+dep_tristate 'Realtek 8169 Gigabit Ethernet support' CONFIG_R8169 $CONFIG_PCI
 dep_tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN $CONFIG_PCI
 dep_tristate 'Broadcom Tigon3 support' CONFIG_TIGON3 $CONFIG_PCI
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/Makefile linux-2.4.21/drivers/net/Makefile
--- linux-2.4.20/drivers/net/Makefile	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/net/Makefile	2002-12-18 18:58:05.000000000 +0000
@@ -100,7 +100,7 @@
 endif
 
 obj-$(CONFIG_VIA_RHINE) += via-rhine.o mii.o
-obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
+obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o mii.o
 
 #
 # end link order section
@@ -114,7 +114,7 @@
 
 obj-$(CONFIG_WINBOND_840) += winbond-840.o mii.o
 obj-$(CONFIG_SUNDANCE) += sundance.o mii.o
-obj-$(CONFIG_HAMACHI) += hamachi.o
+obj-$(CONFIG_HAMACHI) += hamachi.o mii.o
 obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o
 obj-$(CONFIG_SEEQ8005) += seeq8005.o
 obj-$(CONFIG_ETHERTAP) += ethertap.o
@@ -225,6 +225,10 @@
 obj-$(CONFIG_MAC89x0) += mac89x0.o
 obj-$(CONFIG_TUN) += tun.o
 obj-$(CONFIG_DL2K) += dl2k.o
+obj-$(CONFIG_R8169) += r8169.o
+
+# non-drivers/net drivers who want mii lib
+obj-$(CONFIG_PCMCIA_SMC91C92) += mii.o
 
 ifeq ($(CONFIG_ARCH_ACORN),y)
 mod-subdirs	+= ../acorn/net
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/at1700.c linux-2.4.21/drivers/net/at1700.c
--- linux-2.4.20/drivers/net/at1700.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/net/at1700.c	2002-12-18 18:58:07.000000000 +0000
@@ -311,7 +311,6 @@
 		&& inb(ioaddr + SAPROM + 2) == 0x0e)
 		is_fmv18x = 1;
 	else {
-		ret = -ENODEV;
 		goto err_out;
 	}
 			
@@ -336,11 +335,10 @@
 			}
 			if (i == 8) {
 				goto err_out;
-				ret = -ENODEV;
 			}
 		} else {
 			if (fmv18x_probe_list[inb(ioaddr + IOCONFIG) & 0x07] != ioaddr)
-				return -ENODEV;
+				goto err_out;
 			irq = fmv_irqmap[(inb(ioaddr + IOCONFIG)>>6) & 0x03];
 		}
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/bmac.c linux-2.4.21/drivers/net/bmac.c
--- linux-2.4.20/drivers/net/bmac.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/net/bmac.c	2002-12-18 18:58:02.000000000 +0000
@@ -1403,7 +1403,7 @@
 
 	memset((char *) bp->tx_cmds, 0,
 	       (N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd));
-	/*     init_timer(&bp->tx_timeout); */
+	init_timer(&bp->tx_timeout);
 	/*     bp->timeout_active = 0; */
 
 	ret = request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/bonding.c linux-2.4.21/drivers/net/bonding.c
--- linux-2.4.20/drivers/net/bonding.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/net/bonding.c	2002-12-18 18:58:07.000000000 +0000
@@ -686,7 +686,7 @@
 }
 
 /*
- * This function counts the the number of attached 
+ * This function counts the number of attached 
  * slaves for use by bond_xmit_xor.
  */
 static void update_slave_cnt(bonding_t *bond)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/de620.c linux-2.4.21/drivers/net/de620.c
--- linux-2.4.20/drivers/net/de620.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/net/de620.c	2002-12-18 18:58:01.000000000 +0000
@@ -850,12 +850,6 @@
 		return -ENODEV;
 	}
 
-#if 0 /* Not yet */
-	if (check_region(dev->base_addr, 3)) {
-		printk(", port 0x%x busy\n", dev->base_addr);
-		return -EBUSY;
-	}
-#endif
 	if (!request_region(dev->base_addr, 3, "de620")) {
 		printk(KERN_ERR "io 0x%3lX, which is busy.\n", dev->base_addr);
 		return -EBUSY;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/dl2k.c linux-2.4.21/drivers/net/dl2k.c
--- linux-2.4.20/drivers/net/dl2k.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/net/dl2k.c	2002-12-18 18:58:07.000000000 +0000
@@ -30,17 +30,32 @@
     1.09	2002/03/07	Move rx-poll-now to re-fill loop.	
     				Added rio_timer() to watch rx buffers. 
     1.10	2002/04/16	Fixed miscount of carrier error.
-    1.11	2002/05/23	Added ISR schedule scheme.
+    1.11	2002/05/23	Added ISR schedule scheme
     				Fixed miscount of rx frame error for DGE-550SX.
     				Fixed VLAN bug.
     1.12	2002/06/13	Lock tx_coalesce=1 on 10/100Mbps mode.
- */
+    1.13	2002/08/13	1. Fix disconnection (many tx:carrier/rx:frame
+    				   errs) with some mainboards.
+    				2. Use definition "DRV_NAME" "DRV_VERSION" 
+				   "DRV_RELDATE" for flexibility.	
+    1.14	2002/08/14	Support ethtool.	
+    1.15	2002/08/27	Changed the default media to Auto-Negotiation
+				for the fiber devices.    
+    1.16	2002/09/04      More power down time for fiber devices auto-
+    				negotiation.
+				Fix disconnect bug after ifup and ifdown.
+    1.17	2002/10/03	Fix RMON statistics overflow. 
+			     	Always use I/O mapping to access eeprom, 
+				avoid system freezing with some chipsets.
 
+*/
+#define DRV_NAME	"D-Link DL2000-based linux driver"
+#define DRV_VERSION	"v1.17a"
+#define DRV_RELDATE	"2002/10/04"
 #include "dl2k.h"
 
 static char version[] __devinitdata =
-    KERN_INFO "D-Link DL2000-based linux driver v1.12 2002/06/13\n";
-
+      KERN_INFO DRV_NAME " " DRV_VERSION " " DRV_RELDATE "\n";	
 #define MAX_UNITS 8
 static int mtu[MAX_UNITS];
 static int vlan[MAX_UNITS];
@@ -92,6 +107,7 @@
 static void set_multicast (struct net_device *dev);
 static struct net_device_stats *get_stats (struct net_device *dev);
 static int clear_stats (struct net_device *dev);
+static int rio_ethtool_ioctl (struct net_device *dev, void *useraddr);
 static int rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 static int rio_close (struct net_device *dev);
 static int find_miiphy (struct net_device *dev);
@@ -257,12 +273,8 @@
 	np->link_status = 0;
 	/* Set media and reset PHY */
 	if (np->phy_media) {
-		/* default 1000mbps_fd for fiber deivices */
-		if (np->an_enable == 1) {
-			np->an_enable = 0;
-			np->speed = 1000;
-			np->full_duplex = 1;
-		} else if (np->an_enable == 2) {
+		/* default Auto-Negotiation for fiber deivices */
+	 	if (np->an_enable == 2) {
 			np->an_enable = 1;
 		}
 		mii_set_media_pcs (dev);
@@ -275,10 +287,6 @@
 	}
 	pci_read_config_byte(pdev, PCI_REVISION_ID, &np->pci_rev_id);
 
-	/* Reset all logic functions */
-	writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset,
-		ioaddr + ASICCtrl + 2);
-
 	err = register_netdev (dev);
 	if (err)
 		goto err_out_unmap_rx;
@@ -357,11 +365,16 @@
 
 	int cid, next;
 
+#ifdef	MEM_MAPPING
+	ioaddr = pci_resource_start (np->pdev, 0);
+#endif
 	/* Read eeprom */
 	for (i = 0; i < 128; i++) {
 		((u16 *) sromdata)[i] = le16_to_cpu (read_eeprom (ioaddr, i));
 	}
-
+#ifdef	MEM_MAPPING
+	ioaddr = dev->base_addr;
+#endif	
 	/* Check CRC */
 	crc = ~ether_crc_le (256 - 4, sromdata);
 	if (psrom->crc != crc) {
@@ -421,10 +434,17 @@
 	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int i;
-
+	u16 macctrl;
+	
 	i = request_irq (dev->irq, &rio_interrupt, SA_SHIRQ, dev->name, dev);
 	if (i)
 		return i;
+	
+	/* Reset all logic functions */
+	writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset,
+		ioaddr + ASICCtrl + 2);
+	mdelay(10);
+	
 	/* DebugCtrl bit 4, 5, 9 must set */
 	writel (readl (ioaddr + DebugCtrl) | 0x0230, ioaddr + DebugCtrl);
 
@@ -448,7 +468,7 @@
 	writeb (0xff, ioaddr + TxDMAPollPeriod);
 	writeb (0x30, ioaddr + RxDMABurstThresh);
 	writeb (0x30, ioaddr + RxDMAUrgentThresh);
-
+	writel (0x0007ffff, ioaddr + RmonStatMask);
 	/* clear statistics */
 	clear_stats (dev);
 
@@ -467,9 +487,6 @@
 			ioaddr + MACCtrl);
 	}
 
-	/* Enable default interrupts */
-	EnableInt ();
-
 	init_timer (&np->timer);
 	np->timer.expires = jiffies + 1*HZ;
 	np->timer.data = (unsigned long) dev;
@@ -479,8 +496,18 @@
 	/* Start Tx/Rx */
 	writel (readl (ioaddr + MACCtrl) | StatsEnable | RxEnable | TxEnable, 
 			ioaddr + MACCtrl);
+	
+	macctrl = 0;
+	macctrl |= (np->vlan) ? AutoVLANuntagging : 0;
+	macctrl |= (np->full_duplex) ? DuplexSelect : 0;
+	macctrl |= (np->tx_flow) ? TxFlowControlEnable : 0;
+	macctrl |= (np->rx_flow) ? RxFlowControlEnable : 0;
+	writew(macctrl,	ioaddr + MACCtrl);
 
 	netif_start_queue (dev);
+	
+	/* Enable default interrupts */
+	EnableInt ();
 	return 0;
 }
 
@@ -626,7 +653,7 @@
 	}
 #endif
 	if (np->vlan) {
-		txdesc->status |=
+		tfc_vlan_tag =
 		    cpu_to_le64 (VLANTagInsert) |
 		    (cpu_to_le64 (np->vlan) << 32) |
 		    (cpu_to_le64 (skb->priority) << 45);
@@ -720,9 +747,10 @@
 	long flag = 0;
 	
 	if (irq)
-		spin_lock_irqsave(&np->tx_lock, flag);
-	else
 		spin_lock(&np->tx_lock);
+	else
+		spin_lock_irqsave(&np->tx_lock, flag);
+			
 	/* Free used tx skbuffs */
 	while (entry != np->cur_tx) {
 		struct sk_buff *skb;
@@ -743,9 +771,9 @@
 		tx_use++;
 	}
 	if (irq)
-		spin_unlock_irqrestore(&np->tx_lock, flag);
-	else
 		spin_unlock(&np->tx_lock);
+	else
+		spin_unlock_irqrestore(&np->tx_lock, flag);
 	np->old_tx = entry;
 
 	/* If the ring is no longer full, clear tx_full and 
@@ -809,8 +837,13 @@
 		/* Let TxStartThresh stay default value */
 	}
 	/* Maximum Collisions */
+#ifdef ETHER_STATS	
+	if (tx_status & 0x08) 
+		np->stats.collisions16++;
+#else
 	if (tx_status & 0x08) 
 		np->stats.collisions++;
+#endif
 	/* Restart the Tx */
 	writel (readw (dev->base_addr + MACCtrl) | TxEnable, ioaddr + MACCtrl);
 }
@@ -974,7 +1007,9 @@
 {
 	long ioaddr = dev->base_addr;
 	struct netdev_private *np = dev->priv;
+#ifdef MEM_MAPPING
 	int i;
+#endif
 	unsigned int stat_reg;
 
 	/* All statistics registers need to be acknowledged,
@@ -1017,9 +1052,10 @@
 	readw (ioaddr + MacControlFramesXmtd);
 	readw (ioaddr + FramesWEXDeferal);
 
-
+#ifdef MEM_MAPPING
 	for (i = 0x100; i <= 0x150; i += 4)
 		readl (ioaddr + i);
+#endif
 	readw (ioaddr + TxJumboFrames);
 	readw (ioaddr + RxJumboFrames);
 	readw (ioaddr + TCPCheckSumErrors);
@@ -1032,7 +1068,9 @@
 clear_stats (struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
+#ifdef MEM_MAPPING
 	int i;
+#endif 
 
 	/* All statistics registers need to be acknowledged,
 	   else statistic overflow could cause problems */
@@ -1068,9 +1106,10 @@
 	readw (ioaddr + BcstFramesXmtdOk);
 	readw (ioaddr + MacControlFramesXmtd);
 	readw (ioaddr + FramesWEXDeferal);
-
+#ifdef MEM_MAPPING
 	for (i = 0x100; i <= 0x150; i += 4)
 		readl (ioaddr + i);
+#endif 
 	readw (ioaddr + TxJumboFrames);
 	readw (ioaddr + RxJumboFrames);
 	readw (ioaddr + TCPCheckSumErrors);
@@ -1103,6 +1142,7 @@
 	u16 rx_mode = 0;
 	int i;
 	int bit;
+	int index, crc;
 	struct dev_mc_list *mclist;
 	struct netdev_private *np = dev->priv;
 	
@@ -1122,17 +1162,16 @@
 		rx_mode =
 		    ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast;
 		for (i=0, mclist = dev->mc_list; mclist && i < dev->mc_count; 
-			i++, mclist=mclist->next) {
-
-			int index = 0;
-			int crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
-
+				i++, mclist=mclist->next) 
+		{
+			crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
 			/* The inverted high significant 6 bits of CRC are
 			   used as an index to hashtable */
-			for (bit = 0; bit < 6; bit++)
-				if (crc & (1 << (31 - bit)))
-					index |= (1 << bit);
-
+			for (index=0, bit=0; bit < 6; bit++) {
+				if (test_bit(31-bit, &crc)) {
+					 set_bit(bit, &index);
+				}
+			}
 			hash_table[index / 32] |= (1 << (index % 32));
 		}
 	} else {
@@ -1149,6 +1188,132 @@
 }
 
 static int
+rio_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	struct netdev_private *np = dev->priv;
+       	u32 ethcmd;
+	
+	if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
+		return -EFAULT;
+	switch (ethcmd) {
+		case ETHTOOL_GDRVINFO: {
+			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+			strcpy(info.driver, "DL2K");
+			strcpy(info.version, DRV_VERSION);
+			strcpy(info.bus_info, np->pdev->slot_name);
+			memset(&info.fw_version, 0, sizeof(info.fw_version));
+			if (copy_to_user(useraddr, &info, sizeof(info)))
+				return -EFAULT;
+			return 0;
+		}	
+ 	
+		case ETHTOOL_GSET: {
+			struct ethtool_cmd cmd = { ETHTOOL_GSET };
+			if (np->phy_media) {
+				/* fiber device */
+				cmd.supported = SUPPORTED_Autoneg | 
+							SUPPORTED_FIBRE;
+				cmd.advertising= ADVERTISED_Autoneg |
+							ADVERTISED_FIBRE;
+				cmd.port = PORT_FIBRE;
+				cmd.transceiver = XCVR_INTERNAL;	
+			} else {
+				/* copper device */
+				cmd.supported = SUPPORTED_10baseT_Half | 
+					SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half
+					| SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full |
+					SUPPORTED_Autoneg | SUPPORTED_MII;
+				cmd.advertising = ADVERTISED_10baseT_Half |
+					ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half |
+					ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Full|
+					ADVERTISED_Autoneg | ADVERTISED_MII;
+				cmd.port = PORT_MII;
+				cmd.transceiver = XCVR_INTERNAL;
+			}
+			if ( np->link_status ) { 
+				cmd.speed = np->speed;
+				cmd.duplex = np->full_duplex ? 
+						    DUPLEX_FULL : DUPLEX_HALF;
+			} else {
+				cmd.speed = -1;
+				cmd.duplex = -1;
+			}
+			if ( np->an_enable)
+				cmd.autoneg = AUTONEG_ENABLE;
+			else
+				cmd.autoneg = AUTONEG_DISABLE;
+			
+			cmd.phy_address = np->phy_addr;
+
+			if (copy_to_user(useraddr, &cmd,
+					sizeof(cmd)))
+				return -EFAULT;
+			return 0;				   
+		}
+		case ETHTOOL_SSET: {
+			struct ethtool_cmd cmd;
+			if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
+				return -EFAULT;
+			netif_carrier_off(dev);
+			if (cmd.autoneg == AUTONEG_ENABLE) {
+				if (np->an_enable)
+					return 0;
+				else {
+					np->an_enable = 1;
+					mii_set_media(dev);
+					return 0;	
+				}	
+			} else {
+				np->an_enable = 0;
+				if (np->speed == 1000){
+					cmd.speed = SPEED_100;			
+					cmd.duplex = DUPLEX_FULL;
+					printk("Warning!! Can't disable Auto negotiation in 1000Mbps, change to Manul 100Mbps, Full duplex.\n");
+					}
+				switch(cmd.speed + cmd.duplex){
+				
+				case SPEED_10 + DUPLEX_HALF:
+					np->speed = 10;
+					np->full_duplex = 0;
+					break;
+				
+				case SPEED_10 + DUPLEX_FULL:
+					np->speed = 10;
+					np->full_duplex = 1;
+					break;
+				case SPEED_100 + DUPLEX_HALF:
+					np->speed = 100;
+					np->full_duplex = 0;
+					break;
+				case SPEED_100 + DUPLEX_FULL:
+					np->speed = 100;
+					np->full_duplex = 1;
+					break;
+				case SPEED_1000 + DUPLEX_HALF:/* not supported */
+				case SPEED_1000 + DUPLEX_FULL:/* not supported */
+				default:
+					return -EINVAL;	
+				}
+				mii_set_media(dev);
+			}
+		return 0;		   
+		}
+#ifdef ETHTOOL_GLINK		
+		case ETHTOOL_GLINK:{
+		struct ethtool_value link = { ETHTOOL_GLINK };
+		link.data = np->link_status;
+		if (copy_to_user(useraddr, &link, sizeof(link)))
+			return -EFAULT;
+		return 0;
+		}			   
+#endif
+		default:
+		return -EOPNOTSUPP;
+	}	
+}
+
+
+static int
 rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	int phy_addr;
@@ -1160,6 +1325,8 @@
 
 	phy_addr = np->phy_addr;
 	switch (cmd) {
+	case SIOCETHTOOL:
+		return rio_ethtool_ioctl (dev, (void *) rq->ifr_data);		
 	case SIOCDEVPRIVATE:
 		break;
 	
@@ -1210,14 +1377,15 @@
 #define EEP_READ 0x0200
 #define EEP_BUSY 0x8000
 /* Read the EEPROM word */
+/* We use I/O instruction to read/write eeprom to avoid fail on some machines */
 int
 read_eeprom (long ioaddr, int eep_addr)
 {
 	int i = 1000;
-	writew (EEP_READ | (eep_addr & 0xff), ioaddr + EepromCtrl);
+	outw (EEP_READ | (eep_addr & 0xff), ioaddr + EepromCtrl);
 	while (i-- > 0) {
-		if (!(readw (ioaddr + EepromCtrl) & EEP_BUSY)) {
-			return readw (ioaddr + EepromData);
+		if (!(inw (ioaddr + EepromCtrl) & EEP_BUSY)) {
+			return inw (ioaddr + EepromData);
 		}
 	}
 	return 0;
@@ -1464,7 +1632,7 @@
 		/* 3) Power Down */
 		bmcr.image = 0x1940;	/* must be 0x1940 */
 		mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
-		mdelay (10);	/* wait a certain time */
+		mdelay (100);	/* wait a certain time */
 
 		/* 4) Advertise nothing */
 		mii_write (dev, phy_addr, MII_ANAR, 0);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/dl2k.h linux-2.4.21/drivers/net/dl2k.h
--- linux-2.4.20/drivers/net/dl2k.h	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/net/dl2k.h	2002-12-18 18:58:06.000000000 +0000
@@ -27,9 +27,11 @@
 #include <linux/skbuff.h>
 #include <linux/init.h>
 #include <linux/crc32.h>
+#include <linux/ethtool.h>
 #include <asm/processor.h>	/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
+#include <asm/uaccess.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/time.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/dmfe.c linux-2.4.21/drivers/net/dmfe.c
--- linux-2.4.20/drivers/net/dmfe.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/net/dmfe.c	2002-12-18 18:58:11.000000000 +0000
@@ -29,7 +29,7 @@
     Reformatted, fixing spelling etc as I went
     Removed IRQ 0-15 assumption
 
-    Jeff Garzik <jgarzik@mandrakesoft.com> :
+    Jeff Garzik <jgarzik@pobox.com> :
     Updated to use new PCI driver API.
     Resource usage cleanups.
     Report driver version to user.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/e100/e100.h linux-2.4.21/drivers/net/e100/e100.h
--- linux-2.4.20/drivers/net/e100/e100.h	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/net/e100/e100.h	2002-12-18 18:58:07.000000000 +0000
@@ -927,8 +927,6 @@
 
 	struct proc_dir_entry *proc_parent;
 
-	rwlock_t isolate_lock;
-	int driver_isolated;
 	char *id_string;
 	char *cable_status;
 	char *mdix_status;
@@ -977,8 +975,7 @@
 extern unsigned char e100_get_link_state(struct e100_private *bdp);
 extern unsigned char e100_wait_scb(struct e100_private *bdp);
 
-extern void e100_deisolate_driver(struct e100_private *bdp,
-				  u8 recover, u8 full_reset);
+extern void e100_deisolate_driver(struct e100_private *bdp, u8 full_reset);
 extern unsigned char e100_hw_reset_recover(struct e100_private *bdp,
 					   u32 reset_cmd);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/e100/e100_main.c linux-2.4.21/drivers/net/e100/e100_main.c
--- linux-2.4.20/drivers/net/e100/e100_main.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/net/e100/e100_main.c	2002-12-18 18:58:03.000000000 +0000
@@ -135,7 +135,7 @@
 
 /* Global Data structures and variables */
 char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation";
-char e100_driver_version[]="2.1.24-k1";
+char e100_driver_version[]="2.1.24-k2";
 const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
 char e100_short_driver_name[] = "e100";
 static int e100nics = 0;
@@ -935,13 +935,6 @@
 
 	bdp = dev->priv;
 
-	read_lock(&(bdp->isolate_lock));
-
-	if (bdp->driver_isolated) {
-		rc = -EBUSY;
-		goto exit;
-	}
-
 	/* setup the tcb pool */
 	if (!e100_alloc_tcb_pool(bdp)) {
 		rc = -ENOMEM;
@@ -990,7 +983,6 @@
 err_exit:
 	e100_clear_pools(bdp);
 exit:
-	read_unlock(&(bdp->isolate_lock));
 	return rc;
 }
 
@@ -1008,9 +1000,6 @@
 	free_irq(dev->irq, dev);
 	e100_clear_pools(bdp);
 
-	/* set the isolate flag to false, so e100_open can be called */
-	bdp->driver_isolated = false;
-
 	return 0;
 }
 
@@ -1031,13 +1020,6 @@
 	int notify_stop = false;
 	struct e100_private *bdp = dev->priv;
 
-	read_lock(&(bdp->isolate_lock));
-
-	if (bdp->driver_isolated) {
-		rc = -EBUSY;
-		goto exit2;
-	}
-
 	if (!spin_trylock(&bdp->bd_non_tx_lock)) {
 		notify_stop = true;
 		rc = 1;
@@ -1060,7 +1042,6 @@
 exit1:
 	spin_unlock(&bdp->bd_non_tx_lock);
 exit2:
-	read_unlock(&(bdp->isolate_lock));
 	if (notify_stop) {
 		netif_stop_queue(dev);
 	}
@@ -1115,18 +1096,11 @@
 
 	bdp = dev->priv;
 
-	read_lock(&(bdp->isolate_lock));
-
-	if (bdp->driver_isolated) {
-		goto exit;
-	}
 	if (e100_setup_iaaddr(bdp, (u8 *) (p_sockaddr->sa_data))) {
 		memcpy(&(dev->dev_addr[0]), p_sockaddr->sa_data, ETH_ALEN);
 		rc = 0;
 	}
 
-exit:
-	read_unlock(&(bdp->isolate_lock));
 	return rc;
 }
 
@@ -1180,10 +1154,6 @@
 	unsigned char promisc_enbl;
 	unsigned char mulcast_enbl;
 
-	read_lock(&(bdp->isolate_lock));
-	if (bdp->driver_isolated) {
-		goto exit;
-	}
 	promisc_enbl = ((dev->flags & IFF_PROMISC) == IFF_PROMISC);
 	mulcast_enbl = ((dev->flags & IFF_ALLMULTI) ||
 			(dev->mc_count > MAX_MULTICAST_ADDRS));
@@ -1195,14 +1165,11 @@
 	e100_config(bdp);
 
 	if (promisc_enbl || mulcast_enbl) {
-		goto exit;	/* no need for Multicast Cmd */
+		return;	/* no need for Multicast Cmd */
 	}
 
 	/* get the multicast CB */
 	e100_set_multi_exec(dev);
-
-exit:
-	read_unlock(&(bdp->isolate_lock));
 }
 
 static int
@@ -1308,8 +1275,6 @@
 	spin_lock_init(&(bdp->bd_non_tx_lock));
 	spin_lock_init(&(bdp->config_lock));
 	spin_lock_init(&(bdp->mdi_access_lock));
-	bdp->isolate_lock = RW_LOCK_UNLOCKED;
-	bdp->driver_isolated = false;
 
 	return 1;
 }
@@ -1625,12 +1590,8 @@
 {
 	struct e100_private *bdp = dev->priv;
 
-	read_lock(&(bdp->isolate_lock));
-	if (bdp->driver_isolated) {
-		goto exit;
-	}
 	if (!netif_running(dev)) {
-		goto exit;
+		return;
 	}
 	e100_get_mdix_status(bdp);
 
@@ -1721,9 +1682,6 @@
 
 	if (list_empty(&bdp->active_rx_list))
 		e100_trigger_SWI(bdp);
-
-exit:
-	read_unlock(&(bdp->isolate_lock));
 }
 
 /**
@@ -1828,11 +1786,6 @@
 		return;
 	}
 
-	read_lock(&(bdp->isolate_lock));
-	if (bdp->driver_isolated) {
-		goto exit;
-	}
-
 	/* SWI intr (triggered by watchdog) is signal to allocate new skb buffers */
 	if (intr_status & SCB_STATUS_ACK_SWI) {
 		e100_alloc_skbs(bdp);
@@ -1849,9 +1802,7 @@
 		e100_tx_srv(bdp);
 	}
 
-exit:
 	e100_set_intr_mask(bdp);
-	read_unlock(&(bdp->isolate_lock));
 }
 
 /**
@@ -2656,7 +2607,7 @@
 	if (in_interrupt())
 		return e100_delayed_exec_non_cu_cmd(bdp, command);
 
-	if (netif_running(bdp->device) && (!bdp->driver_isolated))
+	if (netif_running(bdp->device) && netif_carrier_ok(bdp->device))
 		return e100_delayed_exec_non_cu_cmd(bdp, command);
 
 	spin_lock_bh(&(bdp->bd_non_tx_lock));
@@ -3054,33 +3005,32 @@
 void
 e100_isolate_driver(struct e100_private *bdp)
 {
-	write_lock_irq(&(bdp->isolate_lock));
-	bdp->driver_isolated = true;
-	write_unlock_irq(&(bdp->isolate_lock));
-
-	del_timer_sync(&bdp->watchdog_timer);
-
-	del_timer_sync(&bdp->hwi_timer);
-	/* If in middle of cable diag, */
-	if (bdp->hwi_started) {
-		bdp->hwi_started = 0;
-		e100_hwi_restore(bdp);
-	}
-
-	if (netif_running(bdp->device))
-		netif_stop_queue(bdp->device);
-
-	bdp->last_tcb = NULL;
-
+	if (netif_running(bdp->device)) {
+		e100_dis_intr(bdp);
+		del_timer_sync(&bdp->watchdog_timer);
+		del_timer_sync(&bdp->hwi_timer);
+		/* If in middle of cable diag, */
+		if (bdp->hwi_started) {
+			bdp->hwi_started = 0;
+			e100_hwi_restore(bdp);
+		}
+		netif_carrier_off(bdp->device);
+		netif_stop_queue(bdp->device); 
+		bdp->last_tcb = NULL;
+	} 
 	e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
 }
 
 void
 e100_set_speed_duplex(struct e100_private *bdp)
 {
+	if (netif_carrier_ok(bdp->device))
+		e100_isolate_driver(bdp);
 	e100_phy_set_speed_duplex(bdp, true);
 	e100_config_fc(bdp);	/* re-config flow-control if necessary */
 	e100_config(bdp);	
+	if (netif_carrier_ok(bdp->device))
+		e100_deisolate_driver(bdp, false);
 }
 
 static void
@@ -3160,29 +3110,21 @@
 }
 
 void
-e100_deisolate_driver(struct e100_private *bdp, u8 recover, u8 full_init)
+e100_deisolate_driver(struct e100_private *bdp, u8 full_reset)
 {
-	if (full_init) {
-		e100_sw_reset(bdp, PORT_SOFTWARE_RESET);
-		if (!e100_hw_reset_recover(bdp, PORT_SOFTWARE_RESET))
-			printk(KERN_ERR "e100: e100_deisolate_driver:"
-			       " HW SOFTWARE reset recover failed\n");
-	}
+	u32 cmd = full_reset ? PORT_SOFTWARE_RESET : PORT_SELECTIVE_RESET;
+	e100_sw_reset(bdp, cmd);
+	if (cmd == PORT_SOFTWARE_RESET) {
+		if (!e100_hw_reset_recover(bdp, cmd))
+			printk(KERN_ERR "e100: e100_deisolate_driver:" 
+		       		" device configuration failed\n");
+	} 
 
-	if (recover) {
+	if (netif_running(bdp->device)) {
 
 		bdp->next_cu_cmd = START_WAIT;
 		bdp->last_tcb = NULL;
 
-		/* lets reset the chip */
-		if (!full_init) {
-			e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
-
-			if (!e100_hw_reset_recover(bdp, PORT_SELECTIVE_RESET)) {
-				printk(KERN_ERR "e100: e100_deisolate_driver:"
-				       " HW reset recover failed\n");
-			}
-		}
 		e100_start_ru(bdp);
 
 		/* relaunch watchdog timer in 2 sec */
@@ -3192,14 +3134,9 @@
 		// or have unsent frames on the tcb chain
 		e100_tcb_add_C_bit(bdp);
 		e100_tx_srv(bdp);
-
+		netif_wake_queue(bdp->device);
 		e100_set_intr_mask(bdp);
-
-		if (netif_running(bdp->device))
-			netif_wake_queue(bdp->device);
 	}
-
-	bdp->driver_isolated = false;
 }
 
 static int
@@ -4165,22 +4102,17 @@
 {
 	struct net_device *netdev = pci_get_drvdata(pcid);
 	struct e100_private *bdp = netdev->priv;
-	u8 recover = false;
-	u8 full_init = false;
+	u8 full_reset = false;
 
 	pci_set_power_state(pcid, 0);
 	pci_enable_wake(pcid, 0, 0);	/* Clear PME status and disable PME */
 	pci_restore_state(pcid, bdp->pci_state);
 
-	if (netif_running(netdev)) {
-		recover = true;
-	}
-
 	if (bdp->wolopts & (WAKE_UCAST | WAKE_ARP)) {
-		full_init = true;
+		full_reset = true;
 	}
 
-	e100_deisolate_driver(bdp, recover, full_init);
+	e100_deisolate_driver(bdp, full_reset);
 
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/e100/e100_test.c linux-2.4.21/drivers/net/e100/e100_test.c
--- linux-2.4.20/drivers/net/e100/e100_test.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/net/e100/e100_test.c	2002-12-18 18:58:03.000000000 +0000
@@ -95,12 +95,8 @@
 		test_info [E100_EEPROM_TEST_FAIL] = true;
 	}
 
-	/* fully recover only if the device is open*/
-	if (netif_running(dev))  {
-		e100_deisolate_driver(bdp, true, false);
-	} else {
-    		e100_deisolate_driver(bdp, false, false);
-	}
+	e100_deisolate_driver(bdp, false);
+
 	/*Let card recover from the test*/
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(HZ * 2);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/eepro100.c linux-2.4.21/drivers/net/eepro100.c
--- linux-2.4.20/drivers/net/eepro100.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/net/eepro100.c	2002-12-18 18:58:10.000000000 +0000
@@ -17,7 +17,7 @@
 	1998 Apr - 2000 Feb  Andrey V. Savochkin <saw@saw.sw.com.sg>
 		Serious fixes for multicast filter list setting, TX timeout routine;
 		RX ring refilling logic;  other stuff
-	2000 Feb  Jeff Garzik <jgarzik@mandrakesoft.com>
+	2000 Feb  Jeff Garzik <jgarzik@pobox.com>
 		Convert to new PCI driver interface
 	2000 Mar 24  Dragan Stancevic <visitor@valinux.com>
 		Disabled FC and ER, to avoid lockups when when we get FCP interrupts.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/ewrk3.c linux-2.4.21/drivers/net/ewrk3.c
--- linux-2.4.20/drivers/net/ewrk3.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/net/ewrk3.c	2002-12-18 18:58:08.000000000 +0000
@@ -712,6 +712,7 @@
 	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
 	u_char csr, page;
 	u_long iobase = dev->base_addr;
+	int i;
 
 	/*
 	   ** Enable any multicasts
@@ -719,6 +720,13 @@
 	set_multicast_list(dev);
 
 	/*
+	** Set hardware MAC address. Address is initialized from the EEPROM
+	** during startup but may have since been changed by the user.
+	*/
+	for (i=0; i<ETH_ALEN; i++)
+		outb(dev->dev_addr[i], EWRK3_PAR0 + i);
+
+	/*
 	   ** Clean out any remaining entries in all the queues here
 	 */
 	while (inb(EWRK3_TQ));
@@ -1759,23 +1767,17 @@
 		return 0;
 	}
 
-#ifdef BROKEN
 	/* Blink LED for identification */
 	case ETHTOOL_PHYS_ID: {
 		struct ethtool_value edata;
 		u_long flags;
-		long delay, ret;
 		u_char cr;
 		int count;
-		wait_queue_head_t wait;
-
-		init_waitqueue_head(&wait);
 
 		if (copy_from_user(&edata, useraddr, sizeof(edata)))
 			return -EFAULT;
 
 		/* Toggle LED 4x per second */
-		delay = HZ >> 2;
 		count = edata.data << 2;
 
 		spin_lock_irqsave(&lp->hw_lock, flags);
@@ -1796,24 +1798,21 @@
 
 			/* Wait a little while */
 			spin_unlock_irqrestore(&lp->hw_lock, flags);
-			ret = delay;
-			__wait_event_interruptible_timeout(wait, 0, ret);
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(HZ>>2);
 			spin_lock_irqsave(&lp->hw_lock, flags);
 
 			/* Exit if we got a signal */
-			if (ret == -ERESTARTSYS)
-				goto out;
+			if (signal_pending(current))
+				break;
 		}
 
-		ret = 0;
-out:
 		lp->led_mask = CR_LED;
 		cr = inb(EWRK3_CR);
 		outb(cr & ~CR_LED, EWRK3_CR);
 		spin_unlock_irqrestore(&lp->hw_lock, flags);
-		return ret;
+		return signal_pending(current) ? -ERESTARTSYS : 0;
 	}
-#endif /* BROKEN */
 
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/fealnx.c linux-2.4.21/drivers/net/fealnx.c
--- linux-2.4.20/drivers/net/fealnx.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/net/fealnx.c	2002-12-18 18:58:10.000000000 +0000
@@ -1198,7 +1198,6 @@
 		printk("\n");
 	}
 
-	   + dev->if_port = np->default_port;
 	/* Reinit. Gross */
 
 	/* Reset the chip's Tx and Rx processes. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/hamachi.c linux-2.4.21/drivers/net/hamachi.c
--- linux-2.4.20/drivers/net/hamachi.c	2002-12-18 18:27:07.000000000 +0000
+++ linux-2.4.21/drivers/net/hamachi.c	2002-12-18 18:58:08.000000000 +0000
@@ -158,7 +158,6 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/time.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
@@ -508,13 +507,11 @@
 	unsigned int cur_tx, dirty_tx;
 	unsigned int rx_buf_sz;			/* Based on MTU+slack. */
 	unsigned int tx_full:1;			/* The Tx queue is full. */
-	unsigned int full_duplex:1;		/* Full-duplex operation requested. */
 	unsigned int duplex_lock:1;
-	unsigned int medialock:1;		/* Do not sense media. */
 	unsigned int default_port:4;		/* Last dev->if_port value. */
 	/* MII transceiver section. */
 	int mii_cnt;								/* MII device addresses. */
-	u16 advertising;							/* NWay media advertisement */
+	struct mii_if_info mii_if;		/* MII lib hooks/info */
 	unsigned char phys[MII_CNT];		/* MII device addresses, only first one used. */
 	u32 rx_int_var, tx_int_var;	/* interrupt control variables */
 	u32 option;							/* Hold on to a copy of the options */
@@ -557,8 +554,8 @@
 MODULE_PARM_DESC(force32, "GNIC-II: Bit 0: 32 bit PCI, bit 1: disable parity, bit 2: 64 bit PCI (all boards)");
                                                                         
 static int read_eeprom(long ioaddr, int location);
-static int mdio_read(long ioaddr, int phy_id, int location);
-static void mdio_write(long ioaddr, int phy_id, int location, int value);
+static int mdio_read(struct net_device *dev, int phy_id, int location);
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
 static int hamachi_open(struct net_device *dev);
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void hamachi_timer(unsigned long data);
@@ -640,6 +637,12 @@
 	hmp = dev->priv;
 	spin_lock_init(&hmp->lock);
 
+	hmp->mii_if.dev = dev;
+	hmp->mii_if.mdio_read = mdio_read;
+	hmp->mii_if.mdio_write = mdio_write;
+	hmp->mii_if.phy_id_mask = 0x1f;
+	hmp->mii_if.reg_num_mask = 0x1f;
+
 	ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);
 	if (!ring_space)
 		goto err_out_cleardev;
@@ -688,18 +691,18 @@
 	if (option > 0) {
 		hmp->option = option;
 		if (option & 0x200)
-			hmp->full_duplex = 1;
+			hmp->mii_if.full_duplex = 1;
 		else if (option & 0x080)
-			hmp->full_duplex = 0;
+			hmp->mii_if.full_duplex = 0;
 		hmp->default_port = option & 15;
 		if (hmp->default_port)
-			hmp->medialock = 1;
+			hmp->mii_if.force_media = 1;
 	}
 	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)
-		hmp->full_duplex = 1;
+		hmp->mii_if.full_duplex = 1;
 
 	/* lock the duplex mode if someone specified a value */
-	if (hmp->full_duplex || (option & 0x080))
+	if (hmp->mii_if.full_duplex || (option & 0x080))
 		hmp->duplex_lock = 1;
 
 	/* Set interrupt tuning parameters */
@@ -752,17 +755,21 @@
 	if (chip_tbl[hmp->chip_id].flags & CanHaveMII) {
 		int phy, phy_idx = 0;
 		for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) {
-			int mii_status = mdio_read(ioaddr, phy, 1);
+			int mii_status = mdio_read(dev, phy, MII_BMSR);
 			if (mii_status != 0xffff  &&
 				mii_status != 0x0000) {
 				hmp->phys[phy_idx++] = phy;
-				hmp->advertising = mdio_read(ioaddr, phy, 4);
+				hmp->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);
 				printk(KERN_INFO "%s: MII PHY found at address %d, status "
 					   "0x%4.4x advertising %4.4x.\n",
-					   dev->name, phy, mii_status, hmp->advertising);
+					   dev->name, phy, mii_status, hmp->mii_if.advertising);
 			}
 		}
 		hmp->mii_cnt = phy_idx;
+		if (hmp->mii_cnt > 0)
+			hmp->mii_if.phy_id = hmp->phys[0];
+		else
+			memset(&hmp->mii_if, 0, sizeof(hmp->mii_if));
 	}
 	/* Configure gigabit autonegotiation. */
 	writew(0x0400, ioaddr + ANXchngCtrl);	/* Enable legacy links. */
@@ -808,8 +815,9 @@
    These routines assume the MDIO controller is idle, and do not exit until
    the command is finished. */
 
-static int mdio_read(long ioaddr, int phy_id, int location)
+static int mdio_read(struct net_device *dev, int phy_id, int location)
 {
+	long ioaddr = dev->base_addr;
 	int i;
 
 	/* We should check busy first - per docs -KDU */
@@ -824,8 +832,9 @@
 	return readw(ioaddr + MII_Rd_Data);
 }
 
-static void mdio_write(long ioaddr, int phy_id, int location, int value)
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
 {
+	long ioaddr = dev->base_addr;
 	int i;
 
 	/* We should check busy first - per docs -KDU */
@@ -915,7 +924,7 @@
 	/* Setting the Rx mode will start the Rx process. */
 	/* If someone didn't choose a duplex, default to full-duplex */ 
 	if (hmp->duplex_lock != 1)
-		hmp->full_duplex = 1;
+		hmp->mii_if.full_duplex = 1;
 
 	/* always 1, takes no more time to do it */
 	writew(0x0001, ioaddr + RxChecksum);
@@ -1463,64 +1472,6 @@
 	spin_unlock(&hmp->lock);
 }
 
-#ifdef TX_CHECKSUM
-/*
- * Copied from eth_type_trans(), with reduced header, since we don't
- * get it on RX, only on TX.
- */
-static unsigned short hamachi_eth_type_trans(struct sk_buff *skb,
-  struct net_device *dev)
-{
-	struct ethhdr *eth;
-	unsigned char *rawp;
-	
-	skb->mac.raw=skb->data;
-	skb_pull(skb,dev->hard_header_len-8);  /* artificially enlarged on tx */
-	eth= skb->mac.ethernet;
-	
-	if(*eth->h_dest&1)
-	{
-		if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)
-			skb->pkt_type=PACKET_BROADCAST;
-		else
-			skb->pkt_type=PACKET_MULTICAST;
-	}
-	
-	/*
-	 *	This ALLMULTI check should be redundant by 1.4
-	 *	so don't forget to remove it.
-	 *
-	 *	Seems, you forgot to remove it. All silly devices
-	 *	seems to set IFF_PROMISC.
-	 */
-	 
-	else if(dev->flags&(IFF_PROMISC/*|IFF_ALLMULTI*/))
-	{
-		if(memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN))
-			skb->pkt_type=PACKET_OTHERHOST;
-	}
-	
-	if (ntohs(eth->h_proto) >= 1536)
-		return eth->h_proto;
-		
-	rawp = skb->data;
-	
-	/*
-	 *	This is a magic hack to spot IPX packets. Older Novell breaks
-	 *	the protocol design and runs IPX over 802.3 without an 802.2 LLC
-	 *	layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
-	 *	won't work for fault tolerant netware but does for the rest.
-	 */
-	if (*(unsigned short *)rawp == 0xFFFF)
-		return htons(ETH_P_802_3);
-		
-	/*
-	 *	Real 802.2 LLC
-	 */
-	return htons(ETH_P_802_2);
-}
-#endif  /* TX_CHECKSUM */
-
 /* This routine is logically part of the interrupt handler, but seperated
    for clarity and better register allocation. */
 static int hamachi_rx(struct net_device *dev)
@@ -1625,12 +1576,7 @@
 				skb_put(skb = hmp->rx_skbuff[entry], pkt_len);
 				hmp->rx_skbuff[entry] = NULL;
 			}
-#ifdef TX_CHECKSUM
-			/* account for extra TX hard_header bytes */
-			skb->protocol = hamachi_eth_type_trans(skb, dev);
-#else
 			skb->protocol = eth_type_trans(skb, dev);
-#endif
 
 
 #ifdef RX_CHECKSUM
@@ -1912,7 +1858,7 @@
 
 static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
 {
-	struct hamachi_private *hmp = dev->priv;
+	struct hamachi_private *np = dev->priv;
 	u32 ethcmd;
 		
 	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
@@ -1923,12 +1869,53 @@
 		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
 		strcpy(info.driver, DRV_NAME);
 		strcpy(info.version, DRV_VERSION);
-		strcpy(info.bus_info, hmp->pci_dev->slot_name);
+		strcpy(info.bus_info, np->pci_dev->slot_name);
 		if (copy_to_user(useraddr, &info, sizeof(info)))
 			return -EFAULT;
 		return 0;
 	}
 
+	/* get settings */
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		if (!(chip_tbl[np->chip_id].flags & CanHaveMII))
+			return -EINVAL;
+		spin_lock_irq(&np->lock);
+		mii_ethtool_gset(&np->mii_if, &ecmd);
+		spin_unlock_irq(&np->lock);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set settings */
+	case ETHTOOL_SSET: {
+		int r;
+		struct ethtool_cmd ecmd;
+		if (!(chip_tbl[np->chip_id].flags & CanHaveMII))
+			return -EINVAL;
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+		spin_lock_irq(&np->lock);
+		r = mii_ethtool_sset(&np->mii_if, &ecmd);
+		spin_unlock_irq(&np->lock);
+		return r;
+	}
+	/* restart autonegotiation */
+	case ETHTOOL_NWAY_RST: {
+		if (!(chip_tbl[np->chip_id].flags & CanHaveMII))
+			return -EINVAL;
+		return mii_nway_restart(&np->mii_if);
+	}
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = {ETHTOOL_GLINK};
+		if (!(chip_tbl[np->chip_id].flags & CanHaveMII))
+			return -EINVAL;
+		edata.data = mii_link_ok(&np->mii_if);
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
         }
 	
 	return -EOPNOTSUPP;
@@ -1936,32 +1923,17 @@
 
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	long ioaddr = dev->base_addr;
-	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
+	struct hamachi_private *np = dev->priv;
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
+	int rc;
 
-	switch(cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
-		data->phy_id = ((struct hamachi_private *)dev->priv)->phys[0] & 0x1f;
-		/* Fall Through */
-
-	case SIOCGMIIREG:		/* Read MII PHY register. */
-	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
-		data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f);
-		return 0;
+	if (!netif_running(dev))
+		return -EINVAL;
 
-	case SIOCSMIIREG:		/* Write MII PHY register. */
-	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
-		/* TODO: Check the sequencing of this.  Might need to stop and
-		 * restart Rx and Tx engines. -KDU
-		 */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		mdio_write(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
-		return 0;
-	case SIOCDEVPRIVATE+3: { /* set rx,tx intr params */
+	if (cmd == SIOCETHTOOL)
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
+	else if (cmd == (SIOCDEVPRIVATE+3)) { /* set rx,tx intr params */
 		u32 *d = (u32 *)&rq->ifr_data;
 		/* Should add this check here or an ordinary user can do nasty
 		 * things. -KDU
@@ -1975,11 +1947,16 @@
 		printk(KERN_NOTICE "%s: tx %08x, rx %08x intr\n", dev->name,
 		  (u32) readl(dev->base_addr + TxIntrCtrl),
 		  (u32) readl(dev->base_addr + RxIntrCtrl));
-		return 0;
-	    }
-	default:
-		return -EOPNOTSUPP;
+		rc = 0;
+	}
+
+	else {
+		spin_lock_irq(&np->lock);
+		rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
+		spin_unlock_irq(&np->lock);
 	}
+
+	return rc;
 }
 
 
@@ -2010,10 +1987,10 @@
 MODULE_DEVICE_TABLE(pci, hamachi_pci_tbl);
 
 static struct pci_driver hamachi_driver = {
-	name:		DRV_NAME,
-	id_table:	hamachi_pci_tbl,
-	probe:		hamachi_init_one,
-	remove:		__devexit_p(hamachi_remove_one),
+	.name		= DRV_NAME,
+	.id_table	= hamachi_pci_tbl,
+	.probe		= hamachi_init_one,
+	.remove		= __devexit_p(hamachi_remove_one),
 };
 
 static int __init hamachi_init (void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/irda/ali-ircc.c linux-2.4.21/drivers/net/irda/ali-ircc.c
--- linux-2.4.20/drivers/net/irda/ali-ircc.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/irda/ali-ircc.c	2002-12-18 18:58:07.000000000 +0000
@@ -2017,22 +2017,19 @@
 
 	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
 	
-	/* Disable interrupts & save flags */
-	save_flags(flags);
-	cli();	
-	
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
 		IRDA_DEBUG(1, "%s(), SIOCSBANDWIDTH\n", __FUNCTION__);
-		/*
-		 * This function will also be used by IrLAP to change the
-		 * speed, so we still must allow for speed change within
-		 * interrupt context.
-		 */
-		if (!in_interrupt() && !capable(CAP_NET_ADMIN))
+		/* Root only */
+		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 		
+		/* Is it really needed ? And what about spinlock ? */
+		save_flags(flags);
+		cli();	
+
 		ali_ircc_change_speed(self, irq->ifr_baudrate);		
+		restore_flags(flags);
 		break;
 	case SIOCSMEDIABUSY: /* Set media busy */
 		IRDA_DEBUG(1, "%s(), SIOCSMEDIABUSY\n", __FUNCTION__);
@@ -2042,14 +2039,17 @@
 		break;
 	case SIOCGRECEIVING: /* Check if we are receiving right now */
 		IRDA_DEBUG(2, "%s(), SIOCGRECEIVING\n", __FUNCTION__);
+		/* Is it really needed ? And what about spinlock ? */
+		save_flags(flags);
+		cli();	
+
 		irq->ifr_receiving = ali_ircc_is_receiving(self);
+		restore_flags(flags);
 		break;
 	default:
 		ret = -EOPNOTSUPP;
 	}
-	
-	restore_flags(flags);
-	
+
 	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 	
 	return ret;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/irda/irtty.c linux-2.4.21/drivers/net/irda/irtty.c
--- linux-2.4.20/drivers/net/irda/irtty.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/irda/irtty.c	2002-12-18 18:58:05.000000000 +0000
@@ -966,9 +966,14 @@
 
 	IRDA_DEBUG(3, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
 	
-	/* Disable interrupts & save flags */
-	save_flags(flags);
-	cli();
+	/* Locking :
+	 * irda_device_dongle_init() can't be locked.
+	 * irda_task_execute() doesn't need to be locked (but
+	 * irtty_change_speed() should protect itself).
+	 * As this driver doesn't have spinlock protection, keep
+	 * old fashion locking :-(
+	 * Jean II
+	 */
 	
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
@@ -994,14 +999,17 @@
 		dongle->write       = irtty_raw_write;
 		dongle->set_dtr_rts = irtty_set_dtr_rts;
 		
-		self->dongle = dongle;
-
-		/* Now initialize the dongle!  */
+		/* Now initialize the dongle!
+		 * Safe to do unlocked : self->dongle is still NULL. */ 
 		dongle->issue->open(dongle, &self->qos);
 		
 		/* Reset dongle */
 		irda_task_execute(dongle, dongle->issue->reset, NULL, NULL, 
 				  NULL);	
+
+		/* Make dongle available to driver only now to avoid
+		 * race conditions - Jean II */
+		self->dongle = dongle;
 		break;
 	case SIOCSMEDIABUSY: /* Set media busy */
 		if (!capable(CAP_NET_ADMIN))
@@ -1015,21 +1023,27 @@
 	case SIOCSDTRRTS:
 		if (!capable(CAP_NET_ADMIN))
 			ret = -EPERM;
-		else
+		else {
+			save_flags(flags);
+			cli();
 			irtty_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
+			restore_flags(flags);
+		}
 		break;
 	case SIOCSMODE:
 		if (!capable(CAP_NET_ADMIN))
 			ret = -EPERM;
-		else
+		else {
+			save_flags(flags);
+			cli();
 			irtty_set_mode(dev, irq->ifr_mode);
+			restore_flags(flags);
+		}
 		break;
 	default:
 		ret = -EOPNOTSUPP;
 	}
 	
-	restore_flags(flags);
-	
 	return ret;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/irda/smc-ircc.c linux-2.4.21/drivers/net/irda/smc-ircc.c
--- linux-2.4.20/drivers/net/irda/smc-ircc.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/irda/smc-ircc.c	2002-12-18 18:58:01.000000000 +0000
@@ -10,6 +10,8 @@
  * Modified by:   Dag Brattli <dag@brattli.net>
  * Modified at:   Tue Jun 26 2001
  * Modified by:   Stefani Seibold <stefani@seibold.net>
+ * Modified at:   Thur Apr 18 2002
+ * Modified by:   Jeff Snyder <je4d@pobox.com>
  * 
  *     Copyright (c) 2001      Stefani Seibold
  *     Copyright (c) 1999-2001 Dag Brattli
@@ -537,7 +539,7 @@
 	if (ircc_irq < 255) {
 		if (ircc_irq!=irq)
 			MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n",
-				driver_name, self->io->irq, ircc_irq);
+				driver_name, irq, ircc_irq);
 		self->io->irq = ircc_irq;
 	}
 	else
@@ -545,13 +547,13 @@
 	if (ircc_dma < 255) {
 		if (ircc_dma!=dma)
 			MESSAGE("%s, Overriding DMA - chip says %d, using %d\n",
-				driver_name, self->io->dma, ircc_dma);
+				driver_name, dma, ircc_dma);
 		self->io->dma = ircc_dma;
 	}
 	else
 		self->io->dma = dma;
 
-	request_region(fir_base, CHIP_IO_EXTENT, driver_name);
+	request_region(self->io->fir_base, CHIP_IO_EXTENT, driver_name);
 
 	/* Initialize QoS for this device */
 	irda_init_max_qos_capabilies(&irport->qos);
@@ -1187,10 +1189,9 @@
         outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB);
 #endif
 	/* Release the PORT that this driver is using */
-	IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", 
-		__FUNCTION__, self->io->fir_base);
+	IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__, iobase);
 
-	release_region(self->io->fir_base, self->io->fir_ext);
+	release_region(iobase, CHIP_IO_EXTENT);
 
 	if (self->tx_buff.head)
 		kfree(self->tx_buff.head);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/lasi_82596.c linux-2.4.21/drivers/net/lasi_82596.c
--- linux-2.4.20/drivers/net/lasi_82596.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/lasi_82596.c	2002-12-18 18:58:03.000000000 +0000
@@ -1412,8 +1412,7 @@
 	DEB(DEB_INIT,printk("%s: Shutting down ethercard, status was %4.4x.\n",
 		       dev->name, lp->scb.status));
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lp->lock, flags);
 
 	wait_cmd(dev,lp,100,"close1 timed out");
 	lp->scb.command = CUC_ABORT | RX_ABORT;
@@ -1422,7 +1421,7 @@
 	CA(dev);
 
 	wait_cmd(dev,lp,100,"close2 timed out");
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lp->lock, flags);
 	DEB(DEB_STRUCT,i596_display_data(dev));
 	i596_cleanup_cmd(dev,lp);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/mii.c linux-2.4.21/drivers/net/mii.c
--- linux-2.4.20/drivers/net/mii.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/mii.c	2002-12-18 18:58:06.000000000 +0000
@@ -2,7 +2,7 @@
 
 	mii.c: MII interface library
 
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2001,2002 Jeff Garzik
 
 	Various code came from myson803.c and other files by
@@ -339,7 +339,7 @@
 	return rc;
 }
 
-MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
+MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
 MODULE_DESCRIPTION ("MII hardware support library");
 MODULE_LICENSE("GPL");
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/ni52.c linux-2.4.21/drivers/net/ni52.c
--- linux-2.4.20/drivers/net/ni52.c	2001-09-30 19:26:07.000000000 +0000
+++ linux-2.4.21/drivers/net/ni52.c	2002-12-18 18:58:02.000000000 +0000
@@ -226,10 +226,11 @@
 	volatile struct iscp_struct	*iscp;	/* volatile is important */
 	volatile struct scb_struct	*scb;	/* volatile is important */
 	volatile struct tbd_struct	*xmit_buffs[NUM_XMIT_BUFFS];
-	volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
 #if (NUM_XMIT_BUFFS == 1)
+	volatile struct transmit_cmd_struct *xmit_cmds[2];
 	volatile struct nop_cmd_struct *nop_cmds[2];
 #else
+	volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
 	volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
 #endif
 	volatile int		nop_point,num_recv_buffs;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/ns83820.c linux-2.4.21/drivers/net/ns83820.c
--- linux-2.4.20/drivers/net/ns83820.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/ns83820.c	2002-12-18 18:58:11.000000000 +0000
@@ -1214,7 +1214,7 @@
 
 static int ns83820_ioctl(struct net_device *_dev, struct ifreq *rq, int cmd)
 {
-	struct ns83820 *dev = _dev->priv;
+	struct ns83820 *dev = (struct ns83820 *)_dev;
 
 	switch(cmd) {
 	case SIOCETHTOOL:
@@ -1788,6 +1788,7 @@
 	dev->ee.cache = &dev->MEAR_cache;
 	dev->ee.lock = &dev->misc_lock;
 	dev->net_dev.owner = THIS_MODULE;
+	dev->net_dev.priv = dev;
 
 	PREPARE_TQUEUE(&dev->tq_refill, queue_refill, dev);
 	tasklet_init(&dev->rx_tasklet, rx_action, (unsigned long)dev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/pci-skeleton.c linux-2.4.21/drivers/net/pci-skeleton.c
--- linux-2.4.20/drivers/net/pci-skeleton.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/pci-skeleton.c	2002-12-18 18:58:02.000000000 +0000
@@ -2,7 +2,7 @@
 
 	drivers/net/pci-skeleton.c
 
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 
 	Original code came from 8139too.c, which in turns was based
 	originally on Donald Becker's rtl8139.c driver, versions 1.11
@@ -483,7 +483,7 @@
 	chip_t chipset;
 };
 
-MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
+MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
 MODULE_DESCRIPTION ("Skeleton for a PCI Fast Ethernet driver");
 MODULE_LICENSE("GPL");
 MODULE_PARM (multicast_filter_limit, "i");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/pcmcia/fmvj18x_cs.c linux-2.4.21/drivers/net/pcmcia/fmvj18x_cs.c
--- linux-2.4.20/drivers/net/pcmcia/fmvj18x_cs.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/pcmcia/fmvj18x_cs.c	2002-12-18 18:58:03.000000000 +0000
@@ -1,5 +1,5 @@
 /*======================================================================
-    fmvj18x_cs.c 2.6 2001/09/17
+    fmvj18x_cs.c 2.8 2002/03/23
 
     A fmvj18x (and its compatibles) PCMCIA client driver
 
@@ -29,7 +29,7 @@
 ======================================================================*/
 
 #define DRV_NAME	"fmvj18x_cs"
-#define DRV_VERSION	"2.6"
+#define DRV_VERSION	"2.8"
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -65,6 +65,10 @@
 /*====================================================================*/
 
 /* Module parameters */
+
+MODULE_DESCRIPTION("fmvj18x and compatible PCMCIA ethernet driver");
+MODULE_LICENSE("GPL");
+
 #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
 /* Bit map of interrupts to choose from */
@@ -80,7 +84,7 @@
 #ifdef PCMCIA_DEBUG
 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version = DRV_NAME ".c " DRV_VERSION " 2001/09/17";
+static char *version = DRV_NAME ".c " DRV_VERSION " 2002/03/23";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -91,6 +95,7 @@
  */
 static void fmvj18x_config(dev_link_t *link);
 static int fmvj18x_get_hwinfo(dev_link_t *link, u_char *node_id);
+static int fmvj18x_setup_mfc(dev_link_t *link);
 static void fmvj18x_release(u_long arg);
 static int fmvj18x_event(event_t event, int priority,
 			  event_callback_args_t *args);
@@ -122,8 +127,6 @@
 	       XXX10304
 } cardtype_t;
 
-#define MANFID_UNGERMANN 0x02c0
-
 /*
     driver specific data structure
 */
@@ -388,6 +391,45 @@
 #define CS_CHECK(fn, args...) \
 while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
 
+static int mfc_try_io_port(dev_link_t *link)
+{
+    int i, ret;
+    static ioaddr_t serial_base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+
+    for (i = 0; i < 5; i++) {
+	link->io.BasePort2 = serial_base[i];
+	link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+	if (link->io.BasePort2 == 0) {
+	    link->io.NumPorts2 = 0;
+	    printk(KERN_NOTICE "fmvj18x_cs: out of resource for serial\n");
+	}
+	ret = CardServices(RequestIO, link->handle, &link->io);
+	if (ret == CS_SUCCESS) return ret;
+    }
+    return ret;
+}
+
+static int ungermann_try_io_port(dev_link_t *link)
+{
+    int ret;
+    ioaddr_t ioaddr;
+    /*
+	Ungermann-Bass Access/CARD accepts 0x300,0x320,0x340,0x360
+	0x380,0x3c0 only for ioport.
+    */
+    for (ioaddr = 0x300; ioaddr < 0x3e0; ioaddr += 0x20) {
+	link->io.BasePort1 = ioaddr;
+	ret = CardServices(RequestIO, link->handle, &link->io);
+	if (ret == CS_SUCCESS) {
+	    /* calculate ConfigIndex value */
+	    link->conf.ConfigIndex = 
+		((link->io.BasePort1 & 0x0f0) >> 3) | 0x22;
+	    return ret;
+	}
+    }
+    return ret;	/* RequestIO failed */
+}
+
 static void fmvj18x_config(dev_link_t *link)
 {
     client_handle_t handle = link->handle;
@@ -401,7 +443,7 @@
     cardtype_t cardtype;
     char *card_name = "unknown";
     u_char *node_id;
-    
+
     DEBUG(0, "fmvj18x_config(0x%p)\n", link);
 
     /*
@@ -444,6 +486,11 @@
 		CardServices(GetStatus, handle, &status);
 		if (status.CardState & CS_EVENT_3VCARD)
 		    link->conf.Vcc = 33; /* inserted in 3.3V slot */
+	    } else if (le16_to_cpu(buf[1]) == PRODID_TDK_GN3410) {
+		/* MultiFunction Card */
+		link->conf.ConfigBase = 0x800;
+		link->conf.ConfigIndex = 0x47;
+		link->io.NumPorts2 = 8;
 	    }
 	    break;
 	case MANFID_CONTEC:
@@ -481,31 +528,22 @@
 	    break;
 	case MANFID_UNGERMANN:
 	    cardtype = UNGERMANN;
-	    /*
-	       Ungermann-Bass Access/CARD accepts 0x300,0x320,0x340,0x360
-	       0x380,0x3c0 only for ioport.
-	    */
-	    for (link->io.BasePort1 = 0x300; link->io.BasePort1 < 0x3e0;
-		link->io.BasePort1 += 0x20) {
-		ret = CardServices(RequestIO, link->handle, &link->io);
-		if (ret == CS_SUCCESS) {
-		/* calculate ConfigIndex value */
-		link->conf.ConfigIndex = 
-		    ((link->io.BasePort1 & 0x0f0) >> 3) | 0x22;
-		goto req_irq;
-		}
-	    }
-	    /* if ioport allocation is failed, goto failed */
-	    printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n");
-	    goto failed;
+	    break;
 	default:
 	    cardtype = MBH10302;
 	    link->conf.ConfigIndex = 1;
 	}
     }
 
-    CS_CHECK(RequestIO, link->handle, &link->io);
-req_irq:
+    if (link->io.NumPorts2 != 0) {
+	ret = mfc_try_io_port(link);
+	if (ret != CS_SUCCESS) goto cs_failed;
+    } else if (cardtype == UNGERMANN) {
+	ret = ungermann_try_io_port(link);
+	if (ret != CS_SUCCESS) goto cs_failed;
+    } else { 
+	CS_CHECK(RequestIO, link->handle, &link->io);
+    }
     CS_CHECK(RequestIRQ, link->handle, &link->irq);
     CS_CHECK(RequestConfiguration, link->handle, &link->conf);
     dev->irq = link->irq.AssignedIRQ;
@@ -515,19 +553,22 @@
 	goto failed;
     }
 
+    if (link->io.BasePort2 != 0)
+	fmvj18x_setup_mfc(link);
+
     ioaddr = dev->base_addr;
 
     /* Reset controller */
-    if( sram_config == 0 ) 
+    if (sram_config == 0) 
 	outb(CONFIG0_RST, ioaddr + CONFIG_0);
     else
 	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
 
     /* Power On chip and select bank 0 */
-    if(cardtype == UNGERMANN)
-	outb(BANK_0U, ioaddr + CONFIG_1);
-    else
+    if (cardtype == MBH10302)
 	outb(BANK_0, ioaddr + CONFIG_1);
+    else
+	outb(BANK_0U, ioaddr + CONFIG_1);
     
     /* Set hardware address */
     switch (cardtype) {
@@ -591,7 +632,6 @@
 
     strcpy(lp->node.dev_name, dev->name);
     link->dev = &lp->node;
-    link->state &= ~DEV_CONFIG_PENDING;
 
     lp->cardtype = cardtype;
     /* print current configuration */
@@ -601,6 +641,7 @@
     for (i = 0; i < 6; i++)
 	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
 
+    link->state &= ~DEV_CONFIG_PENDING;
     return;
     
 cs_failed:
@@ -608,6 +649,7 @@
     cs_error(link->handle, last_fn, last_ret);
 failed:
     fmvj18x_release((u_long)link);
+    link->state &= ~DEV_CONFIG_PENDING;
 
 } /* fmvj18x_config */
 /*====================================================================*/
@@ -666,6 +708,51 @@
 } /* fmvj18x_get_hwinfo */
 /*====================================================================*/
 
+static int fmvj18x_setup_mfc(dev_link_t *link)
+{
+    win_req_t req;
+    memreq_t mem;
+    u_char *base;
+    int i, j;
+    local_info_t *lp = link->priv;
+    struct net_device *dev = &lp->dev;
+    ioaddr_t ioaddr;
+
+    /* Allocate a small memory window */
+    req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
+    req.Base = 0; req.Size = 0;
+    req.AccessSpeed = 0;
+    link->win = (window_handle_t)link->handle;
+    i = CardServices(RequestWindow, &link->win, &req);
+    if (i != CS_SUCCESS) {
+	cs_error(link->handle, RequestWindow, i);
+	return -1;
+    }
+
+    base = ioremap(req.Base, req.Size);
+    mem.Page = 0;
+    mem.CardOffset = 0;
+    CardServices(MapMemPage, link->win, &mem);
+
+    ioaddr = dev->base_addr;
+    writeb(0x47, base+0x800);	/* Config Option Register of LAN */
+    writeb(0x0, base+0x802);	/* Config and Status Register */
+
+    writeb(ioaddr & 0xff, base+0x80a);		/* I/O Base(Low) of LAN */
+    writeb((ioaddr >> 8) & 0xff, base+0x80c);	/* I/O Base(High) of LAN */
+   
+    writeb(0x45, base+0x820);	/* Config Option Register of Modem */
+    writeb(0x8, base+0x822);	/* Config and Status Register */
+
+    iounmap(base);
+    j = CardServices(ReleaseWindow, link->win);
+    if (j != CS_SUCCESS)
+	cs_error(link->handle, ReleaseWindow, j);
+    return 0;
+
+}
+/*====================================================================*/
+
 static void fmvj18x_release(u_long arg)
 {
     dev_link_t *link = (dev_link_t *)arg;
@@ -752,7 +839,7 @@
     if (serv.Revision != CS_RELEASE_CODE) {
 	printk(KERN_NOTICE "fmvj18x: Card Services release "
 	       "does not match!\n");
-	return -1;
+	return -EINVAL;
     }
     register_pccard_driver(&dev_info, &fmvj18x_attach, &fmvj18x_detach);
     return 0;
@@ -942,10 +1029,10 @@
 	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
 
     /* Power On chip and select bank 0 */
-    if( lp->cardtype == UNGERMANN)
-	outb(BANK_0U, ioaddr + CONFIG_1);
-    else
+    if (lp->cardtype == MBH10302)
 	outb(BANK_0, ioaddr + CONFIG_1);
+    else
+	outb(BANK_0U, ioaddr + CONFIG_1);
 
     /* Set Tx modes */
     outb(D_TX_MODE, ioaddr + TX_MODE);
@@ -957,20 +1044,20 @@
         outb(dev->dev_addr[i], ioaddr + NODE_ID + i);
 
     /* Switch to bank 1 */
-    if ( lp->cardtype == UNGERMANN )
-	outb(BANK_1U, ioaddr + CONFIG_1);
-    else
+    if (lp->cardtype == MBH10302)
 	outb(BANK_1, ioaddr + CONFIG_1);
+    else
+	outb(BANK_1U, ioaddr + CONFIG_1);
 
     /* set the multicast table to accept none. */
     for (i = 0; i < 6; i++) 
         outb(0x00, ioaddr + MAR_ADR + i);
 
     /* Switch to bank 2 (runtime mode) */
-    if ( lp->cardtype == UNGERMANN )
-	outb(BANK_2U, ioaddr + CONFIG_1);
-    else
+    if (lp->cardtype == MBH10302)
 	outb(BANK_2, ioaddr + CONFIG_1);
+    else
+	outb(BANK_2U, ioaddr + CONFIG_1);
 
     /* set 16col ctrl bits */
     if( lp->cardtype == TDK || lp->cardtype == CONTEC) 
@@ -999,16 +1086,16 @@
     outb(0xff, ioaddr + TX_STATUS);
     outb(0xff, ioaddr + RX_STATUS);
 
-    if( lp->cardtype != TDK ) 
-    		outb(INTR_OFF, ioaddr + LAN_CTRL);
+    if (lp->cardtype == MBH10302)
+	outb(INTR_OFF, ioaddr + LAN_CTRL);
 
     /* Turn on Rx interrupts */
     outb(D_TX_INTR, ioaddr + TX_INTR);
     outb(D_RX_INTR, ioaddr + RX_INTR);
 
     /* Turn on interrupts from LAN card controller */
-    if( lp->cardtype != TDK ) 
-		outb(INTR_ON, ioaddr + LAN_CTRL);
+    if (lp->cardtype == MBH10302)
+	outb(INTR_ON, ioaddr + LAN_CTRL);
 } /* fjn_reset */
 
 /*====================================================================*/
@@ -1063,7 +1150,7 @@
 
 	    skb_reserve(skb, 2);
 	    insw(ioaddr + DATAPORT, skb_put(skb, pkt_len),
-		    (pkt_len + 1) >> 1);
+		 (pkt_len + 1) >> 1);
 	    skb->protocol = eth_type_trans(skb, dev);
 
 #ifdef PCMCIA_DEBUG
@@ -1090,7 +1177,7 @@
 	   has done a netif_wake_queue() for us and will work on them
 	   when we get to the bottom-half routine. */
 /*
-    if( lp->cardtype != TDK ) {
+    if (lp->cardtype != TDK) {
 	int i;
 	for (i = 0; i < 20; i++) {
 	    if ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == F_BUF_EMP)
@@ -1223,7 +1310,7 @@
     outb(CHIP_OFF ,ioaddr + CONFIG_1);
 
     /* Set the ethernet adaptor disable IRQ */
-    if( lp->cardtype != TDK ) 
+    if (lp->cardtype == MBH10302)
 	outb(INTR_OFF, ioaddr + LAN_CTRL);
 
     link->open--;
@@ -1252,8 +1339,8 @@
 {
     ioaddr_t ioaddr = dev->base_addr;
     struct local_info_t *lp = (struct local_info_t *)dev->priv;
-    unsigned char mc_filter[8];		 /* Multicast hash filter */
-    unsigned long flags;
+    u_char mc_filter[8];		 /* Multicast hash filter */
+    u_long flags;
     int i;
     
     if (dev->flags & IFF_PROMISC) {
@@ -1293,4 +1380,3 @@
     }
     restore_flags(flags);
 }
-MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/pcmcia/smc91c92_cs.c linux-2.4.21/drivers/net/pcmcia/smc91c92_cs.c
--- linux-2.4.20/drivers/net/pcmcia/smc91c92_cs.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/pcmcia/smc91c92_cs.c	2002-12-18 18:58:03.000000000 +0000
@@ -8,8 +8,8 @@
 
     Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
 
-    smc91c92_cs.c 1.2 2002/09/28 15:00:00
-    
+    smc91c92_cs.c 1.122 2002/10/25 06:26:39
+
     This driver contains code written by Donald Becker
     (becker@scyld.com), Rowan Hughes (x-csrdh@jcu.edu.au),
     David Hinds (dahinds@users.sourceforge.net), and Erik Stahlman
@@ -18,7 +18,7 @@
     incorporated some parts of his driver here.  I (Dave) wrote most
     of the PCMCIA glue code, and the Ositech support code.  Kelly
     Stephens (kstephen@holli.com) added support for the Motorola
-    Mariner, with help from Allen Brost. 
+    Mariner, with help from Allen Brost.
 
     This software may be used and distributed according to the terms of
     the GNU General Public License, incorporated herein by reference.
@@ -92,7 +92,7 @@
 #endif
 
 #define DRV_NAME	"smc91c92_cs"
-#define DRV_VERSION	"1.2"
+#define DRV_VERSION	"1.122"
 
 /*====================================================================*/
 
@@ -130,6 +130,8 @@
     u_short			fast_poll;
     u_short			link_status;
     struct mii_if_info		mii_if;
+    int				duplex;
+    int				rx_ovrn;
 };
 
 /* Special definitions for Megahertz multifunction cards */
@@ -257,7 +259,7 @@
 #define	MULTICAST2	2
 #define	MULTICAST4	4
 #define	MULTICAST6	6
-#define MGMT    	8 
+#define MGMT    	8
 #define REVISION	0x0a
 
 /* Transmit status bits. */
@@ -287,22 +289,22 @@
 static int smc91c92_event(event_t event, int priority,
 			  event_callback_args_t *args);
 
-static int smc91c92_open(struct net_device *dev);
-static int smc91c92_close(struct net_device *dev);
+static int smc_open(struct net_device *dev);
+static int smc_close(struct net_device *dev);
+static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void smc_tx_timeout(struct net_device *dev);
 static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void smc_rx(struct net_device *dev);
-static struct net_device_stats *smc91c92_get_stats(struct net_device *dev);
+static struct net_device_stats *smc_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
 static int s9k_config(struct net_device *dev, struct ifmap *map);
 static void smc_set_xcvr(struct net_device *dev, int if_port);
 static void smc_reset(struct net_device *dev);
 static void media_check(u_long arg);
-static void smc_mdio_sync(ioaddr_t addr);
-static int smc_mdio_read(struct net_device *dev, int phy_id, int loc);
-static void smc_mdio_write(struct net_device *dev, int phy_id, int loc, int value);
-static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void mdio_sync(ioaddr_t addr);
+static int mdio_read(struct net_device *dev, int phy_id, int loc);
+static void mdio_write(struct net_device *dev, int phy_id, int loc, int value);
 static int smc_link_ok(struct net_device *dev);
 
 /*======================================================================
@@ -310,7 +312,7 @@
     This bit of code is used to avoid unregistering network devices
     at inappropriate times.  2.2 and later kernels are fairly picky
     about when this can happen.
-    
+
 ======================================================================*/
 
 static void flush_stale_links(void)
@@ -349,7 +351,7 @@
 
     DEBUG(0, "smc91c92_attach()\n");
     flush_stale_links();
-    
+
     /* Create new ethernet device */
     smc = kmalloc(sizeof(struct smc_private), GFP_KERNEL);
     if (!smc) return NULL;
@@ -375,25 +377,25 @@
 
     /* The SMC91c92-specific entries in the device structure. */
     dev->hard_start_xmit = &smc_start_xmit;
-    dev->get_stats = &smc91c92_get_stats;
+    dev->get_stats = &smc_get_stats;
     dev->set_config = &s9k_config;
     dev->set_multicast_list = &set_rx_mode;
-    dev->do_ioctl = &smc_ioctl;
     ether_setup(dev);
-    dev->open = &smc91c92_open;
-    dev->stop = &smc91c92_close;
+    dev->open = &smc_open;
+    dev->stop = &smc_close;
+    dev->do_ioctl = &smc_ioctl;
 #ifdef HAVE_TX_TIMEOUT
     dev->tx_timeout = smc_tx_timeout;
     dev->watchdog_timeo = TX_TIMEOUT;
 #endif
     dev->priv = link->priv = link->irq.Instance = smc;
-   
+
     smc->mii_if.dev = dev;
-    smc->mii_if.mdio_read = smc_mdio_read;
-    smc->mii_if.mdio_write = smc_mdio_write;
+    smc->mii_if.mdio_read = mdio_read;
+    smc->mii_if.mdio_write = mdio_write;
     smc->mii_if.phy_id_mask = 0x1f;
     smc->mii_if.reg_num_mask = 0x1f;
-    
+
     /* Register with Card Services */
     link->next = dev_list;
     dev_list = link;
@@ -411,7 +413,7 @@
 	smc91c92_detach(link);
 	return NULL;
     }
-    
+
     return link;
 } /* smc91c92_attach */
 
@@ -430,13 +432,13 @@
     dev_link_t **linkp;
 
     DEBUG(0, "smc91c92_detach(0x%p)\n", link);
-    
+
     /* Locate device structure */
     for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
 	if (*linkp == link) break;
     if (*linkp == NULL)
 	return;
-    
+
     del_timer(&link->release);
     if (link->state & DEV_CONFIG) {
 	smc91c92_release((u_long)link);
@@ -445,16 +447,16 @@
 	    return;
 	}
     }
-    
+
     if (link->handle)
 	CardServices(DeregisterClient, link->handle);
-    
+
     /* Unlink device structure, free bits */
     *linkp = link->next;
     if (link->dev)
 	unregister_netdev(&smc->dev);
     kfree(smc);
-    
+
 } /* smc91c92_detach */
 
 /*====================================================================*/
@@ -502,14 +504,14 @@
     mhz_mfc_config() handles socket setup for multifunction (1144
     and 3288) cards.  mhz_setup() gets a card's hardware ethernet
     address.
-    
+
 ======================================================================*/
 
 static int mhz_3288_power(dev_link_t *link)
 {
     struct smc_private *smc = link->priv;
     u_char tmp;
-    
+
     /* Read the ISR twice... */
     readb(smc->base+MEGAHERTZ_ISR);
     udelay(5);
@@ -517,7 +519,7 @@
 
     /* Pause 200ms... */
     mdelay(200);
-    
+
     /* Now read and write the COR... */
     tmp = readb(smc->base + link->conf.ConfigBase + CISREG_COR);
     udelay(5);
@@ -569,7 +571,7 @@
     if (i != CS_SUCCESS)
 	return i;
     dev->base_addr = link->io.BasePort1;
-    
+
     /* Allocate a memory window, for accessing the ISR */
     req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
     req.Base = req.Size = 0;
@@ -583,12 +585,12 @@
     if (smc->manfid == MANFID_MOTOROLA)
 	mem.CardOffset = link->conf.ConfigBase;
     i = CardServices(MapMemPage, link->win, &mem);
-    
+
     if ((i == CS_SUCCESS)
 	&& (smc->manfid == MANFID_MEGAHERTZ)
 	&& (smc->cardid == PRODID_MEGAHERTZ_EM3288))
 	mhz_3288_power(link);
-    
+
     return i;
 }
 
@@ -628,7 +630,7 @@
     buf[12] = '\0';
     if (cvt_ascii_address(dev, buf) == 0)
 	return 0;
-    
+
     return -1;
 }
 
@@ -638,7 +640,7 @@
 
     mot_config() writes directly to the Mariner configuration
     registers because the CIS is just bogus.
-    
+
 ======================================================================*/
 
 static void mot_config(dev_link_t *link)
@@ -647,12 +649,12 @@
     struct net_device *dev = &smc->dev;
     ioaddr_t ioaddr = dev->base_addr;
     ioaddr_t iouart = link->io.BasePort2;
-    
+
     /* Set UART base address and force map with COR bit 1 */
     writeb(iouart & 0xff,        smc->base + MOT_UART + CISREG_IOBASE_0);
     writeb((iouart >> 8) & 0xff, smc->base + MOT_UART + CISREG_IOBASE_1);
     writeb(MOT_NORMAL,           smc->base + MOT_UART + CISREG_COR);
-    
+
     /* Set SMC base address and force map with COR bit 1 */
     writeb(ioaddr & 0xff,        smc->base + MOT_LAN + CISREG_IOBASE_0);
     writeb((ioaddr >> 8) & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_1);
@@ -671,7 +673,7 @@
     u_int addr;
 
     /* Read Ethernet address from Serial EEPROM */
-    
+
     for (i = 0; i < 3; i++) {
 	SMC_SELECT_BANK(2);
 	outw(MOT_EEPROM + i, ioaddr + POINTER);
@@ -691,7 +693,7 @@
 	dev->dev_addr[2*i]   = addr & 0xff;
 	dev->dev_addr[2*i+1] = (addr >> 8) & 0xff;
     }
-    
+
     return 0;
 }
 
@@ -743,7 +745,7 @@
     tuple.Attributes = tuple.TupleOffset = 0;
     tuple.TupleData = buf;
     tuple.TupleDataMax = sizeof(buf);
-    
+
     /* Check for a LAN function extension tuple */
     tuple.DesiredTuple = CISTPL_FUNCE;
     i = first_tuple(handle, &tuple, &parse);
@@ -760,7 +762,7 @@
 	    return 0;
 	}
     }
-    
+
     /* Try the third string in the Version 1 Version/ID tuple. */
     tuple.DesiredTuple = CISTPL_VERS_1;
     if (first_tuple(handle, &tuple, &parse) != CS_SUCCESS)
@@ -780,7 +782,7 @@
     struct net_device *dev = &smc->dev;
     static ioaddr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
     int i, j;
-    
+
     link->conf.Attributes |= CONF_ENABLE_SPKR;
     link->conf.Status = CCSR_AUDIO_ENA;
     link->irq.Attributes =
@@ -789,10 +791,10 @@
     link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
     link->io.NumPorts2 = 8;
     link->io.IOAddrLines = 16;
-    
+
     /* Enable Hard Decode, LAN, Modem */
     link->conf.ConfigIndex = 0x23;
-    
+
     for (i = j = 0; j < 4; j++) {
 	link->io.BasePort2 = com[j];
 	i = CardServices(RequestIO, link->handle, &link->io);
@@ -816,12 +818,12 @@
     tuple_t tuple;
     u_char buf[255];
     int i;
-    
+
     tuple.Attributes = TUPLE_RETURN_COMMON;
     tuple.TupleData = buf;
     tuple.TupleDataMax = sizeof(buf);
     tuple.TupleOffset = 0;
-    
+
     /* Read the station address from tuple 0x90, subtuple 0x04 */
     tuple.DesiredTuple = 0x90;
     i = CardServices(GetFirstTuple, handle, &tuple);
@@ -862,7 +864,7 @@
 
     This verifies that the chip is some SMC91cXX variant, and returns
     the revision code if successful.  Otherwise, it returns -ENODEV.
-    
+
 ======================================================================*/
 
 static int check_sig(dev_link_t *link)
@@ -888,7 +890,7 @@
     else
 	s &= ~CFG_16BIT;
     outb(s, ioaddr + CONFIG);
-    
+
     /* Check Base Address Register to make sure bus width is OK */
     s = inw(ioaddr + BASE_ADDR);
     if ((inw(ioaddr + BANK_SELECT) >> 8 == 0x33) &&
@@ -936,7 +938,7 @@
     ioaddr_t ioaddr;
 
     DEBUG(0, "smc91c92_config(0x%p)\n", link);
-    
+
     tuple.Attributes = tuple.TupleOffset = 0;
     tuple.TupleData = (cisdata_t *)buf;
     tuple.TupleDataMax = sizeof(buf);
@@ -946,14 +948,14 @@
     CS_EXIT_TEST(i, ParseTuple, config_failed);
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
-    
+
     tuple.DesiredTuple = CISTPL_MANFID;
     tuple.Attributes = TUPLE_RETURN_COMMON;
     if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
 	smc->manfid = parse.manfid.manf;
 	smc->cardid = parse.manfid.card;
     }
-    
+
     /* Configure card */
     link->state |= DEV_CONFIG;
 
@@ -969,12 +971,12 @@
 	i = smc_config(link);
     }
     CS_EXIT_TEST(i, RequestIO, config_failed);
-    
+
     i = CardServices(RequestIRQ, link->handle, &link->irq);
     CS_EXIT_TEST(i, RequestIRQ, config_failed);
     i = CardServices(RequestConfiguration, link->handle, &link->conf);
     CS_EXIT_TEST(i, RequestConfiguration, config_failed);
-    
+
     if (smc->manfid == MANFID_MOTOROLA)
 	mot_config(link);
 
@@ -984,7 +986,7 @@
 	dev->if_port = if_port;
     else
 	printk(KERN_NOTICE "smc91c92_cs: invalid if_port requested\n");
-    
+
     if (register_netdev(dev) != 0) {
 	printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n");
 	goto config_undo;
@@ -1004,16 +1006,16 @@
     default: /* get the hw address from EEPROM */
 	i = mot_setup(link); break;
     }
-    
+
     if (i != 0) {
 	printk(KERN_NOTICE "smc91c92_cs: Unable to find hardware address.\n");
-	link->state &= ~DEV_CONFIG_PENDING;
 	goto config_undo;
     }
 
     strcpy(smc->node.dev_name, dev->name);
     link->dev = &smc->node;
-    link->state &= ~DEV_CONFIG_PENDING;
+    smc->duplex = 0;
+    smc->rx_ovrn = 0;
 
     rev = check_sig(link);
     name = "???";
@@ -1055,12 +1057,12 @@
 	printk(" buffer, %s xcvr\n", (smc->cfg & CFG_MII_SELECT) ?
 	       "MII" : if_names[dev->if_port]);
     }
-    
+
     if (smc->cfg & CFG_MII_SELECT) {
 	SMC_SELECT_BANK(3);
 
 	for (i = 0; i < 32; i++) {
-	    j = smc_mdio_read(dev, i, 1);
+	    j = mdio_read(dev, i, 1);
 	    if ((j != 0) && (j != 0xffff)) break;
 	}
 	smc->mii_if.phy_id = (i < 32) ? i : -1;
@@ -1073,13 +1075,15 @@
 	SMC_SELECT_BANK(0);
     }
 
+    link->state &= ~DEV_CONFIG_PENDING;
     return;
-    
+
 config_undo:
     unregister_netdev(dev);
 config_failed:			/* CS_EXIT_TEST() calls jump to here... */
     smc91c92_release((u_long)link);
-    
+    link->state &= ~DEV_CONFIG_PENDING;
+
 } /* smc91c92_config */
 
 /*======================================================================
@@ -1096,14 +1100,14 @@
     struct smc_private *smc = link->priv;
 
     DEBUG(0, "smc91c92_release(0x%p)\n", link);
-    
+
     if (link->open) {
 	DEBUG(1, "smc91c92_cs: release postponed, '%s' still open\n",
 	      link->dev->dev_name);
 	link->state |= DEV_STALE_CONFIG;
 	return;
     }
-    
+
     CardServices(ReleaseConfiguration, link->handle);
     CardServices(ReleaseIO, link->handle, &link->io);
     CardServices(ReleaseIRQ, link->handle, &link->irq);
@@ -1111,7 +1115,7 @@
 	iounmap(smc->base);
 	CardServices(ReleaseWindow, link->win);
     }
-    
+
     link->state &= ~DEV_CONFIG;
 
 } /* smc91c92_release */
@@ -1131,8 +1135,8 @@
     dev_link_t *link = args->client_data;
     struct smc_private *smc = link->priv;
     struct net_device *dev = &smc->dev;
-    int i;   
- 
+    int i;
+
     DEBUG(1, "smc91c92_event(0x%06x)\n", event);
 
     switch (event) {
@@ -1144,7 +1148,7 @@
 	}
 	break;
     case CS_EVENT_CARD_INSERTION:
-	link->state |= DEV_PRESENT;
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
 	smc91c92_config(link);
 	break;
     case CS_EVENT_PM_SUSPEND:
@@ -1206,7 +1210,7 @@
 #define MDIO_DATA_WRITE1	(MDIO_DIR_WRITE | MDIO_DATA_OUT)
 #define MDIO_DATA_READ		0x02
 
-static void smc_mdio_sync(ioaddr_t addr)
+static void mdio_sync(ioaddr_t addr)
 {
     int bits;
     for (bits = 0; bits < 32; bits++) {
@@ -1215,13 +1219,13 @@
     }
 }
 
-static int smc_mdio_read(struct net_device *dev, int phy_id, int loc)
+static int mdio_read(struct net_device *dev, int phy_id, int loc)
 {
     ioaddr_t addr = dev->base_addr + MGMT;
     u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
     int i, retval = 0;
 
-    smc_mdio_sync(addr);
+    mdio_sync(addr);
     for (i = 13; i >= 0; i--) {
 	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
 	outb(dat, addr);
@@ -1235,13 +1239,13 @@
     return (retval>>1) & 0xffff;
 }
 
-static void smc_mdio_write(struct net_device *dev, int phy_id, int loc, int value)
+static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
 {
     ioaddr_t addr = dev->base_addr + MGMT;
     u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
     int i;
 
-    smc_mdio_sync(addr);
+    mdio_sync(addr);
     for (i = 31; i >= 0; i--) {
 	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
 	outb(dat, addr);
@@ -1254,10 +1258,10 @@
 }
 
 /*======================================================================
-  
+
     The driver core code, most of which should be common with a
     non-PCMCIA implementation.
-    
+
 ======================================================================*/
 
 #ifdef PCMCIA_DEBUG
@@ -1277,17 +1281,17 @@
 }
 #endif
 
-static int smc91c92_open(struct net_device *dev)
+static int smc_open(struct net_device *dev)
 {
     struct smc_private *smc = dev->priv;
     dev_link_t *link = &smc->link;
 
 #ifdef PCMCIA_DEBUG
-    DEBUG(0, "%s: smc91c92_open(%p), ID/Window %4.4x.\n",
+    DEBUG(0, "%s: smc_open(%p), ID/Window %4.4x.\n",
 	  dev->name, dev, inw(dev->base_addr + BANK_SELECT));
     if (pc_debug > 1) smc_dump(dev);
 #endif
-    
+
     /* Check that the PCMCIA card is still here. */
     if (!DEV_OK(link))
 	return -ENODEV;
@@ -1302,25 +1306,25 @@
     netif_start_queue(dev);
     smc->saved_skb = 0;
     smc->packets_waiting = 0;
-    
+
     smc_reset(dev);
     smc->media.function = &media_check;
     smc->media.data = (u_long)smc;
     smc->media.expires = jiffies + HZ;
     add_timer(&smc->media);
-    
+
     return 0;
-} /* smc91c92_open */
+} /* smc_open */
 
 /*====================================================================*/
 
-static int smc91c92_close(struct net_device *dev)
+static int smc_close(struct net_device *dev)
 {
     struct smc_private *smc = dev->priv;
     dev_link_t *link = &smc->link;
     ioaddr_t ioaddr = dev->base_addr;
 
-    DEBUG(0, "%s: smc91c92_close(), status %4.4x.\n",
+    DEBUG(0, "%s: smc_close(), status %4.4x.\n",
 	  dev->name, inw(ioaddr + BANK_SELECT));
 
     netif_stop_queue(dev);
@@ -1332,27 +1336,27 @@
     SMC_SELECT_BANK(0);
     mask_bits(0xff00, ioaddr + RCR);
     mask_bits(0xff00, ioaddr + TCR);
-    
+
     /* Put the chip into power-down mode. */
     SMC_SELECT_BANK(1);
     outw(CTL_POWERDOWN, ioaddr + CONTROL );
-    
+
     link->open--;
     del_timer(&smc->media);
     if (link->state & DEV_STALE_CONFIG)
 	mod_timer(&link->release, jiffies + HZ/20);
-    
+
     MOD_DEC_USE_COUNT;
-    
+
     return 0;
-} /* smc91c92_close */
+} /* smc_close */
 
 /*======================================================================
 
    Transfer a packet to the hardware and trigger the packet send.
    This may be called at either from either the Tx queue code
    or the interrupt handler.
-   
+
 ======================================================================*/
 
 static void smc_hardware_send_packet(struct net_device * dev)
@@ -1361,12 +1365,12 @@
     struct sk_buff *skb = smc->saved_skb;
     ioaddr_t ioaddr = dev->base_addr;
     u_char packet_no;
-    
+
     if (!skb) {
 	printk(KERN_ERR "%s: In XMIT with no packet to send.\n", dev->name);
 	return;
     }
-    
+
     /* There should be a packet slot waiting. */
     packet_no = inw(ioaddr + PNR_ARR) >> 8;
     if (packet_no & 0x80) {
@@ -1384,7 +1388,7 @@
     outw(packet_no, ioaddr + PNR_ARR);
     /* point to the beginning of the packet */
     outw(PTR_AUTOINC , ioaddr + POINTER);
-    
+
     /* Send the packet length (+6 for status, length and ctl byte)
        and the status word (set to zeros). */
     {
@@ -1402,15 +1406,15 @@
 	/* The odd last byte, if there is one, goes in the control word. */
 	outw((length & 1) ? 0x2000 | buf[length-1] : 0, ioaddr + DATA_1);
     }
-    
+
     /* Enable the Tx interrupts, both Tx (TxErr) and TxEmpty. */
     outw(((IM_TX_INT|IM_TX_EMPTY_INT)<<8) |
 	 (inw(ioaddr + INTERRUPT) & 0xff00),
 	 ioaddr + INTERRUPT);
-    
+
     /* The chip does the rest of the work. */
     outw(MC_ENQUEUE , ioaddr + MMU_CMD);
-    
+
     smc->saved_skb = NULL;
     dev_kfree_skb_irq(skb);
     dev->trans_start = jiffies;
@@ -1444,9 +1448,9 @@
 
     netif_stop_queue(dev);
 
-    DEBUG(2, "%s: smc91c92_start_xmit(length = %d) called,"
+    DEBUG(2, "%s: smc_start_xmit(length = %d) called,"
 	  " status %4.4x.\n", dev->name, skb->len, inw(ioaddr + 2));
-    
+
     if (smc->saved_skb) {
 	/* THIS SHOULD NEVER HAPPEN. */
 	smc->stats.tx_aborted_errors++;
@@ -1455,9 +1459,9 @@
 	return 1;
     }
     smc->saved_skb = skb;
-    
+
     num_pages = skb->len >> 8;
-    
+
     if (num_pages > 7) {
 	printk(KERN_ERR "%s: Far too big packet error.\n", dev->name);
 	dev_kfree_skb (skb);
@@ -1467,9 +1471,15 @@
     }
     /* A packet is now waiting. */
     smc->packets_waiting++;
-    
+
     SMC_SELECT_BANK(2);	/* Paranoia, we should always be in window 2 */
-    
+
+    /* need MC_RESET to keep the memory consistent. errata? */
+    if (smc->rx_ovrn) {
+	outw(MC_RESET, ioaddr + MMU_CMD);
+	smc->rx_ovrn = 0;
+    }
+
     /* Allocate the memory; send the packet now if we win. */
     outw(MC_ALLOC | num_pages, ioaddr + MMU_CMD);
     for (time_out = MEMORY_WAIT_TIME; time_out >= 0; time_out--) {
@@ -1481,18 +1491,18 @@
 	    return 0;
 	}
     }
-    
+
     /* Otherwise defer until the Tx-space-allocated interrupt. */
     DEBUG(2, "%s: memory allocation deferred.\n", dev->name);
     outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT);
-    
+
     return 0;
 }
 
 /*======================================================================
 
     Handle a Tx anomolous event.  Entered while in Window 2.
-    
+
 ======================================================================*/
 
 static void smc_tx_err(struct net_device * dev)
@@ -1502,13 +1512,13 @@
     int saved_packet = inw(ioaddr + PNR_ARR) & 0xff;
     int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f;
     int tx_status;
-    
+
     /* select this as the packet to read from */
     outw(packet_no, ioaddr + PNR_ARR);
-    
+
     /* read the first word from this packet */
     outw(PTR_AUTOINC | PTR_READ | 0, ioaddr + POINTER);
-    
+
     tx_status = inw(ioaddr + DATA_1);
 
     smc->stats.tx_errors++;
@@ -1518,21 +1528,21 @@
 	smc->stats.tx_aborted_errors++;
 	smc->tx_err++;
     }
-    
+
     if (tx_status & TS_SUCCESS) {
 	printk(KERN_NOTICE "%s: Successful packet caused error "
 	       "interrupt?\n", dev->name);
     }
     /* re-enable transmit */
     SMC_SELECT_BANK(0);
-    outw(inw(ioaddr + TCR) | TCR_ENABLE, ioaddr + TCR);
+    outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR);
     SMC_SELECT_BANK(2);
-    
+
     outw(MC_FREEPKT, ioaddr + MMU_CMD); 	/* Free the packet memory. */
-    
+
     /* one less packet waiting for me */
     smc->packets_waiting--;
-    
+
     outw(saved_packet, ioaddr + PNR_ARR);
     return;
 }
@@ -1544,7 +1554,7 @@
     struct smc_private *smc = dev->priv;
     ioaddr_t ioaddr = dev->base_addr;
     u_short card_stats, ephs;
-    
+
     SMC_SELECT_BANK(0);
     ephs = inw(ioaddr + EPH);
     DEBUG(2, "%s: Ethernet protocol handler interrupt, status"
@@ -1561,7 +1571,7 @@
     card_stats >>= 4;			/* excess deferred */
 #endif
     /* If we had a transmit error we must re-enable the transmitter. */
-    outw(inw(ioaddr + TCR) | TCR_ENABLE, ioaddr + TCR);
+    outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR);
 
     /* Clear a link error interrupt. */
     SMC_SELECT_BANK(1);
@@ -1572,7 +1582,7 @@
 }
 
 /*====================================================================*/
-    
+
 static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
     struct smc_private *smc = dev_id;
@@ -1584,10 +1594,10 @@
     if (!netif_device_present(dev))
 	return;
     ioaddr = dev->base_addr;
-    
+
     DEBUG(3, "%s: SMC91c92 interrupt %d at %#x.\n", dev->name,
 	  irq, ioaddr);
-    
+
     smc->watchdog = 0;
     saved_bank = inw(ioaddr + BANK_SELECT);
     if ((saved_bank & 0xff00) != 0x3300) {
@@ -1597,13 +1607,13 @@
 	      "/ejected device.\n", dev->name, irq);
 	goto irq_done;
     }
-    
+
     SMC_SELECT_BANK(2);
     saved_pointer = inw(ioaddr + POINTER);
     mask = inw(ioaddr + INTERRUPT) >> 8;
     /* clear all interrupts */
     outw(0, ioaddr + INTERRUPT);
-    
+
     do { /* read the status flag, and mask it */
 	status = inw(ioaddr + INTERRUPT) & 0xff;
 	DEBUG(3, "%s: Status is %#2.2x (mask %#2.2x).\n", dev->name,
@@ -1629,18 +1639,20 @@
 	if (status & IM_ALLOC_INT) {
 	    /* Clear this interrupt so it doesn't happen again */
 	    mask &= ~IM_ALLOC_INT;
-	    
+	
 	    smc_hardware_send_packet(dev);
-	    
+	
 	    /* enable xmit interrupts based on this */
 	    mask |= (IM_TX_EMPTY_INT | IM_TX_INT);
-	    
+	
 	    /* and let the card send more packets to me */
 	    netif_wake_queue(dev);
 	}
 	if (status & IM_RX_OVRN_INT) {
 	    smc->stats.rx_errors++;
-	    smc->stats.rx_fifo_errors++;		
+	    smc->stats.rx_fifo_errors++;
+	    if (smc->duplex)
+		smc->rx_ovrn = 1; /* need MC_RESET outside smc_interrupt */
 	    outw(IM_RX_OVRN_INT, ioaddr + INTERRUPT);
 	}
 	if (status & IM_EPH_INT)
@@ -1649,7 +1661,7 @@
 
     DEBUG(3, "  Restoring saved registers mask %2.2x bank %4.4x"
 	  " pointer %4.4x.\n", mask, saved_bank, saved_pointer);
-    
+
     /* restore state register */
     outw((mask<<8), ioaddr + INTERRUPT);
     outw(saved_pointer, ioaddr + POINTER);
@@ -1658,7 +1670,7 @@
     DEBUG(3, "%s: Exiting interrupt IRQ%d.\n", dev->name, irq);
 
 irq_done:
-    
+
     if ((smc->manfid == MANFID_OSITECH) &&
 	(smc->cardid != PRODID_OSITECH_SEVEN)) {
 	/* Retrigger interrupt if needed */
@@ -1691,15 +1703,15 @@
     int rx_status;
     int packet_length;	/* Caution: not frame length, rather words
 			   to transfer from the chip. */
-    
+
     /* Assertion: we are in Window 2. */
-    
+
     if (inw(ioaddr + FIFO_PORTS) & FP_RXEMPTY) {
 	printk(KERN_ERR "%s: smc_rx() with nothing on Rx FIFO.\n",
 	       dev->name);
 	return;
     }
-    
+
     /*  Reset the read pointer, and read the status and packet length. */
     outw(PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER);
     rx_status = inw(ioaddr + DATA_1);
@@ -1707,7 +1719,7 @@
 
     DEBUG(2, "%s: Receive status %4.4x length %d.\n",
 	  dev->name, rx_status, packet_length);
-    
+
     if (!(rx_status & RS_ERRORS)) {		
 	/* do stuff to make a new packet */
 	struct sk_buff *skb;
@@ -1725,7 +1737,7 @@
 	packet_length -= (rx_status & RS_ODDFRAME ? 5 : 6);
 	skb_reserve(skb, 2);
 	insw(ioaddr+DATA_1, skb_put(skb, packet_length),
-		(packet_length+1)>>1);
+	     (packet_length+1)>>1);
 	skb->protocol = eth_type_trans(skb, dev);
 	
 	skb->dev = dev;
@@ -1746,31 +1758,30 @@
     }
     /* Let the MMU free the memory of this packet. */
     outw(MC_RELEASE, ioaddr + MMU_CMD);
-    
+
     return;
 }
 
 /*====================================================================*/
 
-static struct net_device_stats *smc91c92_get_stats(struct net_device *dev)
+static struct net_device_stats *smc_get_stats(struct net_device *dev)
 {
     struct smc_private *smc = (struct smc_private *)dev->priv;
     /* Nothing to update - the 91c92 is a pretty primative chip. */
     return &smc->stats;
 }
 
-
 /*======================================================================
-  
+
     Calculate values for the hardware multicast filter hash table.
-    
+
 ======================================================================*/
 
 static void fill_multicast_tbl(int count, struct dev_mc_list *addrs,
 			       u_char *multicast_table)
 {
     struct dev_mc_list	*mc_addr;
-    
+
     for (mc_addr = addrs;  mc_addr && --count > 0;  mc_addr = mc_addr->next) {
 	u_int position = ether_crc(6, mc_addr->dmi_addr);
 #ifndef final_version		/* Verify multicast address. */
@@ -1782,14 +1793,14 @@
 }
 
 /*======================================================================
-  
+
     Set the receive mode.
-    
+
     This routine is used by both the protocol level to notify us of
     promiscuous/multicast mode changes, and by the open/reset code to
     initialize the Rx registers.  We always set the multicast list and
     leave the receiver running.
-    
+
 ======================================================================*/
 
 static void set_rx_mode(struct net_device *dev)
@@ -1799,7 +1810,7 @@
     u_int multicast_table[ 2 ] = { 0, };
     unsigned long flags;
     u_short rx_cfg_setting;
-    
+
     if (dev->flags & IFF_PROMISC) {
 	printk(KERN_NOTICE "%s: setting Rx mode to promiscuous.\n", dev->name);
 	rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti;
@@ -1812,7 +1823,7 @@
 	}
 	rx_cfg_setting = RxStripCRC | RxEnable;
     }
-    
+
     /* Load MC table and Rx setting into the chip without interrupts. */
     spin_lock_irqsave(&smc->lock, flags);
     SMC_SELECT_BANK(3);
@@ -1822,14 +1833,14 @@
     outw(rx_cfg_setting, ioaddr + RCR);
     SMC_SELECT_BANK(2);
     spin_unlock_irqrestore(&smc->lock, flags);
- 
+
     return;
 }
 
 /*======================================================================
 
     Senses when a card's config changes. Here, it's coax or TP.
- 
+
 ======================================================================*/
 
 static int s9k_config(struct net_device *dev, struct ifmap *map)
@@ -1889,18 +1900,18 @@
     int i;
 
     DEBUG(0, "%s: smc91c92 reset called.\n", dev->name);
-    
+
     /* The first interaction must be a write to bring the chip out
        of sleep mode. */
     SMC_SELECT_BANK(0);
     /* Reset the chip. */
     outw(RCR_SOFTRESET, ioaddr + RCR);
     udelay(10);
-    
+
     /* Clear the transmit and receive configuration registers. */
     outw(RCR_CLEAR, ioaddr + RCR);
     outw(TCR_CLEAR, ioaddr + TCR);
-    
+
     /* Set the Window 1 control, configuration and station addr registers.
        No point in writing the I/O base register ;-> */
     SMC_SELECT_BANK(1);
@@ -1914,32 +1925,35 @@
 	outw((dev->if_port == 2 ? OSI_AUI_PWR : 0) |
 	     (inw(ioaddr-0x10+OSITECH_AUI_PWR) & 0xff00),
 	     ioaddr - 0x10 + OSITECH_AUI_PWR);
-    
+
     /* Fill in the physical address.  The databook is wrong about the order! */
     for (i = 0; i < 6; i += 2)
 	outw((dev->dev_addr[i+1]<<8)+dev->dev_addr[i],
 	     ioaddr + ADDR0 + i);
-    
+
     /* Reset the MMU */
     SMC_SELECT_BANK(2);
     outw(MC_RESET, ioaddr + MMU_CMD);
     outw(0, ioaddr + INTERRUPT);
-    
+
     /* Re-enable the chip. */
     SMC_SELECT_BANK(0);
     outw(((smc->cfg & CFG_MII_SELECT) ? 0 : TCR_MONCSN) |
-	 TCR_ENABLE | TCR_PAD_EN, ioaddr + TCR);
+	 TCR_ENABLE | TCR_PAD_EN | smc->duplex, ioaddr + TCR);
     set_rx_mode(dev);
 
     if (smc->cfg & CFG_MII_SELECT) {
 	SMC_SELECT_BANK(3);
 
 	/* Reset MII */
-	smc_mdio_write(dev, smc->mii_if.phy_id, 0, 0x8000);
+	mdio_write(dev, smc->mii_if.phy_id, 0, 0x8000);
+
+	/* Advertise 100F, 100H, 10F, 10H */
+	mdio_write(dev, smc->mii_if.phy_id, 4, 0x01e1);
 
 	/* Restart MII autonegotiation */
-	smc_mdio_write(dev, smc->mii_if.phy_id, 0, 0x0000);
-	smc_mdio_write(dev, smc->mii_if.phy_id, 0, 0x1200);
+	mdio_write(dev, smc->mii_if.phy_id, 0, 0x0000);
+	mdio_write(dev, smc->mii_if.phy_id, 0, 0x1200);
     }
 
     /* Enable interrupts. */
@@ -1951,7 +1965,7 @@
 /*======================================================================
 
     Media selection timer routine
-    
+
 ======================================================================*/
 
 static void media_check(u_long arg)
@@ -1968,12 +1982,18 @@
 	goto reschedule;
 
     SMC_SELECT_BANK(2);
+
+    /* need MC_RESET to keep the memory consistent. errata? */
+    if (smc->rx_ovrn) {
+	outw(MC_RESET, ioaddr + MMU_CMD);
+	smc->rx_ovrn = 0;
+    }
     i = inw(ioaddr + INTERRUPT);
     SMC_SELECT_BANK(0);
     media = inw(ioaddr + EPH) & EPH_LINK_OK;
     SMC_SELECT_BANK(1);
     media |= (inw(ioaddr + CONFIG) & CFG_AUI_SELECT) ? 2 : 1;
-    
+
     /* Check for pending interrupt with watchdog flag set: with
        this, we can limp along even if the interrupt is blocked */
     if (smc->watchdog++ && ((i>>8) & i)) {
@@ -1995,7 +2015,7 @@
 	    goto reschedule;
 
 	SMC_SELECT_BANK(3);
-	link = smc_mdio_read(dev, smc->mii_if.phy_id, 1);
+	link = mdio_read(dev, smc->mii_if.phy_id, 1);
 	if (!link || (link == 0xffff)) {
   	    printk(KERN_INFO "%s: MII is missing!\n", dev->name);
 	    smc->mii_if.phy_id = -1;
@@ -2004,21 +2024,23 @@
 
 	link &= 0x0004;
 	if (link != smc->link_status) {
-	    u_short p = smc_mdio_read(dev, smc->mii_if.phy_id, 5);
+	    u_short p = mdio_read(dev, smc->mii_if.phy_id, 5);
 	    printk(KERN_INFO "%s: %s link beat\n", dev->name,
 		(link) ? "found" : "lost");
+	    smc->duplex = (((p & 0x0100) || ((p & 0x1c0) == 0x40))
+			   ? TCR_FDUPLX : 0);
 	    if (link) {
 	        printk(KERN_INFO "%s: autonegotiation complete: "
-	   	    "%sbaseT-%cD selected\n", dev->name,
-		    ((p & 0x0180) ? "100" : "10"),
-		    (((p & 0x0100) || ((p & 0x1c0) == 0x40)) ? 'F' : 'H'));
+		       "%sbaseT-%cD selected\n", dev->name,
+		       ((p & 0x0180) ? "100" : "10"),
+		       (smc->duplex ? 'F' : 'H'));
 	    }
+	    SMC_SELECT_BANK(0);
+	    outw(inw(ioaddr + TCR) | smc->duplex, ioaddr + TCR);
 	    smc->link_status = link;
 	}
-    }
-
-    if (smc->cfg & CFG_MII_SELECT)
 	goto reschedule;
+    }
 
     /* Ignore collisions unless we've had no rx's recently */
     if (jiffies - dev->last_rx > HZ) {
@@ -2053,7 +2075,7 @@
 	}
 	smc->media_status = media;
     }
-    
+
 reschedule:
     smc->media.expires = jiffies + HZ;
     add_timer(&smc->media);
@@ -2167,7 +2189,7 @@
 	    return -EFAULT;
 	spin_lock_irq(&smc->lock);
 	if (smc->cfg & CFG_MII_SELECT)
-	    ret = mii_ethtool_sset(&smc->mii_if, &ecmd);    
+	    ret = mii_ethtool_sset(&smc->mii_if, &ecmd);
 	else
 	    ret = smc_netdev_set_ecmd(dev, &ecmd);
 	spin_unlock_irq(&smc->lock);
@@ -2194,7 +2216,7 @@
 	    return -EFAULT;
 	return 0;
     }
-    
+
     /* set message-level */
     case ETHTOOL_SMSGLVL: {
 	struct ethtool_value edata;
@@ -2211,7 +2233,7 @@
 	else
 	    return -EOPNOTSUPP;
     }
-    
+
     default:
 	break;
     }
@@ -2233,7 +2255,7 @@
     case SIOCETHTOOL:
 	rc = smc_ethtool_ioctl(dev, (void *) rq->ifr_data);
 	break;
-    
+
     default:
 	spin_lock_irq(&smc->lock);
 	rc = generic_mii_ioctl(&smc->mii_if, mii, cmd, NULL);
@@ -2255,7 +2277,7 @@
     if (serv.Revision != CS_RELEASE_CODE) {
 	printk(KERN_ERR
 	       "smc91c92_cs: Card Services release does not match!\n");
-	return -1;
+	return -EINVAL;
     }
     register_pccard_driver(&dev_info, &smc91c92_attach, &smc91c92_detach);
     return 0;
@@ -2271,4 +2293,3 @@
 
 module_init(init_smc91c92_cs);
 module_exit(exit_smc91c92_cs);
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/pcmcia/wavelan_cs.c linux-2.4.21/drivers/net/pcmcia/wavelan_cs.c
--- linux-2.4.20/drivers/net/pcmcia/wavelan_cs.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/pcmcia/wavelan_cs.c	2002-12-18 18:58:09.000000000 +0000
@@ -707,7 +707,7 @@
   
   while(wavepoint!=NULL)
     {
-      if(wavepoint->last_seen < jiffies-CELL_TIMEOUT)
+      if(time_after(jiffies, wavepoint->last_seen + CELL_TIMEOUT))
 	{
 #ifdef WAVELAN_ROAMING_DEBUG
 	  printk(KERN_DEBUG "WaveLAN: Bye bye %.4X\n",wavepoint->nwid);
@@ -1890,7 +1890,8 @@
 }
 #endif	/* HISTOGRAM */
 
-static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+static inline int
+wl_netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
 {
 	u32 ethcmd;
 		
@@ -1933,7 +1934,7 @@
 #endif
 
   if (cmd == SIOCETHTOOL)
-    return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+    return wl_netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 
   /* Disable interrupts & save flags */
   wv_splhi(lp, &flags);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/pcmcia/xircom_cb.c linux-2.4.21/drivers/net/pcmcia/xircom_cb.c
--- linux-2.4.20/drivers/net/pcmcia/xircom_cb.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/pcmcia/xircom_cb.c	2002-12-18 18:58:05.000000000 +0000
@@ -285,32 +285,30 @@
 	private->lock = SPIN_LOCK_UNLOCKED;
 	dev->irq = pdev->irq;
 	dev->base_addr = private->io_port;
-	
-	
+
 	initialize_card(private);
 	read_mac_address(private);
 	setup_descriptors(private);
-	
+
 	dev->open = &xircom_open;
 	dev->hard_start_xmit = &xircom_start_xmit;
 	dev->stop = &xircom_close;
 	dev->get_stats = &xircom_get_stats;
 	dev->priv = private;
 	dev->do_ioctl = &private_ioctl;
-	pdev->driver_data = dev;
+	pci_set_drvdata(pdev, dev);
 
-	
 	/* start the transmitter to get a heartbeat */
 	/* TODO: send 2 dummy packets here */
 	tranceiver_voodoo(private);
-	
+
 	spin_lock_irqsave(&private->lock,flags);
 	  activate_transmitter(private);
 	  activate_receiver(private);
 	spin_unlock_irqrestore(&private->lock,flags);
-	
+
 	trigger_receive(private);
-	
+
 	leave("xircom_probe");
 	return 0;
 }
@@ -324,7 +322,7 @@
  */
 static void __devexit xircom_remove(struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata(pdev);
 	struct xircom_private *card;
 	enter("xircom_remove");
 	if (dev!=NULL) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/r8169.c linux-2.4.21/drivers/net/r8169.c
--- linux-2.4.20/drivers/net/r8169.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/net/r8169.c	2002-12-18 18:58:04.000000000 +0000
@@ -0,0 +1,1122 @@
+/*
+=========================================================================
+ r8169.c: A RealTek RTL-8169 Gigabit Ethernet driver for Linux kernel 2.4.x.
+ --------------------------------------------------------------------
+
+ History:
+ Feb  4 2002	- created initially by ShuChen <shuchen@realtek.com.tw>.
+ May 20 2002	- Add link status force-mode and TBI mode support.
+=========================================================================
+  1. The media can be forced in 5 modes.
+	 Command: 'insmod r8169 media = SET_MEDIA'
+	 Ex:	  'insmod r8169 media = 0x04' will force PHY to operate in 100Mpbs Half-duplex.
+	
+	 SET_MEDIA can be:
+ 		_10_Half	= 0x01
+ 		_10_Full	= 0x02
+ 		_100_Half	= 0x04
+ 		_100_Full	= 0x08
+ 		_1000_Full	= 0x10
+  
+  2. Support TBI mode.
+=========================================================================
+VERSION 1.1	<2002/10/4>
+
+	The bit4:0 of MII register 4 is called "selector field", and have to be
+	00001b to indicate support of IEEE std 802.3 during NWay process of
+	exchanging Link Code Word (FLP). 
+
+VERSION 1.2	<2002/11/30>
+
+	- Large style cleanup
+	- Use ether_crc in stock kernel (linux/crc32.h)
+	- Copy mc_filter setup code from 8139cp
+	  (includes an optimization, and avoids set_bit use)
+
+*/
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/crc32.h>
+
+#define RTL8169_VERSION "1.2"
+#define MODULENAME "r8169"
+#define RTL8169_DRIVER_NAME   MODULENAME " Gigabit Ethernet driver " RTL8169_VERSION
+#define PFX MODULENAME ": "
+
+#ifdef RTL8169_DEBUG
+#define assert(expr) \
+        if(!(expr)) {					\
+	        printk( "Assertion failed! %s,%s,%s,line=%d\n",	\
+        	#expr,__FILE__,__FUNCTION__,__LINE__);		\
+        }
+#else
+#define assert(expr) do {} while (0)
+#endif
+
+/* media options */
+#define MAX_UNITS 8
+static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 20;
+
+/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
+   The RTL chips use a 64 element hash table based on the Ethernet CRC.  */
+static int multicast_filter_limit = 32;
+
+/* MAC address length*/
+#define MAC_ADDR_LEN	6
+
+/* max supported gigabit ethernet frame size -- must be at least (dev->mtu+14+4).*/
+#define MAX_ETH_FRAME_SIZE	1536
+
+#define TX_FIFO_THRESH 256	/* In bytes */
+
+#define RX_FIFO_THRESH	7	/* 7 means NO threshold, Rx buffer level before first PCI xfer.  */
+#define RX_DMA_BURST	6	/* Maximum PCI burst, '6' is 1024 */
+#define TX_DMA_BURST	6	/* Maximum PCI burst, '6' is 1024 */
+#define EarlyTxThld 	0x3F	/* 0x3F means NO early transmit */
+#define RxPacketMaxSize	0x0800	/* Maximum size supported is 16K-1 */
+#define InterFrameGap	0x03	/* 3 means InterFrameGap = the shortest one */
+
+#define NUM_TX_DESC	64	/* Number of Tx descriptor registers */
+#define NUM_RX_DESC	64	/* Number of Rx descriptor registers */
+#define RX_BUF_SIZE	1536	/* Rx Buffer size */
+
+#define RTL_MIN_IO_SIZE 0x80
+#define TX_TIMEOUT  (6*HZ)
+
+/* write/read MMIO register */
+#define RTL_W8(reg, val8)	writeb ((val8), ioaddr + (reg))
+#define RTL_W16(reg, val16)	writew ((val16), ioaddr + (reg))
+#define RTL_W32(reg, val32)	writel ((val32), ioaddr + (reg))
+#define RTL_R8(reg)		readb (ioaddr + (reg))
+#define RTL_R16(reg)		readw (ioaddr + (reg))
+#define RTL_R32(reg)		((unsigned long) readl (ioaddr + (reg)))
+
+static struct {
+	const char *name;
+} board_info[] __devinitdata = {
+	{
+"RealTek RTL8169 Gigabit Ethernet"},};
+
+static struct pci_device_id rtl8169_pci_tbl[] __devinitdata = {
+	{0x10ec, 0x8169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0,},
+};
+
+MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl);
+
+enum RTL8169_registers {
+	MAC0 = 0,		/* Ethernet hardware address. */
+	MAR0 = 8,		/* Multicast filter. */
+	TxDescStartAddr = 0x20,
+	TxHDescStartAddr = 0x28,
+	FLASH = 0x30,
+	ERSR = 0x36,
+	ChipCmd = 0x37,
+	TxPoll = 0x38,
+	IntrMask = 0x3C,
+	IntrStatus = 0x3E,
+	TxConfig = 0x40,
+	RxConfig = 0x44,
+	RxMissed = 0x4C,
+	Cfg9346 = 0x50,
+	Config0 = 0x51,
+	Config1 = 0x52,
+	Config2 = 0x53,
+	Config3 = 0x54,
+	Config4 = 0x55,
+	Config5 = 0x56,
+	MultiIntr = 0x5C,
+	PHYAR = 0x60,
+	TBICSR = 0x64,
+	TBI_ANAR = 0x68,
+	TBI_LPAR = 0x6A,
+	PHYstatus = 0x6C,
+	RxMaxSize = 0xDA,
+	CPlusCmd = 0xE0,
+	RxDescStartAddr = 0xE4,
+	EarlyTxThres = 0xEC,
+	FuncEvent = 0xF0,
+	FuncEventMask = 0xF4,
+	FuncPresetState = 0xF8,
+	FuncForceEvent = 0xFC,
+};
+
+enum RTL8169_register_content {
+	/*InterruptStatusBits */
+	SYSErr = 0x8000,
+	PCSTimeout = 0x4000,
+	SWInt = 0x0100,
+	TxDescUnavail = 0x80,
+	RxFIFOOver = 0x40,
+	RxUnderrun = 0x20,
+	RxOverflow = 0x10,
+	TxErr = 0x08,
+	TxOK = 0x04,
+	RxErr = 0x02,
+	RxOK = 0x01,
+
+	/*RxStatusDesc */
+	RxRES = 0x00200000,
+	RxCRC = 0x00080000,
+	RxRUNT = 0x00100000,
+	RxRWT = 0x00400000,
+
+	/*ChipCmdBits */
+	CmdReset = 0x10,
+	CmdRxEnb = 0x08,
+	CmdTxEnb = 0x04,
+	RxBufEmpty = 0x01,
+
+	/*Cfg9346Bits */
+	Cfg9346_Lock = 0x00,
+	Cfg9346_Unlock = 0xC0,
+
+	/*rx_mode_bits */
+	AcceptErr = 0x20,
+	AcceptRunt = 0x10,
+	AcceptBroadcast = 0x08,
+	AcceptMulticast = 0x04,
+	AcceptMyPhys = 0x02,
+	AcceptAllPhys = 0x01,
+
+	/*RxConfigBits */
+	RxCfgFIFOShift = 13,
+	RxCfgDMAShift = 8,
+
+	/*TxConfigBits */
+	TxInterFrameGapShift = 24,
+	TxDMAShift = 8,		/* DMA burst value (0-7) is shift this many bits */
+
+	/*rtl8169_PHYstatus */
+	TBI_Enable = 0x80,
+	TxFlowCtrl = 0x40,
+	RxFlowCtrl = 0x20,
+	_1000bpsF = 0x10,
+	_100bps = 0x08,
+	_10bps = 0x04,
+	LinkStatus = 0x02,
+	FullDup = 0x01,
+
+	/*GIGABIT_PHY_registers */
+	PHY_CTRL_REG = 0,
+	PHY_STAT_REG = 1,
+	PHY_AUTO_NEGO_REG = 4,
+	PHY_1000_CTRL_REG = 9,
+
+	/*GIGABIT_PHY_REG_BIT */
+	PHY_Restart_Auto_Nego = 0x0200,
+	PHY_Enable_Auto_Nego = 0x1000,
+
+	//PHY_STAT_REG = 1;
+	PHY_Auto_Neco_Comp = 0x0020,
+
+	//PHY_AUTO_NEGO_REG = 4;
+	PHY_Cap_10_Half = 0x0020,
+	PHY_Cap_10_Full = 0x0040,
+	PHY_Cap_100_Half = 0x0080,
+	PHY_Cap_100_Full = 0x0100,
+
+	//PHY_1000_CTRL_REG = 9;
+	PHY_Cap_1000_Full = 0x0200,
+
+	PHY_Cap_Null = 0x0,
+
+	/*_MediaType*/
+	_10_Half = 0x01,
+	_10_Full = 0x02,
+	_100_Half = 0x04,
+	_100_Full = 0x08,
+	_1000_Full = 0x10,
+
+	/*_TBICSRBit*/
+	TBILinkOK = 0x02000000,
+};
+
+const static struct {
+	const char *name;
+	u8 version;		/* depend on RTL8169 docs */
+	u32 RxConfigMask;	/* should clear the bits supported by this chip */
+} rtl_chip_info[] = {
+	{
+"RTL-8169", 0x00, 0xff7e1880,},};
+
+enum _DescStatusBit {
+	OWNbit = 0x80000000,
+	EORbit = 0x40000000,
+	FSbit = 0x20000000,
+	LSbit = 0x10000000,
+};
+
+struct TxDesc {
+	u32 status;
+	u32 vlan_tag;
+	u32 buf_addr;
+	u32 buf_Haddr;
+};
+
+struct RxDesc {
+	u32 status;
+	u32 vlan_tag;
+	u32 buf_addr;
+	u32 buf_Haddr;
+};
+
+struct rtl8169_private {
+	void *mmio_addr;	/* memory map physical address */
+	struct pci_dev *pci_dev;	/* Index of PCI device  */
+	struct net_device_stats stats;	/* statistics of net device */
+	spinlock_t lock;	/* spin lock flag */
+	int chipset;
+	unsigned long cur_rx;	/* Index into the Rx descriptor buffer of next Rx pkt. */
+	unsigned long cur_tx;	/* Index into the Tx descriptor buffer of next Rx pkt. */
+	unsigned long dirty_tx;
+	unsigned char *TxDescArrays;	/* Index of Tx Descriptor buffer */
+	unsigned char *RxDescArrays;	/* Index of Rx Descriptor buffer */
+	struct TxDesc *TxDescArray;	/* Index of 256-alignment Tx Descriptor buffer */
+	struct RxDesc *RxDescArray;	/* Index of 256-alignment Rx Descriptor buffer */
+	unsigned char *RxBufferRings;	/* Index of Rx Buffer  */
+	unsigned char *RxBufferRing[NUM_RX_DESC];	/* Index of Rx Buffer array */
+	struct sk_buff *Tx_skbuff[NUM_TX_DESC];	/* Index of Transmit data buffer */
+};
+
+MODULE_AUTHOR("Realtek");
+MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");
+MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "i");
+
+static int rtl8169_open(struct net_device *dev);
+static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void rtl8169_interrupt(int irq, void *dev_instance,
+			      struct pt_regs *regs);
+static void rtl8169_init_ring(struct net_device *dev);
+static void rtl8169_hw_start(struct net_device *dev);
+static int rtl8169_close(struct net_device *dev);
+static void rtl8169_set_rx_mode(struct net_device *dev);
+static void rtl8169_tx_timeout(struct net_device *dev);
+static struct net_device_stats *rtl8169_get_stats(struct net_device *netdev);
+
+static const u16 rtl8169_intr_mask =
+    SYSErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK |
+    RxErr | RxOK;
+static const unsigned int rtl8169_rx_config =
+    (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
+
+void
+mdio_write(void *ioaddr, int RegAddr, int value)
+{
+	int i;
+
+	RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value);
+	udelay(1000);
+
+	for (i = 2000; i > 0; i--) {
+		// Check if the RTL8169 has completed writing to the specified MII register
+		if (!(RTL_R32(PHYAR) & 0x80000000)) {
+			break;
+		} else {
+			udelay(100);
+		}
+	}
+}
+
+int
+mdio_read(void *ioaddr, int RegAddr)
+{
+	int i, value = -1;
+
+	RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16);
+	udelay(1000);
+
+	for (i = 2000; i > 0; i--) {
+		// Check if the RTL8169 has completed retrieving data from the specified MII register
+		if (RTL_R32(PHYAR) & 0x80000000) {
+			value = (int) (RTL_R32(PHYAR) & 0xFFFF);
+			break;
+		} else {
+			udelay(100);
+		}
+	}
+	return value;
+}
+
+static int __devinit
+rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
+		   void **ioaddr_out)
+{
+	void *ioaddr = NULL;
+	struct net_device *dev;
+	struct rtl8169_private *tp;
+	int rc, i;
+	unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
+	u32 tmp;
+
+	assert(pdev != NULL);
+	assert(ioaddr_out != NULL);
+
+	*ioaddr_out = NULL;
+	*dev_out = NULL;
+
+	// dev zeroed in init_etherdev 
+	dev = init_etherdev(NULL, sizeof (*tp));
+	if (dev == NULL) {
+		printk(KERN_ERR PFX "unable to alloc new ethernet\n");
+		return -ENOMEM;
+	}
+
+	SET_MODULE_OWNER(dev);
+	tp = dev->priv;
+
+	// enable device (incl. PCI PM wakeup and hotplug setup)
+	rc = pci_enable_device(pdev);
+	if (rc)
+		goto err_out;
+
+	mmio_start = pci_resource_start(pdev, 1);
+	mmio_end = pci_resource_end(pdev, 1);
+	mmio_flags = pci_resource_flags(pdev, 1);
+	mmio_len = pci_resource_len(pdev, 1);
+
+	// make sure PCI base addr 1 is MMIO
+	if (!(mmio_flags & IORESOURCE_MEM)) {
+		printk(KERN_ERR PFX
+		       "region #1 not an MMIO resource, aborting\n");
+		rc = -ENODEV;
+		goto err_out;
+	}
+	// check for weird/broken PCI region reporting
+	if (mmio_len < RTL_MIN_IO_SIZE) {
+		printk(KERN_ERR PFX "Invalid PCI region size(s), aborting\n");
+		rc = -ENODEV;
+		goto err_out;
+	}
+
+	rc = pci_request_regions(pdev, dev->name);
+	if (rc)
+		goto err_out;
+
+	// enable PCI bus-mastering
+	pci_set_master(pdev);
+
+	// ioremap MMIO region 
+	ioaddr = ioremap(mmio_start, mmio_len);
+	if (ioaddr == NULL) {
+		printk(KERN_ERR PFX "cannot remap MMIO, aborting\n");
+		rc = -EIO;
+		goto err_out_free_res;
+	}
+
+	// Soft reset the chip. 
+	RTL_W8(ChipCmd, CmdReset);
+
+	// Check that the chip has finished the reset.
+	for (i = 1000; i > 0; i--)
+		if ((RTL_R8(ChipCmd) & CmdReset) == 0)
+			break;
+		else
+			udelay(10);
+
+	// identify chip attached to board
+	tmp = RTL_R32(TxConfig);
+	tmp = ((tmp & 0x7c000000) + ((tmp & 0x00800000) << 2)) >> 24;
+
+	for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--)
+		if (tmp == rtl_chip_info[i].version) {
+			tp->chipset = i;
+			goto match;
+		}
+	//if unknown chip, assume array element #0, original RTL-8169 in this case
+	printk(KERN_DEBUG PFX
+	       "PCI device %s: unknown chip version, assuming RTL-8169\n",
+	       pdev->slot_name);
+	printk(KERN_DEBUG PFX "PCI device %s: TxConfig = 0x%lx\n",
+	       pdev->slot_name, (unsigned long) RTL_R32(TxConfig));
+	tp->chipset = 0;
+
+match:
+	*ioaddr_out = ioaddr;
+	*dev_out = dev;
+	return 0;
+
+err_out_free_res:
+	pci_release_regions(pdev);
+
+err_out:
+	unregister_netdev(dev);
+	kfree(dev);
+	return rc;
+}
+
+static int __devinit
+rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct net_device *dev = NULL;
+	struct rtl8169_private *tp = NULL;
+	void *ioaddr = NULL;
+	static int board_idx = -1;
+	static int printed_version = 0;
+	int i;
+	int option = -1, Cap10_100 = 0, Cap1000 = 0;
+
+	assert(pdev != NULL);
+	assert(ent != NULL);
+
+	board_idx++;
+
+	if (!printed_version) {
+		printk(KERN_INFO RTL8169_DRIVER_NAME " loaded\n");
+		printed_version = 1;
+	}
+
+	i = rtl8169_init_board(pdev, &dev, &ioaddr);
+	if (i < 0) {
+		return i;
+	}
+
+	tp = dev->priv;
+	assert(ioaddr != NULL);
+	assert(dev != NULL);
+	assert(tp != NULL);
+
+	// Get MAC address //
+	for (i = 0; i < MAC_ADDR_LEN; i++) {
+		dev->dev_addr[i] = RTL_R8(MAC0 + i);
+	}
+
+	dev->open = rtl8169_open;
+	dev->hard_start_xmit = rtl8169_start_xmit;
+	dev->get_stats = rtl8169_get_stats;
+	dev->stop = rtl8169_close;
+	dev->tx_timeout = rtl8169_tx_timeout;
+	dev->set_multicast_list = rtl8169_set_rx_mode;
+	dev->watchdog_timeo = TX_TIMEOUT;
+	dev->irq = pdev->irq;
+	dev->base_addr = (unsigned long) ioaddr;
+//      dev->do_ioctl           = mii_ioctl;
+
+	tp = dev->priv;		// private data //
+	tp->pci_dev = pdev;
+	tp->mmio_addr = ioaddr;
+
+	printk(KERN_DEBUG "%s: Identified chip type is '%s'.\n", dev->name,
+	       rtl_chip_info[tp->chipset].name);
+
+	spin_lock_init(&tp->lock);
+
+	pci_set_drvdata(pdev, dev);
+
+	printk(KERN_INFO "%s: %s at 0x%lx, "
+	       "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
+	       "IRQ %d\n",
+	       dev->name,
+	       board_info[ent->driver_data].name,
+	       dev->base_addr,
+	       dev->dev_addr[0], dev->dev_addr[1],
+	       dev->dev_addr[2], dev->dev_addr[3],
+	       dev->dev_addr[4], dev->dev_addr[5], dev->irq);
+
+	// if TBI is not endbled
+	if (!(RTL_R8(PHYstatus) & TBI_Enable)) {
+		int val = mdio_read(ioaddr, PHY_AUTO_NEGO_REG);
+
+		option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx];
+		// Force RTL8169 in 10/100/1000 Full/Half mode.
+		if (option > 0) {
+			printk(KERN_INFO "%s: Force-mode Enabled.\n",
+			       dev->name);
+			Cap10_100 = 0, Cap1000 = 0;
+			switch (option) {
+			case _10_Half:
+				Cap10_100 = PHY_Cap_10_Half;
+				Cap1000 = PHY_Cap_Null;
+				break;
+			case _10_Full:
+				Cap10_100 = PHY_Cap_10_Full;
+				Cap1000 = PHY_Cap_Null;
+				break;
+			case _100_Half:
+				Cap10_100 = PHY_Cap_100_Half;
+				Cap1000 = PHY_Cap_Null;
+				break;
+			case _100_Full:
+				Cap10_100 = PHY_Cap_100_Full;
+				Cap1000 = PHY_Cap_Null;
+				break;
+			case _1000_Full:
+				Cap10_100 = PHY_Cap_Null;
+				Cap1000 = PHY_Cap_1000_Full;
+				break;
+			default:
+				break;
+			}
+			mdio_write(ioaddr, PHY_AUTO_NEGO_REG, Cap10_100 | (val & 0x1F));	//leave PHY_AUTO_NEGO_REG bit4:0 unchanged
+			mdio_write(ioaddr, PHY_1000_CTRL_REG, Cap1000);
+		} else {
+			printk(KERN_INFO "%s: Auto-negotiation Enabled.\n",
+			       dev->name);
+
+			// enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged
+			mdio_write(ioaddr, PHY_AUTO_NEGO_REG,
+				   PHY_Cap_10_Half | PHY_Cap_10_Full |
+				   PHY_Cap_100_Half | PHY_Cap_100_Full | (val &
+									  0x1F));
+
+			// enable 1000 Full Mode
+			mdio_write(ioaddr, PHY_1000_CTRL_REG,
+				   PHY_Cap_1000_Full);
+
+		}
+
+		// Enable auto-negotiation and restart auto-nigotiation
+		mdio_write(ioaddr, PHY_CTRL_REG,
+			   PHY_Enable_Auto_Nego | PHY_Restart_Auto_Nego);
+		udelay(100);
+
+		// wait for auto-negotiation process
+		for (i = 10000; i > 0; i--) {
+			//check if auto-negotiation complete
+			if (mdio_read(ioaddr, PHY_STAT_REG) &
+			    PHY_Auto_Neco_Comp) {
+				udelay(100);
+				option = RTL_R8(PHYstatus);
+				if (option & _1000bpsF) {
+					printk(KERN_INFO
+					       "%s: 1000Mbps Full-duplex operation.\n",
+					       dev->name);
+				} else {
+					printk(KERN_INFO
+					       "%s: %sMbps %s-duplex operation.\n",
+					       dev->name,
+					       (option & _100bps) ? "100" :
+					       "10",
+					       (option & FullDup) ? "Full" :
+					       "Half");
+				}
+				break;
+			} else {
+				udelay(100);
+			}
+		}		// end for-loop to wait for auto-negotiation process
+
+	} else {
+		udelay(100);
+		printk(KERN_INFO
+		       "%s: 1000Mbps Full-duplex operation, TBI Link %s!\n",
+		       dev->name,
+		       (RTL_R32(TBICSR) & TBILinkOK) ? "OK" : "Failed");
+
+	}
+
+	return 0;
+}
+
+static void __devexit
+rtl8169_remove_one(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct rtl8169_private *tp = (struct rtl8169_private *) (dev->priv);
+
+	assert(dev != NULL);
+	assert(tp != NULL);
+
+	unregister_netdev(dev);
+	iounmap(tp->mmio_addr);
+	pci_release_regions(pdev);
+
+	// poison memory before freeing 
+	memset(dev, 0xBC,
+	       sizeof (struct net_device) + sizeof (struct rtl8169_private));
+
+	kfree(dev);
+	pci_set_drvdata(pdev, NULL);
+}
+
+static int
+rtl8169_open(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	int retval;
+	u8 diff;
+	u32 TxPhyAddr, RxPhyAddr;
+
+	retval =
+	    request_irq(dev->irq, rtl8169_interrupt, SA_SHIRQ, dev->name, dev);
+	if (retval) {
+		return retval;
+	}
+
+	tp->TxDescArrays =
+	    kmalloc(NUM_TX_DESC * sizeof (struct TxDesc) + 256, GFP_KERNEL);
+	// Tx Desscriptor needs 256 bytes alignment;
+	TxPhyAddr = virt_to_bus(tp->TxDescArrays);
+	diff = 256 - (TxPhyAddr - ((TxPhyAddr >> 8) << 8));
+	TxPhyAddr += diff;
+	tp->TxDescArray = (struct TxDesc *) (tp->TxDescArrays + diff);
+
+	tp->RxDescArrays =
+	    kmalloc(NUM_RX_DESC * sizeof (struct RxDesc) + 256, GFP_KERNEL);
+	// Rx Desscriptor needs 256 bytes alignment;
+	RxPhyAddr = virt_to_bus(tp->RxDescArrays);
+	diff = 256 - (RxPhyAddr - ((RxPhyAddr >> 8) << 8));
+	RxPhyAddr += diff;
+	tp->RxDescArray = (struct RxDesc *) (tp->RxDescArrays + diff);
+
+	if (tp->TxDescArrays == NULL || tp->RxDescArrays == NULL) {
+		printk(KERN_INFO
+		       "Allocate RxDescArray or TxDescArray failed\n");
+		free_irq(dev->irq, dev);
+		if (tp->TxDescArrays)
+			kfree(tp->TxDescArrays);
+		if (tp->RxDescArrays)
+			kfree(tp->RxDescArrays);
+		return -ENOMEM;
+	}
+	tp->RxBufferRings = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL);
+	if (tp->RxBufferRings == NULL) {
+		printk(KERN_INFO "Allocate RxBufferRing failed\n");
+	}
+
+	rtl8169_init_ring(dev);
+	rtl8169_hw_start(dev);
+
+	return 0;
+
+}
+
+static void
+rtl8169_hw_start(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	u32 i;
+
+	/* Soft reset the chip. */
+	RTL_W8(ChipCmd, CmdReset);
+
+	/* Check that the chip has finished the reset. */
+	for (i = 1000; i > 0; i--) {
+		if ((RTL_R8(ChipCmd) & CmdReset) == 0)
+			break;
+		else
+			udelay(10);
+	}
+
+	RTL_W8(Cfg9346, Cfg9346_Unlock);
+	RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+	RTL_W8(EarlyTxThres, EarlyTxThld);
+
+	// For gigabit rtl8169
+	RTL_W16(RxMaxSize, RxPacketMaxSize);
+
+	// Set Rx Config register
+	i = rtl8169_rx_config | (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].
+				 RxConfigMask);
+	RTL_W32(RxConfig, i);
+
+	/* Set DMA burst size and Interframe Gap Time */
+	RTL_W32(TxConfig,
+		(TX_DMA_BURST << TxDMAShift) | (InterFrameGap <<
+						TxInterFrameGapShift));
+
+	tp->cur_rx = 0;
+
+	RTL_W32(TxDescStartAddr, virt_to_bus(tp->TxDescArray));
+	RTL_W32(RxDescStartAddr, virt_to_bus(tp->RxDescArray));
+	RTL_W8(Cfg9346, Cfg9346_Lock);
+	udelay(10);
+
+	RTL_W32(RxMissed, 0);
+
+	rtl8169_set_rx_mode(dev);
+
+	/* no early-rx interrupts */
+	RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
+
+	/* Enable all known interrupts by setting the interrupt mask. */
+	RTL_W16(IntrMask, rtl8169_intr_mask);
+
+	netif_start_queue(dev);
+
+}
+
+static void
+rtl8169_init_ring(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	int i;
+
+	tp->cur_rx = 0;
+	tp->cur_tx = 0;
+	tp->dirty_tx = 0;
+	memset(tp->TxDescArray, 0x0, NUM_TX_DESC * sizeof (struct TxDesc));
+	memset(tp->RxDescArray, 0x0, NUM_RX_DESC * sizeof (struct RxDesc));
+
+	for (i = 0; i < NUM_TX_DESC; i++) {
+		tp->Tx_skbuff[i] = NULL;
+	}
+	for (i = 0; i < NUM_RX_DESC; i++) {
+		if (i == (NUM_RX_DESC - 1))
+			tp->RxDescArray[i].status =
+			    (OWNbit | EORbit) + RX_BUF_SIZE;
+		else
+			tp->RxDescArray[i].status = OWNbit + RX_BUF_SIZE;
+
+		tp->RxBufferRing[i] = &(tp->RxBufferRings[i * RX_BUF_SIZE]);
+		tp->RxDescArray[i].buf_addr = virt_to_bus(tp->RxBufferRing[i]);
+	}
+}
+
+static void
+rtl8169_tx_clear(struct rtl8169_private *tp)
+{
+	int i;
+
+	tp->cur_tx = 0;
+	for (i = 0; i < NUM_TX_DESC; i++) {
+		if (tp->Tx_skbuff[i] != NULL) {
+			dev_kfree_skb(tp->Tx_skbuff[i]);
+			tp->Tx_skbuff[i] = NULL;
+			tp->stats.tx_dropped++;
+		}
+	}
+}
+
+static void
+rtl8169_tx_timeout(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	u8 tmp8;
+
+	/* disable Tx, if not already */
+	tmp8 = RTL_R8(ChipCmd);
+	if (tmp8 & CmdTxEnb)
+		RTL_W8(ChipCmd, tmp8 & ~CmdTxEnb);
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	RTL_W16(IntrMask, 0x0000);
+
+	/* Stop a shared interrupt from scavenging while we are. */
+	spin_lock_irq(&tp->lock);
+	rtl8169_tx_clear(tp);
+	spin_unlock_irq(&tp->lock);
+
+	/* ...and finally, reset everything */
+	rtl8169_hw_start(dev);
+
+	netif_wake_queue(dev);
+}
+
+static int
+rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	int entry = tp->cur_tx % NUM_TX_DESC;
+
+	spin_lock_irq(&tp->lock);
+
+	if ((tp->TxDescArray[entry].status & OWNbit) == 0) {
+		tp->Tx_skbuff[entry] = skb;
+		tp->TxDescArray[entry].buf_addr = virt_to_bus(skb->data);
+		if (entry != (NUM_TX_DESC - 1))
+			tp->TxDescArray[entry].status =
+			    (OWNbit | FSbit | LSbit) | ((skb->len > ETH_ZLEN) ?
+							skb->len : ETH_ZLEN);
+		else
+			tp->TxDescArray[entry].status =
+			    (OWNbit | EORbit | FSbit | LSbit) |
+			    ((skb->len > ETH_ZLEN) ? skb->len : ETH_ZLEN);
+
+		RTL_W8(TxPoll, 0x40);	//set polling bit
+
+		dev->trans_start = jiffies;
+
+		tp->cur_tx++;
+	}
+
+	spin_unlock_irq(&tp->lock);
+
+	if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) {
+		netif_stop_queue(dev);
+	}
+
+	return 0;
+}
+
+static void
+rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
+		     void *ioaddr)
+{
+	unsigned long dirty_tx, tx_left = 0;
+	int entry = tp->cur_tx % NUM_TX_DESC;
+
+	assert(dev != NULL);
+	assert(tp != NULL);
+	assert(ioaddr != NULL);
+
+	dirty_tx = tp->dirty_tx;
+	tx_left = tp->cur_tx - dirty_tx;
+
+	while (tx_left > 0) {
+		if ((tp->TxDescArray[entry].status & OWNbit) == 0) {
+			dev_kfree_skb_irq(tp->
+					  Tx_skbuff[dirty_tx % NUM_TX_DESC]);
+			tp->Tx_skbuff[dirty_tx % NUM_TX_DESC] = NULL;
+			tp->stats.tx_packets++;
+			dirty_tx++;
+			tx_left--;
+			entry++;
+		}
+	}
+
+	if (tp->dirty_tx != dirty_tx) {
+		tp->dirty_tx = dirty_tx;
+		if (netif_queue_stopped(dev))
+			netif_wake_queue(dev);
+	}
+}
+
+static void
+rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
+		     void *ioaddr)
+{
+	int cur_rx;
+	struct sk_buff *skb;
+	int pkt_size = 0;
+
+	assert(dev != NULL);
+	assert(tp != NULL);
+	assert(ioaddr != NULL);
+
+	cur_rx = tp->cur_rx;
+
+	while ((tp->RxDescArray[cur_rx].status & OWNbit) == 0) {
+
+		if (tp->RxDescArray[cur_rx].status & RxRES) {
+			printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name);
+			tp->stats.rx_errors++;
+			if (tp->RxDescArray[cur_rx].status & (RxRWT | RxRUNT))
+				tp->stats.rx_length_errors++;
+			if (tp->RxDescArray[cur_rx].status & RxCRC)
+				tp->stats.rx_crc_errors++;
+		} else {
+			pkt_size =
+			    (int) (tp->RxDescArray[cur_rx].
+				   status & 0x00001FFF) - 4;
+			skb = dev_alloc_skb(pkt_size + 2);
+			if (skb != NULL) {
+				skb->dev = dev;
+				skb_reserve(skb, 2);	// 16 byte align the IP fields. //
+				eth_copy_and_sum(skb, tp->RxBufferRing[cur_rx],
+						 pkt_size, 0);
+				skb_put(skb, pkt_size);
+				skb->protocol = eth_type_trans(skb, dev);
+				netif_rx(skb);
+
+				if (cur_rx == (NUM_RX_DESC - 1))
+					tp->RxDescArray[cur_rx].status =
+					    (OWNbit | EORbit) + RX_BUF_SIZE;
+				else
+					tp->RxDescArray[cur_rx].status =
+					    OWNbit + RX_BUF_SIZE;
+
+				tp->RxDescArray[cur_rx].buf_addr =
+				    virt_to_bus(tp->RxBufferRing[cur_rx]);
+				dev->last_rx = jiffies;
+				tp->stats.rx_bytes += pkt_size;
+				tp->stats.rx_packets++;
+			} else {
+				printk(KERN_WARNING
+				       "%s: Memory squeeze, deferring packet.\n",
+				       dev->name);
+				/* We should check that some rx space is free.
+				   If not, free one and mark stats->rx_dropped++. */
+				tp->stats.rx_dropped++;
+			}
+		}
+
+		cur_rx = (cur_rx + 1) % NUM_RX_DESC;
+
+	}
+
+	tp->cur_rx = cur_rx;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */
+static void
+rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) dev_instance;
+	struct rtl8169_private *tp = dev->priv;
+	int boguscnt = max_interrupt_work;
+	void *ioaddr = tp->mmio_addr;
+	int status = 0;
+
+	do {
+		status = RTL_R16(IntrStatus);
+
+		/* h/w no longer present (hotplug?) or major error, bail */
+		if (status == 0xFFFF)
+			break;
+
+/*
+		if (status & RxUnderrun)
+			link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit;
+*/
+		RTL_W16(IntrStatus,
+			(status & RxFIFOOver) ? (status | RxOverflow) : status);
+
+		if ((status &
+		     (SYSErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
+		      | TxErr | TxOK | RxErr | RxOK)) == 0)
+			break;
+
+		// Rx interrupt 
+		if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) {
+			rtl8169_rx_interrupt(dev, tp, ioaddr);
+		}
+		// Tx interrupt
+		if (status & (TxOK | TxErr)) {
+			spin_lock(&tp->lock);
+			rtl8169_tx_interrupt(dev, tp, ioaddr);
+			spin_unlock(&tp->lock);
+		}
+
+		boguscnt--;
+	} while (boguscnt > 0);
+
+	if (boguscnt <= 0) {
+		printk(KERN_WARNING "%s: Too much work at interrupt!\n",
+		       dev->name);
+		/* Clear all interrupt sources. */
+		RTL_W16(IntrStatus, 0xffff);
+	}
+}
+
+static int
+rtl8169_close(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	int i;
+
+	netif_stop_queue(dev);
+
+	spin_lock_irq(&tp->lock);
+
+	/* Stop the chip's Tx and Rx DMA processes. */
+	RTL_W8(ChipCmd, 0x00);
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	RTL_W16(IntrMask, 0x0000);
+
+	/* Update the error counts. */
+	tp->stats.rx_missed_errors += RTL_R32(RxMissed);
+	RTL_W32(RxMissed, 0);
+
+	spin_unlock_irq(&tp->lock);
+
+	synchronize_irq();
+	free_irq(dev->irq, dev);
+
+	rtl8169_tx_clear(tp);
+	kfree(tp->TxDescArrays);
+	kfree(tp->RxDescArrays);
+	tp->TxDescArrays = NULL;
+	tp->RxDescArrays = NULL;
+	tp->TxDescArray = NULL;
+	tp->RxDescArray = NULL;
+	kfree(tp->RxBufferRings);
+	for (i = 0; i < NUM_RX_DESC; i++) {
+		tp->RxBufferRing[i] = NULL;
+	}
+
+	return 0;
+}
+
+static void
+rtl8169_set_rx_mode(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	unsigned long flags;
+	u32 mc_filter[2];	/* Multicast hash filter */
+	int i, rx_mode;
+	u32 tmp = 0;
+
+	if (dev->flags & IFF_PROMISC) {
+		/* Unconditionally log net taps. */
+		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n",
+		       dev->name);
+		rx_mode =
+		    AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
+		    AcceptAllPhys;
+		mc_filter[1] = mc_filter[0] = 0xffffffff;
+	} else if ((dev->mc_count > multicast_filter_limit)
+		   || (dev->flags & IFF_ALLMULTI)) {
+		/* Too many to filter perfectly -- accept all multicasts. */
+		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+		mc_filter[1] = mc_filter[0] = 0xffffffff;
+	} else {
+		struct dev_mc_list *mclist;
+		rx_mode = AcceptBroadcast | AcceptMyPhys;
+		mc_filter[1] = mc_filter[0] = 0;
+		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+		     i++, mclist = mclist->next) {
+			int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+			mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+			rx_mode |= AcceptMulticast;
+		}
+	}
+
+	spin_lock_irqsave(&tp->lock, flags);
+
+	tmp =
+	    rtl8169_rx_config | rx_mode | (RTL_R32(RxConfig) &
+					   rtl_chip_info[tp->chipset].
+					   RxConfigMask);
+
+	RTL_W32(RxConfig, tmp);
+	RTL_W32(MAR0 + 0, mc_filter[0]);
+	RTL_W32(MAR0 + 4, mc_filter[1]);
+
+	spin_unlock_irqrestore(&tp->lock, flags);
+}
+
+struct net_device_stats *
+rtl8169_get_stats(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+
+	return &tp->stats;
+}
+
+static struct pci_driver rtl8169_pci_driver = {
+	.name		= MODULENAME,
+	.id_table	= rtl8169_pci_tbl,
+	.probe		= rtl8169_init_one,
+	.remove		= rtl8169_remove_one,
+	.suspend	= NULL,
+	.resume		= NULL,
+};
+
+static int __init
+rtl8169_init_module(void)
+{
+	return pci_module_init(&rtl8169_pci_driver);
+}
+
+static void __exit
+rtl8169_cleanup_module(void)
+{
+	pci_unregister_driver(&rtl8169_pci_driver);
+}
+
+module_init(rtl8169_init_module);
+module_exit(rtl8169_cleanup_module);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sis900.c linux-2.4.21/drivers/net/sis900.c
--- linux-2.4.20/drivers/net/sis900.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/sis900.c	2002-12-18 18:58:07.000000000 +0000
@@ -30,13 +30,13 @@
    Rev 1.07.09 Feb.  9 2001 Dave Jones <davej@suse.de> PCI enable cleanup
    Rev 1.07.08 Jan.  8 2001 Lei-Chun Chang added RTL8201 PHY support
    Rev 1.07.07 Nov. 29 2000 Lei-Chun Chang added kernel-doc extractable documentation and 630 workaround fix
-   Rev 1.07.06 Nov.  7 2000 Jeff Garzik <jgarzik@mandrakesoft.com> some bug fix and cleaning
+   Rev 1.07.06 Nov.  7 2000 Jeff Garzik <jgarzik@pobox.com> some bug fix and cleaning
    Rev 1.07.05 Nov.  6 2000 metapirat<metapirat@gmx.de> contribute media type select by ifconfig
    Rev 1.07.04 Sep.  6 2000 Lei-Chun Chang added ICS1893 PHY support
    Rev 1.07.03 Aug. 24 2000 Lei-Chun Chang (lcchang@sis.com.tw) modified 630E eqaulizer workaround rule
    Rev 1.07.01 Aug. 08 2000 Ollie Lho minor update for SiS 630E and SiS 630E A1
    Rev 1.07    Mar. 07 2000 Ollie Lho bug fix in Rx buffer ring
-   Rev 1.06.04 Feb. 11 2000 Jeff Garzik <jgarzik@mandrakesoft.com> softnet and init for kernel 2.4
+   Rev 1.06.04 Feb. 11 2000 Jeff Garzik <jgarzik@pobox.com> softnet and init for kernel 2.4
    Rev 1.06.03 Dec. 23 1999 Ollie Lho Third release
    Rev 1.06.02 Nov. 23 1999 Ollie Lho bug in mac probing fixed
    Rev 1.06.01 Nov. 16 1999 Ollie Lho CRC calculation provide by Joseph Zbiciak (im14u2c@primenet.com)
@@ -532,6 +532,13 @@
 		
 		if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) == NULL) {
 			printk(KERN_INFO "Cannot allocate mem for struct mii_phy\n");
+			mii_phy = sis_priv->first_mii;
+			while (mii_phy) {
+				struct mii_phy *phy;
+				phy = mii_phy;
+				mii_phy = mii_phy->next;
+				kfree(phy);
+			}
 			return 0;
 		}
 		
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/skgehw.h linux-2.4.21/drivers/net/sk98lin/h/skgehw.h
--- linux-2.4.20/drivers/net/sk98lin/h/skgehw.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21/drivers/net/sk98lin/h/skgehw.h	2002-12-18 18:58:11.000000000 +0000
@@ -384,7 +384,6 @@
 /* VPD Region */
 /*	PCI_VPD_ADR_REG		16 bit	VPD Address Register */
 #define	PCI_VPD_FLAG	(1L<<15)	/* Bit 15:	starts VPD rd/wd cycle*/
-#define PCI_VPD_ADDR	(0x3fffL<<0)	/* Bit 14..0:	VPD address */
 
 /*
  *	Control Register File:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/skfp/h/skfbi.h linux-2.4.21/drivers/net/skfp/h/skfbi.h
--- linux-2.4.20/drivers/net/skfp/h/skfbi.h	2001-03-26 02:24:31.000000000 +0000
+++ linux-2.4.21/drivers/net/skfp/h/skfbi.h	2002-12-18 18:58:07.000000000 +0000
@@ -1039,7 +1039,6 @@
 /*	PCI_VPD_NITEM		 8 bit (ML)	Next Item Ptr */
 /*	PCI_VPD_ADR_REG		16 bit (ML)	VPD Address Register */
 #define	PCI_VPD_FLAG	(1<<15)		/* Bit 15	starts VPD rd/wd cycle*/
-#define PCI_VPD_ADDR	(0x3fff<<0)	/* Bit  0..14	VPD address */
 
 /*	PCI_VPD_DAT_REG		32 bit (ML)	VPD Data Register */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/starfire.c linux-2.4.21/drivers/net/starfire.c
--- linux-2.4.20/drivers/net/starfire.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/net/starfire.c	2002-12-18 18:58:05.000000000 +0000
@@ -568,19 +568,18 @@
 	struct net_device_stats stats;
 	struct pci_dev *pci_dev;
 	/* Frequently used values: keep some adjacent for cache effect. */
+	spinlock_t lock;
 	unsigned int cur_rx, dirty_rx;	/* Producer/consumer ring indices */
 	unsigned int cur_tx, dirty_tx;
 	unsigned int rx_buf_sz;		/* Based on MTU+slack. */
 	unsigned int tx_full:1,		/* The Tx queue is full. */
 	/* These values keep track of the transceiver/media in use. */
-		autoneg:1,		/* Autonegotiation allowed. */
-		full_duplex:1,		/* Full-duplex operation. */
 		speed100:1;		/* Set if speed == 100MBit. */
 	unsigned int intr_mitigation;
 	u32 tx_mode;
 	u8 tx_threshold;
 	/* MII transceiver section. */
-	u16 advertising;		/* NWay media advertisement */
+	struct mii_if_info mii_if;		/* MII lib hooks/info */
 	int phy_cnt;			/* MII device addresses. */
 	unsigned char phys[PHY_CNT];	/* MII device addresses. */
 };
@@ -723,9 +722,17 @@
 	dev->irq = irq;
 
 	np = dev->priv;
+	spin_lock_init(&np->lock);
 	pci_set_drvdata(pdev, dev);
 
 	np->pci_dev = pdev;
+
+	np->mii_if.dev = dev;
+	np->mii_if.mdio_read = mdio_read;
+	np->mii_if.mdio_write = mdio_write;
+	np->mii_if.phy_id_mask = 0x1f;
+	np->mii_if.reg_num_mask = 0x1f;
+
 	drv_flags = netdrv_tbl[chip_idx].drv_flags;
 
 	option = card_idx < MAX_UNITS ? options[card_idx] : 0;
@@ -734,15 +741,15 @@
 
 	/* The lower four bits are the media type. */
 	if (option & 0x200)
-		np->full_duplex = 1;
+		np->mii_if.full_duplex = 1;
 
 	if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
-		np->full_duplex = 1;
+		np->mii_if.full_duplex = 1;
 
-	if (np->full_duplex)
-		np->autoneg = 0;
+	if (np->mii_if.full_duplex)
+		np->mii_if.force_media = 0;
 	else
-		np->autoneg = 1;
+		np->mii_if.force_media = 1;
 	np->speed100 = 1;
 
 	/* The chip-specific entries in the device structure. */
@@ -784,15 +791,19 @@
 			mii_status = mdio_read(dev, phy, MII_BMSR);
 			if (mii_status != 0) {
 				np->phys[phy_idx++] = phy;
-				np->advertising = mdio_read(dev, phy, MII_ADVERTISE);
+				np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);
 				printk(KERN_INFO "%s: MII PHY found at address %d, status "
 					   "0x%4.4x advertising %4.4x.\n",
-					   dev->name, phy, mii_status, np->advertising);
+					   dev->name, phy, mii_status, np->mii_if.advertising);
 				/* there can be only one PHY on-board */
 				break;
 			}
 		}
 		np->phy_cnt = phy_idx;
+		if (np->phy_cnt > 0)
+			np->mii_if.phy_id = np->phys[0];
+		else
+			memset(&np->mii_if, 0, sizeof(np->mii_if));
 	}
 
 #ifdef ZEROCOPY
@@ -839,7 +850,6 @@
 	long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2);
 	writel(value, mdio_addr);
 	/* The busy-wait will occur before a read. */
-	return;
 }
 
 
@@ -892,6 +902,7 @@
 		return -ENOMEM;
 	}
 
+	netif_carrier_off(dev);
 	init_ring(dev);
 	/* Set the size of the Rx buffers. */
 	writel((np->rx_buf_sz << RxBufferLenShift) |
@@ -982,7 +993,7 @@
 		printk(KERN_DEBUG "%s: Setting the Rx and Tx modes.\n", dev->name);
 	set_rx_mode(dev);
 
-	np->advertising = mdio_read(dev, np->phys[0], MII_ADVERTISE);
+	np->mii_if.advertising = mdio_read(dev, np->phys[0], MII_ADVERTISE);
 	check_duplex(dev);
 
 	/* Enable GPIO interrupts on link change */
@@ -1023,25 +1034,25 @@
 	struct netdev_private *np = dev->priv;
 	u16 reg0;
 
-	mdio_write(dev, np->phys[0], MII_ADVERTISE, np->advertising);
+	mdio_write(dev, np->phys[0], MII_ADVERTISE, np->mii_if.advertising);
 	mdio_write(dev, np->phys[0], MII_BMCR, BMCR_RESET);
 	udelay(500);
 	while (mdio_read(dev, np->phys[0], MII_BMCR) & BMCR_RESET);
 
 	reg0 = mdio_read(dev, np->phys[0], MII_BMCR);
 
-	if (np->autoneg) {
+	if (!np->mii_if.force_media) {
 		reg0 |= BMCR_ANENABLE | BMCR_ANRESTART;
 	} else {
 		reg0 &= ~(BMCR_ANENABLE | BMCR_ANRESTART);
 		if (np->speed100)
 			reg0 |= BMCR_SPEED100;
-		if (np->full_duplex)
+		if (np->mii_if.full_duplex)
 			reg0 |= BMCR_FULLDPLX;
 		printk(KERN_DEBUG "%s: Link forced to %sMbit %s-duplex\n",
 		       dev->name,
 		       np->speed100 ? "100" : "10",
-		       np->full_duplex ? "full" : "half");
+		       np->mii_if.full_duplex ? "full" : "half");
 	}
 	mdio_write(dev, np->phys[0], MII_BMCR, reg0);
 }
@@ -1552,16 +1563,16 @@
 			reg5 = mdio_read(dev, np->phys[0], MII_LPA);
 			if (reg4 & ADVERTISE_100FULL && reg5 & LPA_100FULL) {
 				np->speed100 = 1;
-				np->full_duplex = 1;
+				np->mii_if.full_duplex = 1;
 			} else if (reg4 & ADVERTISE_100HALF && reg5 & LPA_100HALF) {
 				np->speed100 = 1;
-				np->full_duplex = 0;
+				np->mii_if.full_duplex = 0;
 			} else if (reg4 & ADVERTISE_10FULL && reg5 & LPA_10FULL) {
 				np->speed100 = 0;
-				np->full_duplex = 1;
+				np->mii_if.full_duplex = 1;
 			} else {
 				np->speed100 = 0;
-				np->full_duplex = 0;
+				np->mii_if.full_duplex = 0;
 			}
 		} else {
 			/* autonegotiation is disabled */
@@ -1570,17 +1581,18 @@
 			else
 				np->speed100 = 0;
 			if (reg0 & BMCR_FULLDPLX)
-				np->full_duplex = 1;
+				np->mii_if.full_duplex = 1;
 			else
-				np->full_duplex = 0;
+				np->mii_if.full_duplex = 0;
 		}
+		netif_carrier_on(dev);
 		printk(KERN_DEBUG "%s: Link is up, running at %sMbit %s-duplex\n",
 		       dev->name,
 		       np->speed100 ? "100" : "10",
-		       np->full_duplex ? "full" : "half");
+		       np->mii_if.full_duplex ? "full" : "half");
 
 		new_tx_mode = np->tx_mode & ~0x2;	/* duplex setting */
-		if (np->full_duplex)
+		if (np->mii_if.full_duplex)
 			new_tx_mode |= 2;
 		if (np->tx_mode != new_tx_mode) {
 			np->tx_mode = new_tx_mode;
@@ -1589,6 +1601,7 @@
 			writel(np->tx_mode, ioaddr + TxMode);
 		}
 	} else {
+		netif_carrier_off(dev);
 		printk(KERN_DEBUG "%s: Link is down\n", dev->name);
 	}
 }
@@ -1715,77 +1728,6 @@
 		return -EFAULT;
 
 	switch (ecmd.cmd) {
-	case ETHTOOL_GSET:
-		ecmd.supported =
-			SUPPORTED_10baseT_Half |
-			SUPPORTED_10baseT_Full |
-			SUPPORTED_100baseT_Half |
-			SUPPORTED_100baseT_Full |
-			SUPPORTED_Autoneg |
-			SUPPORTED_MII;
-
-		ecmd.advertising = ADVERTISED_MII;
-		if (np->advertising & ADVERTISE_10HALF)
-			ecmd.advertising |= ADVERTISED_10baseT_Half;
-		if (np->advertising & ADVERTISE_10FULL)
-			ecmd.advertising |= ADVERTISED_10baseT_Full;
-		if (np->advertising & ADVERTISE_100HALF)
-			ecmd.advertising |= ADVERTISED_100baseT_Half;
-		if (np->advertising & ADVERTISE_100FULL)
-			ecmd.advertising |= ADVERTISED_100baseT_Full;
-		if (np->autoneg) {
-			ecmd.advertising |= ADVERTISED_Autoneg;
-			ecmd.autoneg = AUTONEG_ENABLE;
-		} else
-			ecmd.autoneg = AUTONEG_DISABLE;
-
-		ecmd.port = PORT_MII;
-		ecmd.transceiver = XCVR_INTERNAL;
-		ecmd.phy_address = np->phys[0];
-		ecmd.speed = np->speed100 ? SPEED_100 : SPEED_10;
-		ecmd.duplex = np->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
-		ecmd.maxtxpkt = TX_RING_SIZE;
-		ecmd.maxrxpkt = np->intr_mitigation; /* not 100% accurate */
-
-
-		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
-
-	case ETHTOOL_SSET: {
-		u16 autoneg, speed100, full_duplex;
-
-		autoneg = (ecmd.autoneg == AUTONEG_ENABLE);
-		speed100 = (ecmd.speed == SPEED_100);
-		full_duplex = (ecmd.duplex == DUPLEX_FULL);
-
-		np->autoneg = autoneg;
-		if (speed100 != np->speed100 ||
-		    full_duplex != np->full_duplex) {
-			np->speed100 = speed100;
-			np->full_duplex = full_duplex;
-			/* change advertising bits */
-			np->advertising &= ~(ADVERTISE_10HALF |
-					     ADVERTISE_10FULL |
-					     ADVERTISE_100HALF |
-					     ADVERTISE_100FULL |
-					     ADVERTISE_100BASE4);
-			if (speed100) {
-				if (full_duplex)
-					np->advertising |= ADVERTISE_100FULL;
-				else
-					np->advertising |= ADVERTISE_100HALF;
-			} else {
-				if (full_duplex)
-					np->advertising |= ADVERTISE_10FULL;
-				else
-					np->advertising |= ADVERTISE_10HALF;
-			}
-		}
-		check_duplex(dev);
-		return 0;
-	}
-
 	case ETHTOOL_GDRVINFO: {
 		struct ethtool_drvinfo info;
 		memset(&info, 0, sizeof(info));
@@ -1799,26 +1741,35 @@
 		return 0;
 	}
 
+	/* get settings */
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		spin_lock_irq(&np->lock);
+		mii_ethtool_gset(&np->mii_if, &ecmd);
+		spin_unlock_irq(&np->lock);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set settings */
+	case ETHTOOL_SSET: {
+		int r;
+		struct ethtool_cmd ecmd;
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+		spin_lock_irq(&np->lock);
+		r = mii_ethtool_sset(&np->mii_if, &ecmd);
+		spin_unlock_irq(&np->lock);
+		return r;
+	}
 	/* restart autonegotiation */
 	case ETHTOOL_NWAY_RST: {
-		int tmp;
-		int r = -EINVAL;
-		/* if autoneg is off, it's an error */
-		tmp = mdio_read(dev, np->phys[0], MII_BMCR);
-		if (tmp & BMCR_ANENABLE) {
-			tmp |= (BMCR_ANRESTART);
-			mdio_write(dev, np->phys[0], MII_BMCR, tmp);
-			r = 0;
-		}
-		return r;
+		return mii_nway_restart(&np->mii_if);
 	}
 	/* get link status */
 	case ETHTOOL_GLINK: {
 		struct ethtool_value edata = {ETHTOOL_GLINK};
-		if (mdio_read(dev, np->phys[0], MII_BMSR) & BMSR_LSTATUS)
-			edata.data = 1;
-		else
-			edata.data = 0;
+		edata.data = mii_link_ok(&np->mii_if);
 		if (copy_to_user(useraddr, &edata, sizeof(edata)))
 			return -EFAULT;
 		return 0;
@@ -1849,50 +1800,25 @@
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct netdev_private *np = dev->priv;
-	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
+	int rc;
 
-	switch(cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-
-	/* Legacy mii-diag interface */
-	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
-		data->phy_id = np->phys[0] & 0x1f;
-		/* Fall Through */
-
-	case SIOCGMIIREG:		/* Read MII PHY register. */
-	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
-		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
-		return 0;
+	if (!netif_running(dev))
+		return -EINVAL;
 
-	case SIOCSMIIREG:		/* Write MII PHY register. */
-	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		if (data->phy_id == np->phys[0]) {
-			u16 value = data->val_in;
-			switch (data->reg_num) {
-			case 0:
-				if (value & (BMCR_RESET | BMCR_ANENABLE))
-					/* Autonegotiation. */
-					np->autoneg = 1;
-				else {
-					np->full_duplex = (value & BMCR_FULLDPLX) ? 1 : 0;
-					np->autoneg = 0;
-				}
-				break;
-			case 4:
-				np->advertising = value;
-				break;
-			}
+	if (cmd == SIOCETHTOOL)
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
+	else {
+		spin_lock_irq(&np->lock);
+		rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
+		spin_unlock_irq(&np->lock);
+		
+		if ((cmd == SIOCSMIIREG) && (data->phy_id == np->phys[0]))
 			check_duplex(dev);
-		}
-		mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
-		return 0;
-	default:
-		return -EOPNOTSUPP;
 	}
+
+	return rc;
 }
 
 static int netdev_close(struct net_device *dev)
@@ -2012,10 +1938,10 @@
 
 
 static struct pci_driver starfire_driver = {
-	name:		DRV_NAME,
-	probe:		starfire_init_one,
-	remove:		__devexit_p(starfire_remove_one),
-	id_table:	starfire_pci_tbl,
+	.name		= DRV_NAME,
+	.probe		= starfire_init_one,
+	.remove		= __devexit_p(starfire_remove_one),
+	.id_table	= starfire_pci_tbl,
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sunhme.c linux-2.4.21/drivers/net/sunhme.c
--- linux-2.4.20/drivers/net/sunhme.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/sunhme.c	2002-12-18 18:58:06.000000000 +0000
@@ -2701,7 +2701,6 @@
 	}
 
 	hp = dev->priv;
-	memset(hp, 0, sizeof(*hp));
 
 	hp->happy_dev = sdev;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tg3.c linux-2.4.21/drivers/net/tg3.c
--- linux-2.4.20/drivers/net/tg3.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/tg3.c	2002-12-18 18:58:07.000000000 +0000
@@ -2,7 +2,7 @@
  * tg3.c: Broadcom Tigon3 ethernet driver.
  *
  * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)
- * Copyright (C) 2001, 2002 Jeff Garzik (jgarzik@mandrakesoft.com)
+ * Copyright (C) 2001, 2002 Jeff Garzik (jgarzik@pobox.com)
  */
 
 #include <linux/config.h>
@@ -33,15 +33,6 @@
 #define PCI_DMA_BUS_IS_PHYS 1
 #endif
 
-/* Either I can't figure out how they secretly implemented it (ie. RXD flags
- * for mini ring, where it should go in NIC sram, and how many entries the NIC
- * firmware expects) or it isn't really fully implemented.  Perhaps Broadcom
- * wants people to pay for a "performance enhanced" version of their firmware +
- * binary-only driver that has the mini ring actually implemented.
- * These kids today... -DaveM
- */
-#define TG3_MINI_RING_WORKS 0
-
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 #define TG3_VLAN_TAG_USED 1
 #else
@@ -59,8 +50,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"1.2"
-#define DRV_MODULE_RELDATE	"Nov 14, 2002"
+#define DRV_MODULE_VERSION	"1.2a"
+#define DRV_MODULE_RELDATE	"Dec 9, 2002"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -90,10 +81,6 @@
  */
 #define TG3_RX_RING_SIZE		512
 #define TG3_DEF_RX_RING_PENDING		200
-#if TG3_MINI_RING_WORKS
-#define TG3_RX_MINI_RING_SIZE		256 /* ??? */
-#define TG3_DEF_RX_MINI_RING_PENDING	100
-#endif
 #define TG3_RX_JUMBO_RING_SIZE		256
 #define TG3_DEF_RX_JUMBO_RING_PENDING	100
 #define TG3_RX_RCB_RING_SIZE		1024
@@ -102,10 +89,6 @@
 
 #define TG3_RX_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * \
 				 TG3_RX_RING_SIZE)
-#if TG3_MINI_RING_WORKS
-#define TG3_RX_MINI_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * \
-				 TG3_RX_MINI_RING_SIZE)
-#endif
 #define TG3_RX_JUMBO_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * \
 			         TG3_RX_JUMBO_RING_SIZE)
 #define TG3_RX_RCB_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * \
@@ -121,9 +104,6 @@
 #define NEXT_TX(N)		(((N) + 1) & (TG3_TX_RING_SIZE - 1))
 
 #define RX_PKT_BUF_SZ		(1536 + tp->rx_offset + 64)
-#if TG3_MINI_RING_WORKS
-#define RX_MINI_PKT_BUF_SZ	(256 + tp->rx_offset + 64)
-#endif
 #define RX_JUMBO_PKT_BUF_SZ	(9046 + tp->rx_offset + 64)
 
 /* minimum number of free TX descriptors required to wake up TX process */
@@ -132,7 +112,7 @@
 static char version[] __devinitdata =
 	DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
 
-MODULE_AUTHOR("David S. Miller (davem@redhat.com) and Jeff Garzik (jgarzik@mandrakesoft.com)");
+MODULE_AUTHOR("David S. Miller (davem@redhat.com) and Jeff Garzik (jgarzik@pobox.com)");
 MODULE_DESCRIPTION("Broadcom Tigon3 ethernet driver");
 MODULE_LICENSE("GPL");
 MODULE_PARM(tg3_debug, "i");
@@ -1784,16 +1764,7 @@
 			src_map = &tp->rx_jumbo_buffers[src_idx];
 		skb_size = RX_JUMBO_PKT_BUF_SZ;
 		break;
-#if TG3_MINI_RING_WORKS
-	case RXD_OPAQUE_RING_MINI:
-		dest_idx = dest_idx_unmasked % TG3_RX_MINI_RING_SIZE;
-		desc = &tp->rx_mini[dest_idx];
-		map = &tp->rx_mini_buffers[dest_idx];
-		if (src_idx >= 0)
-			src_map = &tp->rx_mini_buffers[src_idx];
-		skb_size = RX_MINI_PKT_BUF_SZ;
-		break;
-#endif
+
 	default:
 		return -EINVAL;
 	};
@@ -1854,15 +1825,7 @@
 		src_desc = &tp->rx_jumbo[src_idx];
 		src_map = &tp->rx_jumbo_buffers[src_idx];
 		break;
-#if TG3_MINI_RING_WORKS
-	case RXD_OPAQUE_RING_MINI:
-		dest_idx = dest_idx_unmasked % TG3_RX_MINI_RING_SIZE;
-		dest_desc = &tp->rx_mini[dest_idx];
-		dest_map = &tp->rx_mini_buffers[dest_idx];
-		src_desc = &tp->rx_mini[src_idx];
-		src_map = &tp->rx_mini_buffers[src_idx];
-		break;
-#endif
+
 	default:
 		return;
 	};
@@ -1938,14 +1901,6 @@
 			skb = tp->rx_jumbo_buffers[desc_idx].skb;
 			post_ptr = &tp->rx_jumbo_ptr;
 		}
-#if TG3_MINI_RING_WORKS
-		else if (opaque_key == RXD_OPAQUE_RING_MINI) {
-			dma_addr = pci_unmap_addr(&tp->rx_mini_buffers[desc_idx],
-						  mapping);
-			skb = tp->rx_mini_buffers[desc_idx].skb;
-			post_ptr = &tp->rx_mini_ptr;
-		}
-#endif
 		else {
 			goto next_pkt_nopost;
 		}
@@ -1965,7 +1920,6 @@
 
 		len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; /* omit crc */
 
-		/* Kill the copy case if we ever get the mini ring working. */
 		if (len > RX_COPY_THRESHOLD) {
 			int skb_size;
 
@@ -2051,15 +2005,6 @@
 		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
 			tr32(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW);
 	}
-#if TG3_MINI_RING_WORKS
-	if (work_mask & RXD_OPAQUE_RING_MINI) {
-		sw_idx = tp->rx_mini_ptr % TG3_RX_MINI_RING_SIZE;
-		tw32_mailbox(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW,
-			     sw_idx);
-		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
-			tr32(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW);
-	}
-#endif
 
 	return received;
 }
@@ -2734,20 +2679,7 @@
 		dev_kfree_skb_any(rxp->skb);
 		rxp->skb = NULL;
 	}
-#if TG3_MINI_RING_WORKS
-	for (i = 0; i < TG3_RX_MINI_RING_SIZE; i++) {
-		rxp = &tp->rx_mini_buffers[i];
 
-		if (rxp->skb == NULL)
-			continue;
-		pci_unmap_single(tp->pdev,
-				 pci_unmap_addr(rxp, mapping),
-				 RX_MINI_PKT_BUF_SZ - tp->rx_offset,
-				 PCI_DMA_FROMDEVICE);
-		dev_kfree_skb_any(rxp->skb);
-		rxp->skb = NULL;
-	}
-#endif
 	for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) {
 		rxp = &tp->rx_jumbo_buffers[i];
 
@@ -2812,9 +2744,6 @@
 
 	/* Zero out all descriptors. */
 	memset(tp->rx_std, 0, TG3_RX_RING_BYTES);
-#if TG3_MINI_RING_WORKS
-	memset(tp->rx_mini, 0, TG3_RX_MINI_RING_BYTES);
-#endif
 	memset(tp->rx_jumbo, 0, TG3_RX_JUMBO_RING_BYTES);
 	memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES);
 
@@ -2847,19 +2776,7 @@
 		rxd->opaque = (RXD_OPAQUE_RING_STD |
 			       (i << RXD_OPAQUE_INDEX_SHIFT));
 	}
-#if TG3_MINI_RING_WORKS
-	for (i = 0; i < TG3_RX_MINI_RING_SIZE; i++) {
-		struct tg3_rx_buffer_desc *rxd;
 
-		rxd = &tp->rx_mini[i];
-		rxd->idx_len = (RX_MINI_PKT_BUF_SZ - tp->rx_offset - 64)
-			<< RXD_LEN_SHIFT;
-		rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) |
-			RXD_FLAG_MINI;
-		rxd->opaque = (RXD_OPAQUE_RING_MINI |
-			       (i << RXD_OPAQUE_INDEX_SHIFT));
-	}
-#endif
 	if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) {
 		for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) {
 			struct tg3_rx_buffer_desc *rxd;
@@ -2881,14 +2798,6 @@
 			break;
 	}
 
-#if TG3_MINI_RING_WORKS
-	for (i = 0; i < tp->rx_mini_pending; i++) {
-		if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_MINI,
-				     -1, i) < 0)
-			break;
-	}
-#endif
-
 	if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) {
 		for (i = 0; i < tp->rx_jumbo_pending; i++) {
 			if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_JUMBO,
@@ -2913,13 +2822,6 @@
 				    tp->rx_std, tp->rx_std_mapping);
 		tp->rx_std = NULL;
 	}
-#if TG3_MINI_RING_WORKS
-	if (tp->rx_mini) {
-		pci_free_consistent(tp->pdev, TG3_RX_MINI_RING_BYTES,
-				    tp->rx_mini, tp->rx_mini_mapping);
-		tp->rx_mini = NULL;
-	}
-#endif
 	if (tp->rx_jumbo) {
 		pci_free_consistent(tp->pdev, TG3_RX_JUMBO_RING_BYTES,
 				    tp->rx_jumbo, tp->rx_jumbo_mapping);
@@ -2955,9 +2857,6 @@
 {
 	tp->rx_std_buffers = kmalloc((sizeof(struct ring_info) *
 				      (TG3_RX_RING_SIZE +
-#if TG3_MINI_RING_WORKS
-				       TG3_RX_MINI_RING_SIZE +
-#endif
 				       TG3_RX_JUMBO_RING_SIZE)) +
 				     (sizeof(struct tx_ring_info) *
 				      TG3_TX_RING_SIZE),
@@ -2965,29 +2864,14 @@
 	if (!tp->rx_std_buffers)
 		return -ENOMEM;
 
-#if TG3_MINI_RING_WORKS
 	memset(tp->rx_std_buffers, 0,
 	       (sizeof(struct ring_info) *
 		(TG3_RX_RING_SIZE +
-		 TG3_RX_MINI_RING_SIZE +
 		 TG3_RX_JUMBO_RING_SIZE)) +
 	       (sizeof(struct tx_ring_info) *
 		TG3_TX_RING_SIZE));
-#else
-	memset(tp->rx_std_buffers, 0,
-	       (sizeof(struct ring_info) *
-		(TG3_RX_RING_SIZE +
-		 TG3_RX_JUMBO_RING_SIZE)) +
-	       (sizeof(struct tx_ring_info) *
-		TG3_TX_RING_SIZE));
-#endif
 
-#if TG3_MINI_RING_WORKS
-	tp->rx_mini_buffers = &tp->rx_std_buffers[TG3_RX_RING_SIZE];
-	tp->rx_jumbo_buffers = &tp->rx_mini_buffers[TG3_RX_MINI_RING_SIZE];
-#else
 	tp->rx_jumbo_buffers = &tp->rx_std_buffers[TG3_RX_RING_SIZE];
-#endif
 	tp->tx_buffers = (struct tx_ring_info *)
 		&tp->rx_jumbo_buffers[TG3_RX_JUMBO_RING_SIZE];
 
@@ -2996,14 +2880,6 @@
 	if (!tp->rx_std)
 		goto err_out;
 
-#if TG3_MINI_RING_WORKS
-	tp->rx_mini = pci_alloc_consistent(tp->pdev, TG3_RX_MINI_RING_BYTES,
-					   &tp->rx_mini_mapping);
-
-	if (!tp->rx_mini)
-		goto err_out;
-#endif
-
 	tp->rx_jumbo = pci_alloc_consistent(tp->pdev, TG3_RX_JUMBO_RING_BYTES,
 					    &tp->rx_jumbo_mapping);
 
@@ -4119,8 +3995,6 @@
 	 * Standard receive ring @ NIC_SRAM_RX_BUFFER_DESC, 512 entries.
 	 * Jumbo receive ring @ NIC_SRAM_RX_JUMBO_BUFFER_DESC, 256 entries.
 	 *
-	 * ??? No space allocated for mini receive ring? :(
-	 *
 	 * The size of each ring is fixed in the firmware, but the location is
 	 * configurable.
 	 */
@@ -4133,19 +4007,8 @@
 	tw32(RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR,
 	     NIC_SRAM_RX_BUFFER_DESC);
 
-#if TG3_MINI_RING_WORKS
-	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH,
-	     ((u64) tp->rx_mini_mapping >> 32));
-	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW,
-	     ((u64) tp->rx_mini_mapping & 0xffffffff));
-	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS,
-	     RX_MINI_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT);
-	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_NIC_ADDR,
-	     NIC_SRAM_RX_MINI_BUFFER_DESC);
-#else
 	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS,
 	     BDINFO_FLAGS_DISABLED);
-#endif
 
 	if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) {
 		tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH,
@@ -4163,9 +4026,6 @@
 
 	/* Setup replenish thresholds. */
 	tw32(RCVBDI_STD_THRESH, tp->rx_pending / 8);
-#if TG3_MINI_RING_WORKS
-	tw32(RCVBDI_MINI_THRESH, tp->rx_mini_pending / 8);
-#endif
 	tw32(RCVBDI_JUMBO_THRESH, tp->rx_jumbo_pending / 8);
 
 	/* Clear out send RCB ring in SRAM. */
@@ -4213,13 +4073,6 @@
 		     tp->rx_std_ptr);
 	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
 		tr32(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW);
-#if TG3_MINI_RING_WORKS
-	tp->rx_mini_ptr = tp->rx_mini_pending;
-	tw32_mailbox(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW,
-		     tp->rx_mini_ptr);
-	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
-		tr32(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW);
-#endif
 
 	if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE)
 		tp->rx_jumbo_ptr = tp->rx_jumbo_pending;
@@ -4840,23 +4693,6 @@
 		       readl(rxd + 0x0), readl(rxd + 0x4),
 		       readl(rxd + 0x8), readl(rxd + 0xc));
 	}
-#if TG3_MINI_RING_WORKS
-	for (i = 0; i < 6; i++) {
-		unsigned long rxd;
-
-		rxd = tp->regs + NIC_SRAM_WIN_BASE + NIC_SRAM_RX_MINI_BUFFER_DESC
-			+ (i * sizeof(struct tg3_rx_buffer_desc));
-		printk("DEBUG: NIC RXD_MINI(%d)[0][%08x:%08x:%08x:%08x]\n",
-		       i,
-		       readl(rxd + 0x0), readl(rxd + 0x4),
-		       readl(rxd + 0x8), readl(rxd + 0xc));
-		rxd += (4 * sizeof(u32));
-		printk("DEBUG: NIC RXD_MINI(%d)[1][%08x:%08x:%08x:%08x]\n",
-		       i,
-		       readl(rxd + 0x0), readl(rxd + 0x4),
-		       readl(rxd + 0x8), readl(rxd + 0xc));
-	}
-#endif
 
 	for (i = 0; i < 6; i++) {
 		unsigned long rxd;
@@ -5387,19 +5223,11 @@
 		struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM };
 
 		ering.rx_max_pending = TG3_RX_RING_SIZE - 1;
-#if TG3_MINI_RING_WORKS
-		ering.rx_mini_max_pending = TG3_RX_MINI_RING_SIZE - 1;
-#else
 		ering.rx_mini_max_pending = 0;
-#endif
 		ering.rx_jumbo_max_pending = TG3_RX_JUMBO_RING_SIZE - 1;
 
 		ering.rx_pending = tp->rx_pending;
-#if TG3_MINI_RING_WORKS
-		ering.rx_mini_pending = tp->rx_mini_pending;
-#else
 		ering.rx_mini_pending = 0;
-#endif
 		ering.rx_jumbo_pending = tp->rx_jumbo_pending;
 		ering.tx_pending = tp->tx_pending;
 
@@ -5414,9 +5242,6 @@
 			return -EFAULT;
 
 		if ((ering.rx_pending > TG3_RX_RING_SIZE - 1) ||
-#if TG3_MINI_RING_WORKS
-		    (ering.rx_mini_pending > TG3_RX_MINI_RING_SIZE - 1) ||
-#endif
 		    (ering.rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
 		    (ering.tx_pending > TG3_TX_RING_SIZE - 1))
 			return -EINVAL;
@@ -5425,9 +5250,6 @@
 		spin_lock(&tp->tx_lock);
 
 		tp->rx_pending = ering.rx_pending;
-#if TG3_MINI_RING_WORKS
-		tp->rx_mini_pending = ering.rx_mini_pending;
-#endif
 		tp->rx_jumbo_pending = ering.rx_jumbo_pending;
 		tp->tx_pending = ering.tx_pending;
 
@@ -6150,6 +5972,13 @@
 	if ((pci_state_reg & PCISTATE_BUS_32BIT) != 0)
 		tp->tg3_flags |= TG3_FLAG_PCI_32BIT;
 
+	/* Chip-specific fixup from Broadcom driver */
+	if ((tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) &&
+	    (!(pci_state_reg & PCISTATE_RETRY_SAME_DMA))) {
+		pci_state_reg |= PCISTATE_RETRY_SAME_DMA;
+		pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, pci_state_reg);
+	}
+
 	/* Force the chip into D0. */
 	err = tg3_set_power_state(tp, 0);
 	if (err)
@@ -6839,9 +6668,6 @@
 	tg3_init_bufmgr_config(tp);
 
 	tp->rx_pending = TG3_DEF_RX_RING_PENDING;
-#if TG3_MINI_RING_WORKS
-	tp->rx_mini_pending = TG3_DEF_RX_MINI_RING_PENDING;
-#endif
 	tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING;
 	tp->tx_pending = TG3_DEF_TX_RING_PENDING;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tg3.h linux-2.4.21/drivers/net/tg3.h
--- linux-2.4.20/drivers/net/tg3.h	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/tg3.h	2002-12-18 18:58:10.000000000 +0000
@@ -2,7 +2,7 @@
  * tg3.h: Definitions for Broadcom Tigon3 ethernet driver.
  *
  * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)
- * Copyright (C) 2001 Jeff Garzik (jgarzik@mandrakesoft.com)
+ * Copyright (C) 2001 Jeff Garzik (jgarzik@pobox.com)
  */
 
 #ifndef _T3_H
@@ -25,9 +25,6 @@
 
 #define RX_STD_MAX_SIZE			1536
 #define RX_JUMBO_MAX_SIZE		0xdeadbeef /* XXX */
-#if TG3_MINI_RING_WORKS
-#define RX_MINI_MAX_SIZE		256
-#endif
 
 /* First 256 bytes are a mirror of PCI config space. */
 #define TG3PCI_VENDOR			0x00000000
@@ -1301,9 +1298,7 @@
 #define NIC_SRAM_MAC_ADDR_HIGH_MBOX	0x00000c14
 #define NIC_SRAM_MAC_ADDR_LOW_MBOX	0x00000c18
 
-#if TG3_MINI_RING_WORKS
 #define NIC_SRAM_RX_MINI_BUFFER_DESC	0x00001000
-#endif
 
 #define NIC_SRAM_DMA_DESC_POOL_BASE	0x00002000
 #define  NIC_SRAM_DMA_DESC_POOL_SIZE	 0x00002000
@@ -1453,9 +1448,7 @@
 #define RXD_FLAGS_SHIFT	0
 
 #define RXD_FLAG_END			0x0004
-#if TG3_MINI_RING_WORKS
 #define RXD_FLAG_MINI			0x0800
-#endif
 #define RXD_FLAG_JUMBO			0x0020
 #define RXD_FLAG_VLAN			0x0040
 #define RXD_FLAG_ERROR			0x0400
@@ -1490,9 +1483,7 @@
 #define RXD_OPAQUE_INDEX_SHIFT		0
 #define RXD_OPAQUE_RING_STD		0x00010000
 #define RXD_OPAQUE_RING_JUMBO		0x00020000
-#if TG3_MINI_RING_WORKS
 #define RXD_OPAQUE_RING_MINI		0x00040000
-#endif
 #define RXD_OPAQUE_RING_MASK		0x00070000
 };
 
@@ -1728,6 +1719,8 @@
 };
 
 struct tg3 {
+	/* begin "general, frequently-used members" cacheline section */
+
 	/* SMP locking strategy:
 	 *
 	 * lock: Held during all operations except TX packet
@@ -1741,18 +1734,51 @@
 	 * necessary for acquisition of 'tx_lock'.
 	 */
 	spinlock_t			lock;
-	spinlock_t			tx_lock;
+	spinlock_t			indirect_lock;
 
+	unsigned long			regs;
+	struct net_device		*dev;
+	struct pci_dev			*pdev;
+
+	struct tg3_hw_status		*hw_status;
+	dma_addr_t			status_mapping;
+
+	u32				msg_enable;
+
+	/* begin "tx thread" cacheline section */
 	u32				tx_prod;
 	u32				tx_cons;
+	u32				tx_pending;
+
+	spinlock_t			tx_lock;
+
+	/* TX descs are only used if TG3_FLAG_HOST_TXDS is set. */
+	struct tg3_tx_buffer_desc	*tx_ring;
+	struct tx_ring_info		*tx_buffers;
+	dma_addr_t			tx_desc_mapping;
+
+	/* begin "rx thread" cacheline section */
 	u32				rx_rcb_ptr;
 	u32				rx_std_ptr;
 	u32				rx_jumbo_ptr;
-#if TG3_MINI_RING_WORKS
-	u32				rx_mini_ptr;
+	u32				rx_pending;
+	u32				rx_jumbo_pending;
+#if TG3_VLAN_TAG_USED
+	struct vlan_group		*vlgrp;
 #endif
-	spinlock_t			indirect_lock;
 
+	struct tg3_rx_buffer_desc	*rx_std;
+	struct ring_info		*rx_std_buffers;
+	dma_addr_t			rx_std_mapping;
+
+	struct tg3_rx_buffer_desc	*rx_jumbo;
+	struct ring_info		*rx_jumbo_buffers;
+	dma_addr_t			rx_jumbo_mapping;
+
+	struct tg3_rx_buffer_desc	*rx_rcb;
+	dma_addr_t			rx_rcb_mapping;
+
+	/* begin "everything else" cacheline(s) section */
 	struct net_device_stats		net_stats;
 	struct net_device_stats		net_stats_prev;
 	unsigned long			phy_crc_errors;
@@ -1791,8 +1817,6 @@
 #define TG3_FLAG_SPLIT_MODE		0x40000000
 #define TG3_FLAG_INIT_COMPLETE		0x80000000
 
-	u32				msg_enable;
-
 	u32				split_mode_max_reqs;
 #define SPLIT_MODE_5704_MAX_REQ		3
 
@@ -1806,13 +1830,6 @@
 	struct tg3_link_config		link_config;
 	struct tg3_bufmgr_config	bufmgr_config;
 
-	u32				rx_pending;
-#if TG3_MINI_RING_WORKS
-	u32				rx_mini_pending;
-#endif
-	u32				rx_jumbo_pending;
-	u32				tx_pending;
-
 	/* cache h/w values, often passed straight to h/w */
 	u32				rx_mode;
 	u32				tx_mode;
@@ -1865,36 +1882,6 @@
 	 (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \
 	 (X) == PHY_ID_BCM8002 || (X) == PHY_ID_SERDES)
 
-	unsigned long			regs;
-	struct pci_dev			*pdev;
-	struct net_device		*dev;
-#if TG3_VLAN_TAG_USED
-	struct vlan_group		*vlgrp;
-#endif
-
-	struct tg3_rx_buffer_desc	*rx_std;
-	struct ring_info		*rx_std_buffers;
-	dma_addr_t			rx_std_mapping;
-#if TG3_MINI_RING_WORKS
-	struct tg3_rx_buffer_desc	*rx_mini;
-	struct ring_info		*rx_mini_buffers;
-	dma_addr_t			rx_mini_mapping;
-#endif
-	struct tg3_rx_buffer_desc	*rx_jumbo;
-	struct ring_info		*rx_jumbo_buffers;
-	dma_addr_t			rx_jumbo_mapping;
-
-	struct tg3_rx_buffer_desc	*rx_rcb;
-	dma_addr_t			rx_rcb_mapping;
-
-	/* TX descs are only used if TG3_FLAG_HOST_TXDS is set. */
-	struct tg3_tx_buffer_desc	*tx_ring;
-	struct tx_ring_info		*tx_buffers;
-	dma_addr_t			tx_desc_mapping;
-
-	struct tg3_hw_status		*hw_status;
-	dma_addr_t			status_mapping;
-
 	struct tg3_hw_stats		*hw_stats;
 	dma_addr_t			stats_mapping;
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tokenring/3c359.c linux-2.4.21/drivers/net/tokenring/3c359.c
--- linux-2.4.20/drivers/net/tokenring/3c359.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/tokenring/3c359.c	2002-12-18 18:58:09.000000000 +0000
@@ -1780,7 +1780,7 @@
 
 static void __devexit xl_remove_one (struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata(pdev);
 	struct xl_private *xl_priv=(struct xl_private *)dev->priv;
 	
 	unregister_trdev(dev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tokenring/lanstreamer.c linux-2.4.21/drivers/net/tokenring/lanstreamer.c
--- linux-2.4.20/drivers/net/tokenring/lanstreamer.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/tokenring/lanstreamer.c	2002-12-18 18:58:08.000000000 +0000
@@ -66,6 +66,8 @@
  *             the number of TX descriptors to 1, which together can prevent 
  *             the card from locking up the box - <yoder1@us.ibm.com>
  *  09/27/02 - New PCI interface + bug fix. - <yoder1@us.ibm.com>
+ *  11/13/02 - Removed free_irq calls which could cause a hang, added
+ *	       netif_carrier_{on|off} - <yoder1@us.ibm.com>
  *  
  *  To Do:
  *
@@ -137,7 +139,7 @@
  */
 
 static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan\n"
-                        "              v0.5.2 09/30/02 - Kent Yoder";
+                        "              v0.5.3 11/13/02 - Kent Yoder";
 
 static struct pci_device_id streamer_pci_tbl[] __initdata = {
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, PCI_ANY_ID, PCI_ANY_ID,},
@@ -879,6 +881,7 @@
 #endif
 
 	netif_start_queue(dev);
+	netif_carrier_on(dev);
 	return 0;
 }
 
@@ -1102,7 +1105,9 @@
 			       ntohs(readw(streamer_mmio + LAPDINC)),
 			       ntohs(readw(streamer_mmio + LAPDINC)),
 			       ntohs(readw(streamer_mmio + LAPDINC)));
-			free_irq(dev->irq, dev);
+			netif_stop_queue(dev);
+			netif_carrier_off(dev);
+			printk(KERN_WARNING "%s: Adapter must be manually reset.\n", dev->name);
 		}
 
 		/* SISR_ADAPTER_CHECK */
@@ -1200,6 +1205,7 @@
 	int i;
 
 	netif_stop_queue(dev);
+	netif_carrier_off(dev);
 	writew(streamer_priv->srb, streamer_mmio + LAPA);
 	writew(htons(SRB_CLOSE_ADAPTER << 8),streamer_mmio+LAPDINC);
 	writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC);
@@ -1670,11 +1676,10 @@
 			/* @TBD. no llc reset on autostreamer writel(readl(streamer_mmio+BCTL)|(3<<13),streamer_mmio+BCTL);
 			   udelay(1);
 			   writel(readl(streamer_mmio+BCTL)&~(3<<13),streamer_mmio+BCTL); */
-			netif_stop_queue(dev);
-			free_irq(dev->irq, dev);
-
-			printk(KERN_WARNING "%s: Adapter has been closed \n", dev->name);
 
+			netif_stop_queue(dev);
+			netif_carrier_off(dev);
+			printk(KERN_WARNING "%s: Adapter must be manually reset.\n", dev->name);
 		}
 		/* If serious error */
 		if (streamer_priv->streamer_message_level) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tulip/21142.c linux-2.4.21/drivers/net/tulip/21142.c
--- linux-2.4.20/drivers/net/tulip/21142.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/net/tulip/21142.c	2002-12-18 18:58:04.000000000 +0000
@@ -1,7 +1,7 @@
 /*
 	drivers/net/tulip/21142.c
 
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001  The Linux Kernel Team
 	Written/copyright 1994-2001 by Donald Becker.
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tulip/ChangeLog linux-2.4.21/drivers/net/tulip/ChangeLog
--- linux-2.4.20/drivers/net/tulip/ChangeLog	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/tulip/ChangeLog	2002-12-18 18:58:04.000000000 +0000
@@ -14,12 +14,12 @@
 	* 21142.c (t21142_lnk_change): Revert earlier patch
 	to always reset phy; only conditionally do so now.
 
-2002-05-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2002-05-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core (tulip_pci_tbl): Add new "comet"
 	pci id.  Contributed by Ohta Kyuma.
 
-2002-03-07  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2002-03-07  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core (tulip_mwi_config): Use new PCI API functions
 	for enabling and disabled Memory-Write-Invalidate
@@ -98,30 +98,30 @@
 	Clear status for in-progress Tx's, and count
 	Tx errors for all packets being released.
 
-2001-06-16  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-06-16  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip.h, tulip_core.c:
 	Integrate MMIO support from devel branch, but default
 	it to off for stable kernel and driver series.
 
-2001-06-16  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-06-16  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (tulip_init_one):
 	Free descriptor rings on error.
 
-2001-06-16  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-06-16  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (tulip_mwi_config, tulip_init_one):
 	Large update to csr0 bus configuration code.  This is not stable
 	yet, so it is only conditionally enabled, via CONFIG_TULIP_MWI.
 
-2001-06-16  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-06-16  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c:
 	Initialize timer in tulip_init_one and tulip_down,
 	not in tulip_up.
 
-2001-06-14  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-06-14  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c:
 	- Update tulip_suspend, tulip_resume for new PCI PM API.
@@ -138,14 +138,14 @@
 	* tulip_core (set_rx_mode):  Do not use set_bit
 	on an integer variable.  Also fix endianness issue.
 
-2001-06-04  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-06-04  Jeff Garzik  <jgarzik@pobox.com>
 
 	* interrupt.c:
 	Simplify rx processing when CONFIG_NET_HW_FLOWCONTROL is
 	active, and in the process fix a bug where flow control
 	and low load caused rx not to be acknowledged properly.
 
-2001-06-01  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-06-01  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip.h:
 	- Remove tulip_outl_csr helper, redundant.
@@ -165,7 +165,7 @@
 	  convert tabs to spaces.
 	- Move tp->stats.rx_missed_errors update outside the ifdef.
 
-2001-05-18  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-18  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c: Added ethtool support.
 	  ETHTOOL_GDRVINFO ioctl only, for now.
@@ -184,22 +184,22 @@
 
 	* tulip_refill_rx prototype added to tulip.h
 
-2001-05-13  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-13  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c: Remove HAS_PCI_MWI flag from Comet, untested.
 
-2001-05-12  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c, tulip.h: Remove Conexant PCI id, no chip
 	docs are available to fix problems with support.
 
-2001-05-12  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (tulip_init_one): Do not call
 	unregister_netdev in error cleanup.  Remnant of old
 	usage of init_etherdev.
 
-2001-05-12  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
 
 	* media.c (tulip_find_mii): Simple write the updated BMCR
 	twice, as it seems the best thing to do for both broken and
@@ -210,36 +210,36 @@
 	Fill in tp->advertising for all cases.
 	Just to be safe, clear all unwanted bits.
 
-2001-05-12  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (private_ioctl):  Fill in tp->advertising
 	when advertising value is changed by the user.
 
-2001-05-12  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c: Mark Comet chips as needed the updated MWI
 	csr0 configuration.
 
-2001-05-12  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
 
 	* media.c, tulip_core.c:  Move MII scan into
 	from inlined inside tulip_init_one to new function
 	tulip_find_mii in media.c.
 
-2001-05-12  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
 
 	* media.c (tulip_check_duplex):
 	Only restart Rx/Tx engines if they are active
 	(and csr6 changes)
 
-2001-05-12  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (tulip_mwi_config):
 	Clamp values read from PCI cache line size register to
 	values acceptable to tulip chip.  Done for safety and
 	-almost- certainly unneeded.
 
-2001-05-11  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-11  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (tulip_init_one):
 	Instead of unconditionally enabling autonegotiation, disable
@@ -253,7 +253,7 @@
 	to BMCR twice, to avoid setting unnecessarily changing
 	phy settings.
 
-2001-05-11  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-11  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip.h, tulip_core.c:  If HAS_PCI_MWI is set for a
 	given chip, adjust the csr0 values not according to
@@ -264,7 +264,7 @@
 	alignment and system cache size.  Currently MWI bit is set
 	only if the MWI bit is present in the PCI command register.
 
-2001-05-11  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-11  Jeff Garzik  <jgarzik@pobox.com>
 
 	* media.c (tulip_select_media):
 	For media types 1 and 3, only use the provided eeprom
@@ -274,7 +274,7 @@
 	ensures that the csr6 value is written if an update
 	is needed.
 
-2001-05-10  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-10  Jeff Garzik  <jgarzik@pobox.com>
 
 	Merge PNIC-II-specific stuff from Becker's tulip.c:
 
@@ -284,13 +284,13 @@
 	* tulip_core.c (tulip_tx_timeout): Add specific
 	debugging for PNIC2.
 
-2001-05-10  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-10  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (tulip_init_one): Print out
 	tulip%d instead of PCI device number, for
 	consistency.
 
-2001-05-10  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-10  Jeff Garzik  <jgarzik@pobox.com>
 
 	* Merge changes from Becker's tulip.c:
 	Fix bugs in ioctl.
@@ -299,7 +299,7 @@
 	Set CSR14 autonegotiation bit for media types 2 and 4,
 	where the SIA CSR setup values are not provided.
 
-2001-05-10  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-10  Jeff Garzik  <jgarzik@pobox.com>
 
 	* media.c (tulip_select_media): Only update MII
 	advertising value if startup arg < 2.
@@ -313,7 +313,7 @@
 	value 2 as 'startup' arg to select_media, to avoid updating
 	MII advertising value.
 
-2001-05-10  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-10  Jeff Garzik  <jgarzik@pobox.com>
 
 	* pnic.c (pnic_check_duplex): remove
 	pnic.c (pnic_lnk_change, pnic_timer): use
@@ -326,13 +326,13 @@
 
 	(found by Manfred Spraul)
 
-2001-05-10  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-10  Jeff Garzik  <jgarzik@pobox.com>
 
 	* 21142.c, eeprom.c, tulip.h, tulip_core.c:
 	Remove DPRINTK as another, better method of
 	debug message printing is available.
 
-2001-05-09  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-09  Jeff Garzik  <jgarzik@pobox.com>
 
 	* 21142.c (t21142_lnk_change): Pass arg startup==1
 	to tulip_select_media, in order to force csr13 to be
@@ -344,32 +344,32 @@
 
 	* interrupt.c: Better PCI bus error reporting.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c: Now that dev->name is only available late
 	  in the probe, insert a hack to replace a not-evaluated
 	  "eth%d" string with an evaluated "tulip%d" string.
 	  Also, remove obvious comment and an indentation cleanup.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c: If we are a module, always print out the
 	  version string.  If we are built into the kernel, only print
 	  the version string if at least one tulip is detected.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	Merged from Becker's tulip.c 0.92t:
 
 	* tulip_core.c: Add support for Conexant LANfinity.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c: Only suspend/resume if the interface
 	  is up and running.  Use alloc_etherdev and pci_request_regions.
 	  Spelling fix.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c: Remove code that existed when one or more of
 	  the following defines existed.  These defines were never used
@@ -382,7 +382,7 @@
 	* media.c: Add barrier() to mdio_read/write's PNIC status check
 	  loops.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	Merged from Becker's tulip.c 0.92t:
 
@@ -399,20 +399,20 @@
 	  they are in mdio_read/write now.  Use mask to limit
 	  phy number in tulip_init_one's MII scan.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	Merged from Becker's tulip.c 0.92t:
 
 	* 21142.c, tulip_core.c: PNIC2 MAC address and NWay fixes.
 	* tulip.h: Add FullDuplex constant, used in above change.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	* timer.c: Do not call netif_carrier_{on,off}, it is not used in
 	  the main tree.  Leave code in, disabled, as markers for future
 	  carrier notification.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	Merged from Becker's tulip.c 0.92t, except for the tulip.h
 	whitespace cleanup:
@@ -431,14 +431,14 @@
 	  Prefer COMET_MAC_ADDR flag test to chip_id test in set_rx_mode.
 	  Store built mc_filter for later use in intr handler by Comets.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c: Use tp->cur_tx when building the
 	  setup frame, instead of assuming that the setup
 	  frame is always built in slot zero.  This case is
 	  hit during PM resume.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	* *.c: Update file headers (copyright, urls, etc.)
 	* Makefile: re-order to that chip-specific modules on own line
@@ -446,7 +446,7 @@
 	* tulip_core.c: merge medianame[] update from tulip.c.
 	  Additional arch-specific rx_copybreak, csr0 values. (various)
 
-2001-02-20  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-02-20  Jeff Garzik  <jgarzik@pobox.com>
 
 	* media.c (tulip_select_media): No need to initialize
 	new_csr6, all cases initialize it properly.
@@ -465,7 +465,7 @@
 	interrupt handler, as PNIC doesn't support a h/w timer.
 	* tulip_core.c (tulip_tbl[]): Modify default csr6
 
-2001-02-11  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-02-11  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (tulip_init_one): Call pci_enable_device
 	to ensure wakeup/resource assignment before checking those
@@ -474,30 +474,30 @@
 	(tulip_suspend, tulip_resume, tulip_remove_one): Call
 	pci_power_on/off (commented out for now).
 
-2001-02-10  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-02-10  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip.h: Add CFDD_xxx bits for Tulip power management
 	* tulip_core.c (tulip_set_power_state): New function,
 	manipulating Tulip chip power state where supported.
 	(tulip_up, tulip_down, tulip_init_one): Use it.
 
-2001-02-10  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-02-10  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (tulip_tx_timeout): Call netif_wake_queue
 	to ensure the next Tx is always sent to us.
 
-2001-01-27  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-01-27  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (tulip_remove_one): Fix mem leak by freeing
 	tp->media_tbl.  Add check for !dev, reformat code appropriately.
 
-2001-01-27  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-01-27  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_tbl[]: Comment all entries to make order and chip_id
 	relationship more clear.
 	* tulip_pci_tbl[]: Add new Accton PCI id (COMET chipset).
 
-2001-01-16  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-01-16  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c: static vars no longer explicitly
 	initialized to zero.
@@ -532,7 +532,7 @@
 	medianame[] and block_name[] arrays to avoid oops due
 	to bad values returned from hardware.
 
-2000-11-02  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2000-11-02  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (set_rx_mode): This is synchronized via
 	dev->xmit_lock, so only the queueing of the setup frame needs to
@@ -547,13 +547,13 @@
 	* tulip_core.c (tulip_init_ring, tulip_start_xmit, set_rx_mode):
 	Likewise.
 
-2000-10-18  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2000-10-18  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c: (tulip_init_one) Print out ethernet interface
 	on error.  Print out a message when pci_enable_device fails.
 	Handle DMA alloc failure.
 
-2000-10-18  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2000-10-18  Jeff Garzik  <jgarzik@pobox.com>
 
 	* Makefile: New file.
 	* tulip_core.c (tulip_init_one): Correct error messages
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tulip/eeprom.c linux-2.4.21/drivers/net/tulip/eeprom.c
--- linux-2.4.20/drivers/net/tulip/eeprom.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/tulip/eeprom.c	2002-12-18 18:58:07.000000000 +0000
@@ -1,7 +1,7 @@
 /*
 	drivers/net/tulip/eeprom.c
 
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001  The Linux Kernel Team
 	Written/copyright 1994-2001 by Donald Becker.
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tulip/interrupt.c linux-2.4.21/drivers/net/tulip/interrupt.c
--- linux-2.4.20/drivers/net/tulip/interrupt.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/tulip/interrupt.c	2002-12-18 18:58:05.000000000 +0000
@@ -1,7 +1,7 @@
 /*
 	drivers/net/tulip/interrupt.c
 
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001  The Linux Kernel Team
 	Written/copyright 1994-2001 by Donald Becker.
 
@@ -263,7 +263,7 @@
            This would turn on IM for devices that is not contributing
            to backlog congestion with unnecessary latency.
 
-           We monitor the the device RX-ring and have:
+           We monitor the device RX-ring and have:
 
            HW Interrupt Mitigation either ON or OFF.
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tulip/media.c linux-2.4.21/drivers/net/tulip/media.c
--- linux-2.4.20/drivers/net/tulip/media.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/net/tulip/media.c	2002-12-18 18:58:05.000000000 +0000
@@ -1,7 +1,7 @@
 /*
 	drivers/net/tulip/media.c
 
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001  The Linux Kernel Team
 	Written/copyright 1994-2001 by Donald Becker.
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tulip/pnic.c linux-2.4.21/drivers/net/tulip/pnic.c
--- linux-2.4.20/drivers/net/tulip/pnic.c	2001-11-09 21:45:35.000000000 +0000
+++ linux-2.4.21/drivers/net/tulip/pnic.c	2002-12-18 18:58:10.000000000 +0000
@@ -1,7 +1,7 @@
 /*
 	drivers/net/tulip/pnic.c
 
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001  The Linux Kernel Team
 	Written/copyright 1994-2001 by Donald Becker.
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tulip/pnic2.c linux-2.4.21/drivers/net/tulip/pnic2.c
--- linux-2.4.20/drivers/net/tulip/pnic2.c	2001-11-09 21:45:35.000000000 +0000
+++ linux-2.4.21/drivers/net/tulip/pnic2.c	2002-12-18 18:58:03.000000000 +0000
@@ -1,7 +1,7 @@
 /*
 	drivers/net/tulip/pnic2.c
 
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001  The Linux Kernel Team
 	Written/copyright 1994-2001 by Donald Becker.
         Modified to hep support PNIC_II by Kevin B. Hendricks
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tulip/timer.c linux-2.4.21/drivers/net/tulip/timer.c
--- linux-2.4.20/drivers/net/tulip/timer.c	2001-06-20 18:15:44.000000000 +0000
+++ linux-2.4.21/drivers/net/tulip/timer.c	2002-12-18 18:58:01.000000000 +0000
@@ -1,7 +1,7 @@
 /*
 	drivers/net/tulip/timer.c
 
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001  The Linux Kernel Team
 	Written/copyright 1994-2001 by Donald Becker.
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tulip/tulip_core.c linux-2.4.21/drivers/net/tulip/tulip_core.c
--- linux-2.4.20/drivers/net/tulip/tulip_core.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/tulip/tulip_core.c	2002-12-18 18:58:10.000000000 +0000
@@ -1,7 +1,7 @@
 /* tulip_core.c: A DEC 21x4x-family ethernet driver for Linux. */
 
 /*
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000-2002  The Linux Kernel Team
 	Written/copyright 1994-2001 by Donald Becker.
 
@@ -229,6 +229,7 @@
 	{ 0x1186, 0x1561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x1626, 0x8410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x1737, 0xAB09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+	{ 0x17B3, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x14f1, 0x1803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CONEXANT },
 	{ } /* terminate list */
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/via-rhine.c linux-2.4.21/drivers/net/via-rhine.c
--- linux-2.4.20/drivers/net/via-rhine.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/net/via-rhine.c	2002-12-18 18:58:08.000000000 +0000
@@ -98,11 +98,14 @@
  	- location of collision counter is chip specific
  	- allow selecting backoff algorithm (module parameter)
 
+	LK1.1.15 (jgarzik):
+	- Use new MII lib helper generic_mii_ioctl
+
 */
 
 #define DRV_NAME	"via-rhine"
-#define DRV_VERSION	"1.1.14"
-#define DRV_RELDATE	"May-3-2002"
+#define DRV_VERSION	"1.1.15"
+#define DRV_RELDATE	"November-22-2002"
 
 
 /* A few user-configurable values.
@@ -1794,10 +1797,10 @@
 
 
 static struct pci_driver via_rhine_driver = {
-	name:		"via-rhine",
-	id_table:	via_rhine_pci_tbl,
-	probe:		via_rhine_init_one,
-	remove:		__devexit_p(via_rhine_remove_one),
+	.name		= "via-rhine",
+	.id_table	= via_rhine_pci_tbl,
+	.probe		= via_rhine_init_one,
+	.remove		= __devexit_p(via_rhine_remove_one),
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/parport/ChangeLog linux-2.4.21/drivers/parport/ChangeLog
--- linux-2.4.20/drivers/parport/ChangeLog	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/parport/ChangeLog	2002-12-18 18:58:10.000000000 +0000
@@ -1,3 +1,7 @@
+2002-11-29  Tim Waugh  <twaugh@redhat.com>
+
+	* parport_pc.c: Fix ECP hang on Aladdin card.
+
 2002-04-25  Tim Waugh  <twaugh@redhat.com>
 
 	* parport_serial.c, parport_pc.c: Move some SIIG cards around.
@@ -278,7 +282,7 @@
 	* parport_pc.c (parport_pc_probe_port): Remove __devinit
 	attribute.  Export unconditionally.
 
-2001-04-14  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-14  Jeff Garzik  <jgarzik@pobox.com>
 
 	Merged:  2001-03-30  Tim Waugh  <twaugh@redhat.com>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/parport/parport_cs.c linux-2.4.21/drivers/parport/parport_cs.c
--- linux-2.4.20/drivers/parport/parport_cs.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.21/drivers/parport/parport_cs.c	2002-12-18 18:58:12.000000000 +0000
@@ -5,7 +5,7 @@
     (specifically, for the Quatech SPP-100 EPP card: other cards will
     probably require driver tweaks)
     
-    parport_cs.c 1.24 2001/10/13 14:04:05
+    parport_cs.c 1.29 2002/10/11 06:57:41
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -34,9 +34,7 @@
     
 ======================================================================*/
 
-
 #include <linux/kernel.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sched.h>
@@ -78,7 +76,7 @@
 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"parport_cs.c 1.24 2001/10/13 14:04:05 (David Hinds)";
+"parport_cs.c 1.29 2002/10/11 06:57:41 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -224,12 +222,6 @@
 #define CFG_CHECK(fn, args...) \
 if (CardServices(fn, args) != 0) goto next_entry
 
-static struct { u_int flag; char *name; } mode[] = {
-    { PARPORT_MODE_TRISTATE, "PS2" },
-    { PARPORT_MODE_EPP, "EPP" },
-    { PARPORT_MODE_ECP, "ECP" },
-};
-
 void parport_config(dev_link_t *link)
 {
     client_handle_t handle = link->handle;
@@ -241,7 +233,7 @@
     cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
     cistpl_cftable_entry_t dflt = { 0 };
     struct parport *p;
-    int i, last_ret, last_fn;
+    int last_ret, last_fn;
     
     DEBUG(0, "parport_config(0x%p)\n", link);
     
@@ -293,6 +285,9 @@
     CS_CHECK(RequestIRQ, handle, &link->irq);
     CS_CHECK(RequestConfiguration, handle, &link->conf);
 
+    release_region(link->io.BasePort1, link->io.NumPorts1);
+    if (link->io.NumPorts2)
+	release_region(link->io.BasePort2, link->io.NumPorts2);
     p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2,
 			      link->irq.AssignedIRQ, PARPORT_DMA_NONE,
 			      NULL);
@@ -312,15 +307,7 @@
     info->port = p;
     strcpy(info->node.dev_name, p->name);
     link->dev = &info->node;
-    printk(KERN_INFO "%s: PC-style PCMCIA at %#x", p->name,
-	   link->io.BasePort1);
-    if (link->io.NumPorts2)
-	printk(" & %#x", link->io.BasePort2);
-    printk(", irq %u [SPP", link->irq.AssignedIRQ);
-    for (i = 0; i < 5; i++)
-	if (p->modes & mode[i].flag) printk(",%s", mode[i].name);
-    printk("]\n");
-    
+
     link->state &= ~DEV_CONFIG_PENDING;
     return;
     
@@ -328,6 +315,7 @@
     cs_error(link->handle, last_fn, last_ret);
 failed:
     parport_cs_release((u_long)link);
+    link->state &= ~DEV_CONFIG_PENDING;
 
 } /* parport_config */
 
@@ -348,9 +336,12 @@
 
     if (info->ndev) {
 	struct parport *p = info->port;
-	parport_proc_unregister(p);
-	kfree(p->private_data);
-	parport_unregister_port(p);
+	parport_pc_unregister_port(p);
+	request_region(link->io.BasePort1, link->io.NumPorts1,
+		       info->node.dev_name);
+	if (link->io.NumPorts2)
+	    request_region(link->io.BasePort2, link->io.NumPorts2,
+			   info->node.dev_name);
     }
     info->ndev = 0;
     link->dev = NULL;
@@ -415,9 +406,8 @@
     if (serv.Revision != CS_RELEASE_CODE) {
 	printk(KERN_NOTICE "parport_cs: Card Services release "
 	       "does not match!\n");
-	return -1;
+	return -EINVAL;
     }
-
     register_pccard_driver(&dev_info, &parport_attach, &parport_detach);
     return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/parport/parport_pc.c linux-2.4.21/drivers/parport/parport_pc.c
--- linux-2.4.20/drivers/parport/parport_pc.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/parport/parport_pc.c	2002-12-18 18:58:07.000000000 +0000
@@ -2533,7 +2533,7 @@
 	return 0;
 }
 
-/* Via support maintained by Jeff Garzik <jgarzik@mandrakesoft.com> */
+/* Via support maintained by Jeff Garzik <jgarzik@pobox.com> */
 static int __devinit sio_via_686a_probe (struct pci_dev *pdev, int autoirq,
 					 int autodma)
 {
@@ -2766,7 +2766,7 @@
 	 * and 840 locks up if you write 1 to bit 2! */
 	/* oxsemi_954 */		{ 1, { { 0, -1 }, } },
 	/* oxsemi_840 */		{ 1, { { 0, -1 }, } },
-	/* aks_0100 */			{ 1, { { 0, 1 }, } },
+	/* aks_0100 */			{ 1, { { 0, -1 }, } },
 	/* mobility_pp */		{ 1, { { 0, 1 }, } },
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/pci/pci.c linux-2.4.21/drivers/pci/pci.c
--- linux-2.4.20/drivers/pci/pci.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/pci/pci.c	2002-12-18 18:58:05.000000000 +0000
@@ -163,6 +163,8 @@
  *  %PCI_CAP_ID_MSI          Message Signalled Interrupts
  *
  *  %PCI_CAP_ID_CHSWP        CompactPCI HotSwap 
+ *
+ *  %PCI_CAP_ID_PCIX         PCI-X
  */
 int
 pci_find_capability(struct pci_dev *dev, int cap)
@@ -930,14 +932,13 @@
 	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cache_size);
 	cache_size <<= 2;
 	if (cache_size != SMP_CACHE_BYTES) {
-		printk(KERN_WARNING "PCI: %s PCI cache line size set incorrectly "
-		       "(%i bytes) by BIOS/FW, ",
+		printk(KERN_WARNING "PCI: %s PCI cache line size set incorrectly (%i bytes) by BIOS/FW.\n",
 		       dev->slot_name, cache_size);
 		if (cache_size > SMP_CACHE_BYTES) {
-			printk("expecting %i\n", SMP_CACHE_BYTES);
+			printk("PCI: %s cache line size too large - expecting %i.\n", dev->slot_name, SMP_CACHE_BYTES);
 			rc = -EINVAL;
 		} else {
-			printk("correcting to %i\n", SMP_CACHE_BYTES);
+			printk("PCI: %s PCI cache line size corrected to %i.\n", dev->slot_name, SMP_CACHE_BYTES);
 			pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
 					      SMP_CACHE_BYTES >> 2);
 		}
@@ -1037,13 +1038,20 @@
 }
 
 /*
- * Find the extent of a PCI decode..
+ * Find the extent of a PCI decode, do sanity checks.
  */
-static u32 pci_size(u32 base, unsigned long mask)
+static u32 pci_size(u32 base, u32 maxbase, unsigned long mask)
 {
-	u32 size = mask & base;		/* Find the significant bits */
+	u32 size = mask & maxbase;	/* Find the significant bits */
+	if (!size)
+		return 0;
 	size = size & ~(size-1);	/* Get the lowest of them to find the decode size */
-	return size-1;			/* extent = size - 1 */
+	size -= 1;			/* extent = size - 1 */
+	if (base == maxbase && ((base | size) & mask) != mask)
+		return 0;		/* base == maxbase can be valid only
+					   if the BAR has been already
+					   programmed with all 1s */
+	return size;
 }
 
 static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
@@ -1066,13 +1074,17 @@
 		if (l == 0xffffffff)
 			l = 0;
 		if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
+			sz = pci_size(l, sz, PCI_BASE_ADDRESS_MEM_MASK);
+			if (!sz)
+				continue;
 			res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
 			res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
-			sz = pci_size(sz, PCI_BASE_ADDRESS_MEM_MASK);
 		} else {
+			sz = pci_size(l, sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff);
+			if (!sz)
+				continue;
 			res->start = l & PCI_BASE_ADDRESS_IO_MASK;
 			res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK;
-			sz = pci_size(sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff);
 		}
 		res->end = res->start + (unsigned long) sz;
 		res->flags |= pci_calc_resource_flags(l);
@@ -1102,6 +1114,7 @@
 	if (rom) {
 		dev->rom_base_reg = rom;
 		res = &dev->resource[PCI_ROM_RESOURCE];
+		res->name = dev->name;
 		pci_read_config_dword(dev, rom, &l);
 		pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE);
 		pci_read_config_dword(dev, rom, &sz);
@@ -1109,13 +1122,14 @@
 		if (l == 0xffffffff)
 			l = 0;
 		if (sz && sz != 0xffffffff) {
+			sz = pci_size(l, sz, PCI_ROM_ADDRESS_MASK);
+			if (!sz)
+				return;
 			res->flags = (l & PCI_ROM_ADDRESS_ENABLE) |
 			  IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
 			res->start = l & PCI_ROM_ADDRESS_MASK;
-			sz = pci_size(sz, PCI_ROM_ADDRESS_MASK);
 			res->end = res->start + (unsigned long) sz;
 		}
-		res->name = dev->name;
 	}
 }
 
@@ -2153,6 +2167,8 @@
 EXPORT_SYMBOL(pci_do_scan_bus);
 EXPORT_SYMBOL(pci_scan_slot);
 EXPORT_SYMBOL(pci_scan_bus);
+EXPORT_SYMBOL(pci_scan_device);
+EXPORT_SYMBOL(pci_read_bridge_bases);
 #ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(pci_proc_attach_device);
 EXPORT_SYMBOL(pci_proc_detach_device);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/pci/pci.ids linux-2.4.21/drivers/pci/pci.ids
--- linux-2.4.20/drivers/pci/pci.ids	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/pci/pci.ids	2002-12-18 18:58:01.000000000 +0000
@@ -582,6 +582,7 @@
 	6003  CS 4614/22/24 [CrystalClear SoundFusion Audio Accelerator]
 		1013 4280  Crystal SoundFusion PCI Audio Accelerator
 		1681 0050  Hercules Game Theater XP
+		1681 a011  Hercules Fortissimo III 7.1
 	6004  CS 4614/22/24 [CrystalClear SoundFusion Audio Accelerator]
 	6005  Crystal CS4281 PCI Audio
 		1013 4281  Crystal CS4281 PCI Audio
@@ -2617,6 +2618,7 @@
 10fc  I-O Data Device, Inc.
 # What's in the cardbus end of a Sony ACR-A01 card, comes with newer Vaio CD-RW drives
 	0003  Cardbus IDE Controller
+	0005  Cardbus SCSI CBSC II
 10fd  Soyo Computer, Inc
 10fe  Fast Multimedia AG
 10ff  NCube
@@ -2678,6 +2680,7 @@
 	0505  VT82C505
 	0561  VT82C561
 	0571  VT82C586B PIPC Bus Master IDE
+		1458 5002 GA-7VAX Mainboard
 	0576  VT82C576 3V [Apollo Master]
 	0585  VT82C585VP [Apollo VP1/VPX]
 	0586  VT82C586/A/B PCI-to-ISA [Apollo VP]
@@ -2726,6 +2729,7 @@
 		1462 3091  MS-6309 Onboard Audio
 		15dd 7609  Onboard Audio
 	3059  VT8233 AC97 Audio Controller
+		1458 a002  GA-7VAX Onboard Audio (Realtek ALC650) 
 	3065  VT6102 [Rhine-II]
 		1186 1400  DFE-530TX rev A
 		1186 1401  DFE-530TX rev B
@@ -2739,6 +2743,7 @@
 	3102  VT8662 Host Bridge
 	3103  VT8615 Host Bridge
 	3104  USB 2.0
+		1458 5004  GA-7VAX Mainboard
 	3109  VT8233C PCI to ISA Bridge
 	3112  VT8361 [KLE133] Host Bridge
 	3128  VT8753 [P4X266 AGP]
@@ -2747,6 +2752,9 @@
 	3148  P4M266 Host Bridge
 	3156  P/KN266 Host Bridge
 	3177  VT8233A ISA Bridge
+		1458 5001 GA-7VAX Mainboard
+	3189  VT8377 [KT400 AGP] Host Bridge
+		1458 5000 GA-7VAX Mainboard
 	5030  VT82C596 ACPI [Apollo PRO]
 	6100  VT85C100A [Rhine II]
 	8231  VT8231 [PCI-to-ISA Bridge]
@@ -2767,6 +2775,7 @@
 	b102  VT8362 AGP Bridge
 	b103  VT8615 AGP Bridge
 	b112  VT8361 [KLE133] AGP Bridge
+	b168  VT8235 PCI Bridge
 1107  Stratus Computers
 	0576  VIA VT82C570MV [Apollo] (Wrong vendor ID!)
 1108  Proteon, Inc.
@@ -3027,6 +3036,12 @@
 1144  Cincinnati Milacron
 	0001  Noservo controller
 1145  Workbit Corporation
+	f007  NinjaSCSI-32 KME
+	8007  NinjaSCSI-32 Workbit
+	f010  NinjaSCSI-32 Workbit
+	f012  NinjaSCSI-32 Logitec
+	f013  NinjaSCSI-32 Logitec
+	f015  NinjaSCSI-32 Melco
 1146  Force Computers
 1147  Interface Corp
 1148  Syskonnect (Schneider & Koch)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/pci/quirks.c linux-2.4.21/drivers/pci/quirks.c
--- linux-2.4.20/drivers/pci/quirks.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/pci/quirks.c	2002-12-18 18:58:02.000000000 +0000
@@ -167,6 +167,21 @@
 	}
 }
 
+/*
+ *	Ali Magik requires workarounds to be used by the drivers
+ *	that DMA to AGP space. Latency must be set to 0xA and triton
+ *	workaround applied too
+ *	[Info kindly provided by ALi]
+ */	
+ 
+static void __init quirk_alimagik(struct pci_dev *dev)
+{
+	if((pci_pci_problems&PCIPCI_ALIMAGIK)==0)
+	{
+		printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
+		pci_pci_problems|=PCIPCI_ALIMAGIK|PCIPCI_TRITON;
+	}
+}
 
 /*
  *	Natoma has some interesting boundary conditions with Zoran stuff
@@ -212,6 +227,19 @@
 }	
 
 /*
+ *	ATI Northbridge setups MCE the processor if you even
+ *	read somewhere between 0x3b0->0x3bb or read 0x3d3
+ */
+ 
+static void __devinit quirk_ati_exploding_mce(struct pci_dev *dev)
+{
+	printk(KERN_INFO "ATI Northbridge, reserving I/O ports 0x3b0 to 0x3bb.\n");
+	/* Mae rhaid in i beidio a edrych ar y lleoliad I/O hyn */
+	request_region(0x3b0, 0x0C, "RadeonIGP");
+	request_region(0x3d3, 0x01, "RadeonIGP");
+}
+
+/*
  * Let's make the southbridge information explicit instead
  * of having to worry about people probing the ACPI areas,
  * for example.. (Yes, it happens, and if you read the wrong
@@ -521,6 +549,8 @@
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443BX_0, 	quirk_natoma }, 
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443BX_1, 	quirk_natoma }, 
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443BX_2, 	quirk_natoma },
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_AL, 	PCI_DEVICE_ID_AL_M1647, 	quirk_alimagik },
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_AL, 	PCI_DEVICE_ID_AL_M1651, 	quirk_alimagik },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5597,		quirk_nopcipci },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_496,		quirk_nopcipci },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8363_0,	quirk_vialatency },
@@ -548,6 +578,7 @@
 
 	{ PCI_FIXUP_FINAL, 	PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_VIPER_7410,	quirk_amd_ioapic },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering },
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_ATI,	PCI_DEVICE_ID_ATI_RADEON_IGP,   quirk_ati_exploding_mce },
 	/*
 	 * i82380FB mobile docking controller: its PCI-to-PCI bridge
 	 * is subtractive decoding (transparent), and does indicate this
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/pcmcia/cardbus.c linux-2.4.21/drivers/pcmcia/cardbus.c
--- linux-2.4.20/drivers/pcmcia/cardbus.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/pcmcia/cardbus.c	2002-12-18 18:58:05.000000000 +0000
@@ -2,7 +2,7 @@
   
     Cardbus device configuration
     
-    cardbus.c 1.63 1999/11/08 20:47:02
+    cardbus.c 1.87 2002/10/24 06:11:41
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -175,8 +175,8 @@
     
 =====================================================================*/
 
-void read_cb_mem(socket_info_t * s, u_char fn, int space,
-		 u_int addr, u_int len, void *ptr)
+int read_cb_mem(socket_info_t * s, u_char fn, int space,
+		u_int addr, u_int len, void *ptr)
 {
 	struct pci_dev *dev;
 	struct resource *res;
@@ -194,7 +194,7 @@
 			goto fail;
 		for (; len; addr++, ptr++, len--)
 			pci_readb(dev, addr, (u_char *) ptr);
-		return;
+		return 0;
 	}
 
 	res = dev->resource + space - 1;
@@ -214,13 +214,197 @@
 		goto fail;
 
 	memcpy_fromio(ptr, s->cb_cis_virt + addr, len);
-	return;
+	return 0;
 
 fail:
 	memset(ptr, 0xff, len);
-	return;
+	return -1;
 }
 
+struct pci_dev *cb_scan_slot(struct pci_dev *temp, struct list_head *list)
+{
+	struct pci_bus *bus = temp->bus;
+	struct pci_dev *dev;
+	struct pci_dev *first_dev = NULL;
+	int func = 0;
+	int is_multi = 0;
+	u8 hdr_type;
+
+	for (func = 0; func < 8; func++, temp->devfn++) {
+		if (func && !is_multi)		/* not a multi-function device */
+			continue;
+		if (pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type))
+			continue;
+		temp->hdr_type = hdr_type & 0x7f;
+
+		dev = pci_scan_device(temp);
+		if (!dev)
+			continue;
+		sprintf(dev->name, "PCI device %04x:%04x", dev->vendor, dev->device);
+		if (!func) {
+			is_multi = hdr_type & 0x80;
+			first_dev = dev;
+		}
+
+		list_add_tail(&dev->global_list, list);
+		/* Fix up broken headers */
+//FIXME		pci_fixup_device(PCI_FIXUP_HEADER, dev);
+	}
+	return first_dev;
+}
+
+static unsigned int cb_scan_new_bus(struct pci_bus *bus, int irq);
+
+static int cb_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int irq)
+{
+	unsigned int buses;
+	unsigned short cr;
+	struct pci_bus *child;
+	int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
+
+	pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
+	printk("Scanning behind PCI bridge %s, config %06x\n", dev->slot_name, buses & 0xffffff);
+	/*
+	 * We need to assign a number to this bus which we always
+	 * do in the second pass. We also keep all address decoders
+	 * on the bridge disabled during scanning.  FIXME: Why?
+	 */
+	pci_read_config_word(dev, PCI_COMMAND, &cr);
+	pci_write_config_word(dev, PCI_COMMAND, 0x0000);
+	pci_write_config_word(dev, PCI_STATUS, 0xffff);
+
+	child = pci_add_new_bus(bus, dev, ++max);
+	buses = (buses & 0xff000000)
+	      | ((unsigned int)(child->primary)     <<  0)
+	      | ((unsigned int)(child->secondary)   <<  8)
+	      | ((unsigned int)(child->subordinate) << 16);
+	/*
+	 * We need to blast all three values with a single write.
+	 */
+	pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
+	if (!is_cardbus) {
+		/* Now we can scan all subordinate buses... */
+		max = cb_scan_new_bus(child, irq);
+	} else {
+		/*
+		 * For CardBus bridges, we leave 4 bus numbers
+		 * as cards with a PCI-to-PCI bridge can be
+		 * inserted later.
+		 */
+		max += 3;
+	}
+	/*
+	 * Set the subordinate bus number to its real value.
+	 */
+	child->subordinate = max;
+	pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
+	pci_write_config_word(dev, PCI_COMMAND, cr);
+	sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
+	return max;
+}
+
+static unsigned int cb_scan_new_bus(struct pci_bus *bus, int irq)
+{
+	unsigned int devfn, max;
+	struct list_head *ln, *ln_tmp;
+	struct pci_dev *dev, dev0;
+	struct list_head found;
+	
+	INIT_LIST_HEAD(&found);
+	
+	printk("Scanning bus %02x\n", bus->number);
+	max = bus->secondary;
+
+	/* Create a device template */
+	memset(&dev0, 0, sizeof(dev0));
+	dev0.bus = bus;
+	dev0.sysdata = bus->sysdata;
+
+	/* Go find them, Rover! */
+	for (devfn = 0; devfn < 0x100; devfn += 8) {
+		dev0.devfn = devfn;
+		cb_scan_slot(&dev0, &found);
+	}
+
+	/*
+	 * After performing arch-dependent fixup of the bus, look behind
+	 * all PCI-to-PCI bridges on this bus.
+	 */
+	printk("Fixups for bus %02x\n", bus->number);
+	pci_read_bridge_bases(bus);
+
+	list_for_each_safe(ln, ln_tmp, &found)
+	{
+		int i;
+		u8 irq_pin;
+		dev = pci_dev_g(ln);
+		pci_set_power_state(dev, 0);
+		for(i=0;i<6;i++)
+		{
+			struct resource *r = dev->resource + i;
+			if(!r->start && r->end)
+				pci_assign_resource(dev, i);
+		}
+		/* Does this function have an interrupt at all? */
+		pci_readb(dev, PCI_INTERRUPT_PIN, &irq_pin);
+		if (irq_pin) {
+			dev->irq = irq;
+			pci_writeb(dev, PCI_INTERRUPT_LINE, irq);
+		}
+
+		pci_enable_device(dev); /* XXX check return */
+		pci_insert_device(dev, bus);
+		if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+			max = cb_scan_bridge(bus, dev, max, irq);
+	}
+
+	/*
+	 * We've scanned the bus and so we know all about what's on
+	 * the other side of any bridges that may be on this bus plus
+	 * any devices.
+	 *
+	 * Return how far we've got finding sub-buses.
+	 */
+	printk("Bus scan for %02x returning with max=%02x\n", bus->number, max);
+	return max;
+}
+
+static int program_bridge(struct pci_dev *bridge)
+{
+	u32 l;
+	
+	/* Set up the top and bottom of the PCI I/O segment for this bus. */
+	pci_read_config_dword(bridge, PCI_IO_BASE, &l);
+	l &= 0xffff0000;
+	l |= (bridge->resource[7].start >> 8) & 0x00f0;
+	l |= bridge->resource[7].end & 0xf000;
+	pci_write_config_dword(bridge, PCI_IO_BASE, l);
+
+	/* Clear upper 16 bits of I/O base/limit. */
+	pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0);
+
+	/* Clear out the upper 32 bits of PREF base/limit. */
+	pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
+	pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
+
+	/* Set up the top and bottom of the PCI Memory segment
+	   for this bus. */
+	l = (bridge->resource[8].start >> 16) & 0xfff0;
+	l |= bridge->resource[8].end & 0xfff00000;
+	pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
+
+	/* Set up PREF base/limit. */
+	l = (bridge->resource[9].start >> 16) & 0xfff0;
+	l |= bridge->resource[9].end & 0xfff00000;
+	pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
+
+	/* FIXME - 0x0c if our ISA VGA is behind it. It looks like X
+	   can handle this itself - CHECK */
+	l = 0x04;
+	pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, l);
+}
+
+
 /*=====================================================================
 
     cb_alloc() and cb_free() allocate and free the kernel data
@@ -280,14 +464,57 @@
 		dev->hdr_type = hdr & 0x7f;
 
 		pci_setup_device(dev);
-
-		/* FIXME: Do we need to enable the expansion ROM? */
-		for (r = 0; r < 7; r++) {
-			struct resource *res = dev->resource + r;
-			if (res->flags)
-				pci_assign_resource(dev, r);
+		
+		if(dev->hdr_type == 1)
+		{
+			int max = bus->secondary;
+			int idx;
+			struct resource *res, *pres;
+			printk(KERN_INFO "Cardbus: Bridge found - we suck.\n");
+			pci_read_bridge_bases(bus);
+			for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_BRIDGE_RESOURCES + 3; idx++) {
+				res = &dev->resource[idx];
+				/* This is ugly - pci_read_bridge_bases should have
+				   done it for us. Need to find out why it doesnt
+				   before fixing it */
+				if(idx == PCI_BRIDGE_RESOURCES) 
+					res->flags = IORESOURCE_IO | PCI_IO_RANGE_TYPE_32;
+				if(idx == PCI_BRIDGE_RESOURCES+1)
+					res->flags |= IORESOURCE_MEM;
+				if(idx == PCI_BRIDGE_RESOURCES+2)
+					res->flags |= IORESOURCE_MEM|IORESOURCE_PREFETCH;
+				/* Ignore any existing values in the chip */
+				res->start = 0;
+				/* Find the parent resource */
+				pres = pci_find_parent_resource(dev, res);
+				if(!pres)
+				{
+					printk(KERN_ERR "No parent resource for %lx\n", res->flags);
+					continue;
+				}
+				printk(KERN_ERR "Allocating for type %lx, in bus resource.\n", res->flags);
+				/* Hog the entire space */
+				res->start = pres->start;
+				if(idx != PCI_BRIDGE_RESOURCES)
+					res->end = pres->end;
+				else	/* Still working this out - FIXME */
+					res->end = res->start + 255;
+				if (!pres || request_resource(pres, res) < 0)
+					printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name);
+			}
+			program_bridge(dev);
+			max = cb_scan_bridge(bus, dev, max, irq);
+			printk(KERN_INFO "Cardbus: Bridge scanned.\n");
+		}
+		else
+		{			
+			/* FIXME: Do we need to enable the expansion ROM? */
+			for (r = 0; r < 7; r++) {
+				struct resource *res = dev->resource + r;
+				if (res->flags)
+					pci_assign_resource(dev, r);
+			}
 		}
-
 		/* Does this function have an interrupt at all? */
 		pci_readb(dev, PCI_INTERRUPT_PIN, &irq_pin);
 		if (irq_pin) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/pcmcia/cistpl.c linux-2.4.21/drivers/pcmcia/cistpl.c
--- linux-2.4.20/drivers/pcmcia/cistpl.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.21/drivers/pcmcia/cistpl.c	2002-12-18 18:58:06.000000000 +0000
@@ -2,7 +2,7 @@
 
     PCMCIA Card Information Structure parser
 
-    cistpl.c 1.97 2001/10/04 03:33:49
+    cistpl.c 1.99 2002/10/24 06:11:48
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -109,8 +109,8 @@
     }
 }
 
-void read_cis_mem(socket_info_t *s, int attr, u_int addr,
-		  u_int len, void *ptr)
+int read_cis_mem(socket_info_t *s, int attr, u_int addr,
+		 u_int len, void *ptr)
 {
     pccard_mem_map *mem = &s->cis_mem;
     u_char *sys, *buf = ptr;
@@ -118,7 +118,7 @@
     DEBUG(3, "cs: read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
     if (setup_cis_mem(s) != 0) {
 	memset(ptr, 0xff, len);
-	return;
+	return -1;
     }
     mem->flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
 
@@ -156,6 +156,7 @@
     DEBUG(3, "cs:  %#2.2x %#2.2x %#2.2x %#2.2x ...\n",
 	  *(u_char *)(ptr+0), *(u_char *)(ptr+1),
 	  *(u_char *)(ptr+2), *(u_char *)(ptr+3));
+    return 0;
 }
 
 void write_cis_mem(socket_info_t *s, int attr, u_int addr,
@@ -270,7 +271,7 @@
 	if (find_mem_region(&s->cis_mem.sys_start, s->cap.map_size,
 			    s->cap.map_size, low, "card services", s)) {
 	    printk(KERN_NOTICE "cs: unable to map card memory!\n");
-	    return CS_OUT_OF_RESOURCE;
+	    return -1;
 	}
 	s->cis_mem.sys_stop = s->cis_mem.sys_start+s->cap.map_size-1;
 	s->cis_virt = bus_ioremap(s->cap.bus, s->cis_mem.sys_start,
@@ -303,7 +304,7 @@
 static void read_cis_cache(socket_info_t *s, int attr, u_int addr,
 			   u_int len, void *ptr)
 {
-    int i;
+    int i, ret;
     char *caddr;
 
     if (s->fake_cis) {
@@ -326,12 +327,12 @@
     }
 #ifdef CONFIG_CARDBUS
     if (s->state & SOCKET_CARDBUS)
-	read_cb_mem(s, 0, attr, addr, len, ptr);
+	ret = read_cb_mem(s, 0, attr, addr, len, ptr);
     else
 #endif
-	read_cis_mem(s, attr, addr, len, ptr);
+	ret = read_cis_mem(s, attr, addr, len, ptr);
     /* Copy data into the cache, if there is room */
-    if ((i < MAX_CIS_TABLE) &&
+    if ((ret == 0) && (i < MAX_CIS_TABLE) &&
 	(caddr+len < s->cis_cache+MAX_CIS_DATA)) {
 	s->cis_table[i].addr = addr;
 	s->cis_table[i].len = len;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/pcmcia/cs_internal.h linux-2.4.21/drivers/pcmcia/cs_internal.h
--- linux-2.4.20/drivers/pcmcia/cs_internal.h	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.21/drivers/pcmcia/cs_internal.h	2002-12-18 18:58:01.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * cs_internal.h 1.54 2000/10/26 20:10:55
+ * cs_internal.h 1.57 2002/10/24 06:11:43
  *
  * The contents of this file are subject to the Mozilla Public License
  * Version 1.1 (the "License"); you may not use this file except in
@@ -202,13 +202,13 @@
 void cb_release(socket_info_t *s);
 void cb_enable(socket_info_t *s);
 void cb_disable(socket_info_t *s);
-void read_cb_mem(socket_info_t *s, u_char fn, int space,
-		 u_int addr, u_int len, void *ptr);
+int read_cb_mem(socket_info_t *s, u_char fn, int space,
+		u_int addr, u_int len, void *ptr);
 void cb_release_cis_mem(socket_info_t *s);
 
 /* In cistpl.c */
-void read_cis_mem(socket_info_t *s, int attr,
-		  u_int addr, u_int len, void *ptr);
+int read_cis_mem(socket_info_t *s, int attr,
+		 u_int addr, u_int len, void *ptr);
 void write_cis_mem(socket_info_t *s, int attr,
 		   u_int addr, u_int len, void *ptr);
 void release_cis_mem(socket_info_t *s);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/pcmcia/ricoh.h linux-2.4.21/drivers/pcmcia/ricoh.h
--- linux-2.4.20/drivers/pcmcia/ricoh.h	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/pcmcia/ricoh.h	2002-12-18 18:58:08.000000000 +0000
@@ -75,6 +75,12 @@
 #define RL5C46X_BCR_3E0_ENA		0x0800
 #define RL5C46X_BCR_3E2_ENA		0x1000
 
+/* Bridge Configuration Register */
+#define RL5C4XX_CONFIG			0x80	/* 16 bit */
+#define  RL5C4XX_CONFIG_IO_1_MODE	0x0200
+#define  RL5C4XX_CONFIG_IO_0_MODE	0x0100
+#define  RL5C4XX_CONFIG_PREFETCH	0x0001
+
 /* Misc Control Register */
 #define RL5C4XX_MISC			0x0082	/* 16 bit */
 #define  RL5C4XX_MISC_HW_SUSPEND_ENA	0x0002
@@ -119,6 +125,7 @@
 #define rl_ctl(socket)		((socket)->private[1])
 #define rl_io(socket)		((socket)->private[2])
 #define rl_mem(socket)		((socket)->private[3])
+#define rl_config(socket)	((socket)->private[4])
 
 /*
  * Magic Ricoh initialization code.. Save state at
@@ -130,9 +137,17 @@
 	rl_ctl(socket) = config_readw(socket, RL5C4XX_16BIT_CTL);
 	rl_io(socket) = config_readw(socket, RL5C4XX_16BIT_IO_0);
 	rl_mem(socket) = config_readw(socket, RL5C4XX_16BIT_MEM_0);
+	rl_config(socket) = config_readw(socket, RL5C4XX_CONFIG);
 
 	/* Set the default timings, don't trust the original values */
 	rl_ctl(socket) = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING;
+
+	if(socket->dev->device < PCI_DEVICE_ID_RICOH_RL5C475) {
+		rl_ctl(socket) |= RL5C46X_16CTL_LEVEL_1 | RL5C46X_16CTL_LEVEL_2;
+	} else {
+		rl_config(socket) |= RL5C4XX_CONFIG_PREFETCH;
+	}
+
 	return 0;
 }
 
@@ -174,6 +189,7 @@
 	config_writew(socket, RL5C4XX_16BIT_CTL, rl_ctl(socket));
 	config_writew(socket, RL5C4XX_16BIT_IO_0, rl_io(socket));
 	config_writew(socket, RL5C4XX_16BIT_MEM_0, rl_mem(socket));
+	config_writew(socket, RL5C4XX_CONFIG, rl_config(socket));
 
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/pcmcia/sa1100_generic.c linux-2.4.21/drivers/pcmcia/sa1100_generic.c
--- linux-2.4.20/drivers/pcmcia/sa1100_generic.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/pcmcia/sa1100_generic.c	2002-12-18 18:58:10.000000000 +0000
@@ -47,7 +47,6 @@
 #include <linux/notifier.h>
 #include <linux/proc_fs.h>
 #include <linux/version.h>
-#include <linux/cpufreq.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/pcmcia/yenta.c linux-2.4.21/drivers/pcmcia/yenta.c
--- linux-2.4.20/drivers/pcmcia/yenta.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/pcmcia/yenta.c	2002-12-18 18:58:10.000000000 +0000
@@ -2,6 +2,11 @@
  * Regular lowlevel cardbus driver ("yenta")
  *
  * (C) Copyright 1999, 2000 Linus Torvalds
+ *
+ * Changelog:
+ * Aug 2002: Manfred Spraul <manfred@colorfullife.com>
+ * 	Dynamically adjust the size of the bridge resource
+ * 	
  */
 #include <linux/init.h>
 #include <linux/pci.h>
@@ -704,6 +709,15 @@
 	return 0;
 }
 
+/*
+ * Use an adaptive allocation for the memory resource,
+ * sometimes the size behind pci bridges is limited:
+ * 1/8 of the size of the io window of the parent.
+ * max 4 MB, min 16 kB.
+ */
+#define BRIDGE_SIZE_MAX	4*1024*1024
+#define BRIDGE_SIZE_MIN	16*1024
+
 static void yenta_allocate_res(pci_socket_t *socket, int nr, unsigned type)
 {
 	struct pci_bus *bus;
@@ -735,21 +749,42 @@
 	if (start && end > start) {
 		res->start = start;
 		res->end = end;
-		request_resource(root, res);
-		return;
+		if (request_resource(root, res) == 0)
+			return;
+		printk(KERN_INFO "yenta %s: Preassigned resource %d busy, reconfiguring...\n",
+				socket->dev->slot_name, nr);
+		res->start = res->end = 0;
 	}
 
-	align = size = 4*1024*1024;
-	min = PCIBIOS_MIN_MEM; max = ~0U;
 	if (type & IORESOURCE_IO) {
 		align = 1024;
 		size = 256;
 		min = 0x4000;
 		max = 0xffff;
+	} else {
+		unsigned long avail = root->end - root->start;
+		int i;
+		align = size = BRIDGE_SIZE_MAX;
+		if (size > avail/8) {
+			size=(avail+1)/8;
+			/* round size down to next power of 2 */
+			i = 0;
+			while ((size /= 2) != 0)
+				i++;
+			size = 1 << i;
+		}
+		if (size < BRIDGE_SIZE_MIN)
+			size = BRIDGE_SIZE_MIN;
+		align = size;
+		min = PCIBIOS_MIN_MEM; max = ~0U;
 	}
 		
-	if (allocate_resource(root, res, size, min, max, align, NULL, NULL) < 0)
+	if (allocate_resource(root, res, size, min, max, align, NULL, NULL) < 0) {
+		printk(KERN_INFO "yenta %s: no resource of type %x available, trying to continue...\n",
+				socket->dev->slot_name, type);
+		res->start = res->end = 0;
 		return;
+	}
 
 	config_writel(socket, offset, res->start);
 	config_writel(socket, offset+4, res->end);
@@ -767,6 +802,20 @@
 }
 
 /*
+ * Free the bridge mappings for the device..
+ */
+static void yenta_free_resources(pci_socket_t *socket)
+{
+	int i;
+	for (i=0;i<4;i++) {
+		struct resource *res;
+		res = socket->dev->resource + PCI_BRIDGE_RESOURCES + i;
+		if (res->start != 0 && res->end != 0)
+			release_resource(res);
+		res->start = res->end = 0;
+	}
+}
+/*
  * Close it down - release our resources and go home..
  */
 static void yenta_close(pci_socket_t *sock)
@@ -782,6 +831,7 @@
 
 	if (sock->base)
 		iounmap(sock->base);
+	yenta_free_resources(sock);
 }
 
 #include "ti113x.h"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/s390/block/dasd.c linux-2.4.21/drivers/s390/block/dasd.c
--- linux-2.4.20/drivers/s390/block/dasd.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/s390/block/dasd.c	2002-12-18 18:58:08.000000000 +0000
@@ -1315,9 +1315,9 @@
 /*
  * DASD_TERM_IO
  *
- * attempts to terminate the the current IO and set it to failed if termination
+ * Attempts to terminate the current IO and set it to failed if termination
  * was successful.
- * returns an appropriate return code
+ * Returns an appropriate return code.
  */
 int
 dasd_term_IO (ccw_req_t * cqr)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/s390/block/dasd_3990_erp.c linux-2.4.21/drivers/s390/block/dasd_3990_erp.c
--- linux-2.4.20/drivers/s390/block/dasd_3990_erp.c	2002-02-25 19:38:03.000000000 +0000
+++ linux-2.4.21/drivers/s390/block/dasd_3990_erp.c	2002-12-18 18:58:11.000000000 +0000
@@ -2712,10 +2712,10 @@
  * DASD_3990_ERP_ERROR_MATCH
  *
  * DESCRIPTION
- *   check if the the device status of the given cqr is the same.
+ *   Check if the device status of the given cqr is the same.
  *   This means that the failed CCW and the relevant sense data
  *   must match.
- *   I don't distinguish between 24 and 32 byte sense becaus in case of
+ *   I don't distinguish between 24 and 32 byte sense because in case of
  *   24 byte sense byte 25 and 27 is set as well.
  *
  * PARAMETER
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/s390/s390io.c linux-2.4.21/drivers/s390/s390io.c
--- linux-2.4.20/drivers/s390/s390io.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/s390/s390io.c	2002-12-18 18:58:04.000000000 +0000
@@ -8607,7 +8607,7 @@
 cio_ignore_proc_write (struct file *file, const char *user_buf,
 		       size_t user_len, loff_t * offset)
 {
-	char *buffer
+	char *buffer;
 	
 	if(user_len > 65536)
 		user_len = 65536;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sbus/char/display7seg.c linux-2.4.21/drivers/sbus/char/display7seg.c
--- linux-2.4.20/drivers/sbus/char/display7seg.c	2001-10-11 06:42:47.000000000 +0000
+++ linux-2.4.21/drivers/sbus/char/display7seg.c	2002-12-18 18:58:04.000000000 +0000
@@ -198,6 +198,7 @@
 	if (0 != iTmp) {
 		printk("%s: unable to acquire miscdevice minor %i\n",
 		       D7S_DEVNAME, D7S_MINOR);
+		iounmap(d7s_regs);
 		return iTmp;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/Config.in linux-2.4.21/drivers/scsi/Config.in
--- linux-2.4.20/drivers/scsi/Config.in	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/scsi/Config.in	2002-12-18 18:58:07.000000000 +0000
@@ -204,6 +204,7 @@
 if [ "$CONFIG_X86" = "y" ]; then
    dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
 fi
+dep_tristate 'Workbit NinjaSCSI-32Bi/UDE support' CONFIG_SCSI_NSP32 $CONFIG_SCSI
 #
 # Note - this is a very special 'host' adapter that simulates the presence of some disks.
 # It can come in very handy for troubleshooting.  Anyone else is welcome to use it - all
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/Makefile linux-2.4.21/drivers/scsi/Makefile
--- linux-2.4.20/drivers/scsi/Makefile	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/scsi/Makefile	2002-12-18 18:58:05.000000000 +0000
@@ -127,6 +127,7 @@
 obj-$(CONFIG_SCSI_FCAL)		+= fcal.o
 obj-$(CONFIG_SCSI_CPQFCTS)	+= cpqfc.o
 obj-$(CONFIG_SCSI_LASI700)	+= lasi700.o 53c700.o
+obj-$(CONFIG_SCSI_NSP32)	+= nsp32.o
 
 subdir-$(CONFIG_ARCH_ACORN)	+= ../acorn/scsi
 obj-$(CONFIG_ARCH_ACORN)	+= ../acorn/scsi/acorn-scsi.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/aacraid/linit.c linux-2.4.21/drivers/scsi/aacraid/linit.c
--- linux-2.4.20/drivers/scsi/aacraid/linit.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/scsi/aacraid/linit.c	2002-12-18 18:58:02.000000000 +0000
@@ -59,7 +59,7 @@
 #define AAC_DRIVERNAME	"aacraid"
 
 MODULE_AUTHOR("Red Hat Inc and Adaptec");
-MODULE_DESCRIPTION("Supports Dell PERC2, 2/Si, 3/Si, 3/Di, Adaptec 2120S, 2200S, 5400S, and HP NetRAID-4M devices. http://domsch.com/linux/ or http://linux.adaptec.com");
+MODULE_DESCRIPTION("Supports Dell PERC2, 2/Si, 3/Si, 3/Di, PERC 320/DC, Adaptec 2120S, 2200S, 5400S, and HP NetRAID-4M devices. http://domsch.com/linux/ or http://linux.adaptec.com");
 MODULE_LICENSE("GPL");
 MODULE_PARM(nondasd, "i");
 MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on");
@@ -95,6 +95,7 @@
 	{ 0x9005, 0x0285, 0x9005, 0x0286, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2120S   ", 1 }, /* Adaptec 2120S (Crusader)*/
 	{ 0x9005, 0x0285, 0x9005, 0x0285, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2 }, /* Adaptec 2200S (Vulcan)*/
 	{ 0x9005, 0x0285, 0x9005, 0x0287, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2 }, /* Adaptec 2200S (Vulcan-2m)*/
+	{ 0x9005, 0x0285, 0x1028, 0x0287, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, /* Dell PERC 320/DC */
 	{ 0x1011, 0x0046, 0x9005, 0x0365, aac_sa_init, "aacraid",  "ADAPTEC ", "Adaptec 5400S   ", 4 }, /* Adaptec 5400S (Mustang)*/
 	{ 0x1011, 0x0046, 0x9005, 0x0364, aac_sa_init, "aacraid",  "ADAPTEC ", "AAC-364         ", 4 }, /* Adaptec 5400S (Mustang)*/
 	{ 0x1011, 0x0046, 0x9005, 0x1364, aac_sa_init, "percraid", "DELL    ", "PERCRAID        ", 4 }, /* Dell PERC2 "Quad Channel" */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/advansys.c linux-2.4.21/drivers/scsi/advansys.c
--- linux-2.4.20/drivers/scsi/advansys.c	2001-11-09 22:05:06.000000000 +0000
+++ linux-2.4.21/drivers/scsi/advansys.c	2002-12-18 18:58:05.000000000 +0000
@@ -5131,7 +5131,6 @@
                 ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
                 ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
                 ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
-                ep->adapter_info[6] = asc_dvc_varp->cfg->adapter_info[6];
 
                /*
                 * Modify board configuration.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfc.Readme linux-2.4.21/drivers/scsi/cpqfc.Readme
--- linux-2.4.20/drivers/scsi/cpqfc.Readme	2001-10-25 20:53:50.000000000 +0000
+++ linux-2.4.21/drivers/scsi/cpqfc.Readme	2002-12-18 18:58:08.000000000 +0000
@@ -22,6 +22,9 @@
    * Makefile changes to bring cpqfc into line w/ rest of SCSI drivers
      (thanks to Keith Owens)
 
+Ver 2.1.2  Jul 22, 2002
+   * initialize DumCmnd.lun (used as LUN index in fcFindLoggedInPort())
+
 Ver 2.0.5  Aug 06, 2001
    * Reject non-existent luns in the driver rather than letting the 
      hardware do it.  (some HW behaves differently than others in this area.)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfcTS.h linux-2.4.21/drivers/scsi/cpqfcTS.h
--- linux-2.4.20/drivers/scsi/cpqfcTS.h	2001-08-05 20:12:41.000000000 +0000
+++ linux-2.4.21/drivers/scsi/cpqfcTS.h	2002-12-18 18:58:07.000000000 +0000
@@ -5,40 +5,40 @@
 // These functions are required by the Linux SCSI layers
 extern int cpqfcTS_detect(Scsi_Host_Template *);
 extern int cpqfcTS_release(struct Scsi_Host *);
-extern const char * cpqfcTS_info(struct Scsi_Host *);
+extern const char *cpqfcTS_info(struct Scsi_Host *);
 extern int cpqfcTS_proc_info(char *, char **, off_t, int, int, int);
-extern int cpqfcTS_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
+extern int cpqfcTS_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 extern int cpqfcTS_abort(Scsi_Cmnd *);
 extern int cpqfcTS_reset(Scsi_Cmnd *, unsigned int);
-extern int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd);
+extern int cpqfcTS_eh_abort(Scsi_Cmnd * Cmnd);
 extern int cpqfcTS_eh_device_reset(Scsi_Cmnd *);
 extern int cpqfcTS_biosparam(Disk *, kdev_t, int[]);
-extern int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg);
+extern int cpqfcTS_ioctl(Scsi_Device * ScsiDev, int Cmnd, void *arg);
 
 // note: since Tachyon TS supports an extended scatter/gather
 // linked list of infinite length (with linked Ext S/G pages,
 // limited only by available physical memory) we use SG_ALL.
 
 #define CPQFCTS {                                \
- detect:                 cpqfcTS_detect,         \
- release:                cpqfcTS_release,        \
- info:                   cpqfcTS_info,           \
- proc_info:              cpqfcTS_proc_info,      \
- ioctl:                  cpqfcTS_ioctl,          \
- queuecommand:           cpqfcTS_queuecommand,   \
- eh_device_reset_handler:   cpqfcTS_eh_device_reset,   \
- eh_abort_handler:       cpqfcTS_eh_abort,       \
- reset:                  cpqfcTS_reset,          \
- abort:                  cpqfcTS_abort,		 \
- bios_param:             cpqfcTS_biosparam,      \
- can_queue:              CPQFCTS_REQ_QUEUE_LEN,  \
- this_id:                -1,                     \
- sg_tablesize:           SG_ALL,                 \
- cmd_per_lun:            CPQFCTS_CMD_PER_LUN,    \
- present:                0,                      \
- unchecked_isa_dma:      0,                      \
- use_clustering:         ENABLE_CLUSTERING,      \
- use_new_eh_code:        1			 \
+	detect:                 cpqfcTS_detect,         \
+	release:                cpqfcTS_release,        \
+	info:                   cpqfcTS_info,           \
+	proc_info:              cpqfcTS_proc_info,      \
+	ioctl:                  cpqfcTS_ioctl,          \
+	queuecommand:           cpqfcTS_queuecommand,   \
+	eh_device_reset_handler:   cpqfcTS_eh_device_reset,   \
+	eh_abort_handler:       cpqfcTS_eh_abort,       \
+	reset:                  cpqfcTS_reset,    	\
+	abort:                  cpqfcTS_abort,		\
+	bios_param:             cpqfcTS_biosparam,	\
+	can_queue:              CPQFCTS_REQ_QUEUE_LEN,	\
+	this_id:                -1,               	\
+	sg_tablesize:           SG_ALL,           	\
+	cmd_per_lun:            CPQFCTS_CMD_PER_LUN,	\
+	present:                0,              	\
+	unchecked_isa_dma:      0,              	\
+	use_clustering:         ENABLE_CLUSTERING,	\
+	use_new_eh_code:        1			\
 }
 
-#endif /* CPQFCTS_H */ 
+#endif				/* CPQFCTS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfcTSchip.h linux-2.4.21/drivers/scsi/cpqfcTSchip.h
--- linux-2.4.20/drivers/scsi/cpqfcTSchip.h	2000-09-19 15:01:34.000000000 +0000
+++ linux-2.4.21/drivers/scsi/cpqfcTSchip.h	2002-12-18 18:58:08.000000000 +0000
@@ -18,6 +18,7 @@
  * General Public License for more details.
  * Written by Don Zimmerman
 */
+
 #ifndef CPQFCTSCHIP_H
 #define CPQFCTSCHIP_H
 #ifndef TACHYON_CHIP_INC
@@ -29,210 +30,211 @@
 #define FC_PH43			0x09
 #define FC_PH3			0x20
 
-#define TACHLITE_TS_RX_SIZE     1024  // max inbound frame size
+#define TACHLITE_TS_RX_SIZE     1024	// max inbound frame size
 // "I" prefix is for Include
 
-#define IVENDID    0x00  // word
-#define IDEVID     0x02
-#define ITLCFGCMD 0x04
-#define IMEMBASE   0x18    // Tachyon
-#define ITLMEMBASE   0x1C  // Tachlite
-#define IIOBASEL   0x10    // Tachyon I/O base address, lower 256 bytes
-#define IIOBASEU   0x14    // Tachyon I/O base address, upper 256 bytes
-#define ITLIOBASEL   0x14  // TachLite I/O base address, lower 256 bytes
-#define ITLIOBASEU   0x18  // TachLite I/O base address, upper 256 bytes
-#define ITLRAMBASE   0x20  // TL on-board RAM start
-#define ISROMBASE  0x24
-#define IROMBASE   0x30
-
-#define ICFGCMD    0x04    // PCI config - PCI config access (word)
-#define ICFGSTAT   0x06    // PCI status (R - word)
-#define IRCTR_WCTR 0x1F2   // ROM control / pre-fetch wait counter
-#define IPCIMCTR   0x1F3   // PCI master control register
-#define IINTPEND   0x1FD   // Interrupt pending (I/O Upper - Tachyon & TL)
-#define IINTEN     0x1FE   // Interrupt enable  (I/O Upper - Tachyon & TL)
-#define IINTSTAT   0x1FF   // Interrupt status  (I/O Upper - Tachyon & TL)
+#define IVENDID		0x00	// word
+#define IDEVID		0x02
+#define ITLCFGCMD	0x04
+#define IMEMBASE	0x18	// Tachyon
+#define ITLMEMBASE	0x1C	// Tachlite
+#define IIOBASEL	0x10	// Tachyon I/O base address, lower 256 bytes
+#define IIOBASEU	0x14	// Tachyon I/O base address, upper 256 bytes
+#define ITLIOBASEL	0x14	// TachLite I/O base address, lower 256 bytes
+#define ITLIOBASEU	0x18	// TachLite I/O base address, upper 256 bytes
+#define ITLRAMBASE	0x20	// TL on-board RAM start
+#define ISROMBASE	0x24
+#define IROMBASE	0x30
+
+#define ICFGCMD		0x04	// PCI config - PCI config access (word)
+#define ICFGSTAT	0x06	// PCI status (R - word)
+#define IRCTR_WCTR	0x1F2	// ROM control / pre-fetch wait counter
+#define IPCIMCTR	0x1F3	// PCI master control register
+#define IINTPEND	0x1FD	// Interrupt pending (I/O Upper - Tachyon & TL)
+#define IINTEN		0x1FE	// Interrupt enable  (I/O Upper - Tachyon & TL)
+#define IINTSTAT	0x1FF	// Interrupt status  (I/O Upper - Tachyon & TL)
 
 #define IMQ_BASE            0x80
 #define IMQ_LENGTH          0x84
 #define IMQ_CONSUMER_INDEX  0x88
-#define IMQ_PRODUCER_INDEX  0x8C   // Tach copies its INDX to bits 0-7 of value
+#define IMQ_PRODUCER_INDEX  0x8C 	// Tach copies its INDX to bits 0-7 of value
 
 /*
 // IOBASE UPPER
-#define SFSBQ_BASE            0x00   // single-frame sequences
+#define SFSBQ_BASE            0x00	// single-frame sequences
 #define SFSBQ_LENGTH          0x04
 #define SFSBQ_PRODUCER_INDEX  0x08
-#define SFSBQ_CONSUMER_INDEX  0x0C   // (R)
+#define SFSBQ_CONSUMER_INDEX  0x0C	// (R)
 #define SFS_BUFFER_LENGTH     0X10
-                              // SCSI-FCP hardware assists
-#define SEST_BASE             0x40   // SSCI Exchange State Table
+	                          	// SCSI-FCP hardware assists
+#define SEST_BASE             0x40	// SSCI Exchange State Table
 #define SEST_LENGTH           0x44
 #define SCSI_BUFFER_LENGTH    0x48
 #define SEST_LINKED_LIST      0x4C
 
 #define TACHYON_My_ID         0x6C
-#define TACHYON_CONFIGURATION 0x84   // (R/W) reset val 2
+#define TACHYON_CONFIGURATION 0x84	// (R/W) reset val 2
 #define TACHYON_CONTROL       0x88
-#define TACHYON_STATUS        0x8C   // (R)
-#define TACHYON_FLUSH_SEST    0x90   // (R/W)
-#define TACHYON_EE_CREDIT_TMR 0x94   // (R)
-#define TACHYON_BB_CREDIT_TMR 0x98   // (R)
-#define TACHYON_RCV_FRAME_ERR 0x9C   // (R)
-#define FRAME_MANAGER_CONFIG  0xC0   // (R/W)
+#define TACHYON_STATUS        0x8C	// (R)
+#define TACHYON_FLUSH_SEST    0x90	// (R/W)
+#define TACHYON_EE_CREDIT_TMR 0x94	// (R)
+#define TACHYON_BB_CREDIT_TMR 0x98	// (R)
+#define TACHYON_RCV_FRAME_ERR 0x9C	// (R)
+#define FRAME_MANAGER_CONFIG  0xC0	// (R/W)
 #define FRAME_MANAGER_CONTROL 0xC4
-#define FRAME_MANAGER_STATUS  0xC8   // (R)
+#define FRAME_MANAGER_STATUS  0xC8	// (R)
 #define FRAME_MANAGER_ED_TOV  0xCC
-#define FRAME_MANAGER_LINK_ERR1 0xD0   // (R)
-#define FRAME_MANAGER_LINK_ERR2 0xD4   // (R)
-#define FRAME_MANAGER_TIMEOUT2  0xD8   // (W)
-#define FRAME_MANAGER_BB_CREDIT 0xDC   // (R)
-#define FRAME_MANAGER_WWN_HI    0xE0   // (R/W)
-#define FRAME_MANAGER_WWN_LO    0xE4   // (R/W)
-#define FRAME_MANAGER_RCV_AL_PA 0xE8   // (R)
-#define FRAME_MANAGER_PRIMITIVE 0xEC   // {K28.5} byte1 byte2 byte3
+#define FRAME_MANAGER_LINK_ERR1 0xD0	// (R)
+#define FRAME_MANAGER_LINK_ERR2 0xD4	// (R)
+#define FRAME_MANAGER_TIMEOUT2  0xD8	// (W)
+#define FRAME_MANAGER_BB_CREDIT 0xDC	// (R)
+#define FRAME_MANAGER_WWN_HI    0xE0	// (R/W)
+#define FRAME_MANAGER_WWN_LO    0xE4	// (R/W)
+#define FRAME_MANAGER_RCV_AL_PA 0xE8	// (R)
+#define FRAME_MANAGER_PRIMITIVE 0xEC	// {K28.5} byte1 byte2 byte3
 */
-		    
-#define TL_MEM_ERQ_BASE                    0x0 //ERQ Base
-#define TL_IO_ERQ_BASE                     0x0 //ERQ base
 
-#define TL_MEM_ERQ_LENGTH                  0x4 //ERQ Length
-#define TL_IO_ERQ_LENGTH                   0x4 //ERQ Length
+#define TL_MEM_ERQ_BASE                 0x0	//ERQ Base
+#define TL_IO_ERQ_BASE                  0x0	//ERQ base
+
+#define TL_MEM_ERQ_LENGTH               0x4	//ERQ Length
+#define TL_IO_ERQ_LENGTH                0x4	//ERQ Length
 
-#define TL_MEM_ERQ_PRODUCER_INDEX          0x8 //ERQ Producer Index  register
-#define TL_IO_ERQ_PRODUCER_INDEX           0x8 //ERQ Producer Index  register
+#define TL_MEM_ERQ_PRODUCER_INDEX       0x8	//ERQ Producer Index  register
+#define TL_IO_ERQ_PRODUCER_INDEX	0x8	//ERQ Producer Index  register
 
-#define TL_MEM_ERQ_CONSUMER_INDEX_ADR 0xC //ERQ Consumer Index address register
-#define TL_IO_ERQ_CONSUMER_INDEX_ADR  0xC //ERQ Consumer Index address register
+#define TL_MEM_ERQ_CONSUMER_INDEX_ADR	0xC	//ERQ Consumer Index address register
+#define TL_IO_ERQ_CONSUMER_INDEX_ADR	0xC	//ERQ Consumer Index address register
 
-#define TL_MEM_ERQ_CONSUMER_INDEX     0xC //ERQ Consumer Index 
-#define TL_IO_ERQ_CONSUMER_INDEX      0xC //ERQ Consumer Index 
+#define TL_MEM_ERQ_CONSUMER_INDEX     	0xC	//ERQ Consumer Index
+#define TL_IO_ERQ_CONSUMER_INDEX      	0xC	//ERQ Consumer Index
 
-#define TL_MEM_SFQ_BASE               0x50 //SFQ Base
-#define TL_IO_SFQ_BASE                0x50 //SFQ base
+#define TL_MEM_SFQ_BASE               	0x50	//SFQ Base
+#define TL_IO_SFQ_BASE                	0x50	//SFQ base
 
-#define TL_MEM_SFQ_LENGTH             0x54 //SFQ Length
-#define TL_IO_SFQ_LENGTH              0x54 //SFQ Length
+#define TL_MEM_SFQ_LENGTH             	0x54	//SFQ Length
+#define TL_IO_SFQ_LENGTH              	0x54	//SFQ Length
 
-#define TL_MEM_SFQ_CONSUMER_INDEX     0x58 //SFQ Consumer Index
-#define TL_IO_SFQ_CONSUMER_INDEX      0x58 //SFQ Consumer Index
+#define TL_MEM_SFQ_CONSUMER_INDEX     	0x58	//SFQ Consumer Index
+#define TL_IO_SFQ_CONSUMER_INDEX      	0x58	//SFQ Consumer Index
 
-#define TL_MEM_IMQ_BASE               0x80 //IMQ Base
-#define TL_IO_IMQ_BASE                0x80 //IMQ base
+#define TL_MEM_IMQ_BASE               	0x80	//IMQ Base
+#define TL_IO_IMQ_BASE                	0x80	//IMQ base
 
-#define TL_MEM_IMQ_LENGTH             0x84 //IMQ Length
-#define TL_IO_IMQ_LENGTH              0x84 //IMQ Length
+#define TL_MEM_IMQ_LENGTH             	0x84	//IMQ Length
+#define TL_IO_IMQ_LENGTH              	0x84	//IMQ Length
 
-#define TL_MEM_IMQ_CONSUMER_INDEX     0x88 //IMQ Consumer Index
-#define TL_IO_IMQ_CONSUMER_INDEX      0x88 //IMQ Consumer Index
+#define TL_MEM_IMQ_CONSUMER_INDEX     	0x88	//IMQ Consumer Index
+#define TL_IO_IMQ_CONSUMER_INDEX      	0x88	//IMQ Consumer Index
 
-#define TL_MEM_IMQ_PRODUCER_INDEX_ADR 0x8C //IMQ Producer Index address register
-#define TL_IO_IMQ_PRODUCER_INDEX_ADR  0x8C //IMQ Producer Index address register
+#define TL_MEM_IMQ_PRODUCER_INDEX_ADR 	0x8C	//IMQ Producer Index address register
+#define TL_IO_IMQ_PRODUCER_INDEX_ADR  	0x8C	//IMQ Producer Index address register
 
-#define TL_MEM_SEST_BASE              0x140 //SFQ Base
-#define TL_IO_SEST_BASE               0x40 //SFQ base
+#define TL_MEM_SEST_BASE              	0x140	//SFQ Base
+#define TL_IO_SEST_BASE               	0x40	//SFQ base
 
-#define TL_MEM_SEST_LENGTH            0x144 //SFQ Length
-#define TL_IO_SEST_LENGTH             0x44 //SFQ Length
+#define TL_MEM_SEST_LENGTH            	0x144	//SFQ Length
+#define TL_IO_SEST_LENGTH             	0x44	//SFQ Length
 
-#define TL_MEM_SEST_LINKED_LIST       0x14C
+#define TL_MEM_SEST_LINKED_LIST       	0x14C
 
-#define TL_MEM_SEST_SG_PAGE           0x168  // Extended Scatter/Gather page size
+#define TL_MEM_SEST_SG_PAGE           	0x168	// Extended Scatter/Gather page size
 
-#define TL_MEM_TACH_My_ID             0x16C
-#define TL_IO_TACH_My_ID              0x6C //My AL_PA ID
+#define TL_MEM_TACH_My_ID             	0x16C
+#define TL_IO_TACH_My_ID              	0x6C	//My AL_PA ID
 
-#define TL_MEM_TACH_CONFIG            0x184 //Tachlite Configuration register
-#define TL_IO_CONFIG                  0x84 //Tachlite Configuration register
+#define TL_MEM_TACH_CONFIG            	0x184	//Tachlite Configuration register
+#define TL_IO_CONFIG                  	0x84	//Tachlite Configuration register
 
-#define TL_MEM_TACH_CONTROL           0x188 //Tachlite Control register
-#define TL_IO_CTR                     0x88 //Tachlite Control register
+#define TL_MEM_TACH_CONTROL           	0x188	//Tachlite Control register
+#define TL_IO_CTR                     	0x88	//Tachlite Control register
 
-#define TL_MEM_TACH_STATUS            0x18C //Tachlite Status register
-#define TL_IO_STAT                    0x8C //Tachlite Status register
+#define TL_MEM_TACH_STATUS            	0x18C	//Tachlite Status register
+#define TL_IO_STAT                    	0x8C	//Tachlite Status register
 
-#define TL_MEM_FM_CONFIG        0x1C0 //Frame Manager Configuration register
-#define TL_IO_FM_CONFIG         0xC0 //Frame Manager Configuration register
+#define TL_MEM_FM_CONFIG        	0x1C0	//Frame Manager Configuration register
+#define TL_IO_FM_CONFIG         	0xC0	//Frame Manager Configuration register
 
-#define TL_MEM_FM_CONTROL       0x1C4 //Frame Manager Control
-#define TL_IO_FM_CTL            0xC4 //Frame Manager Control
+#define TL_MEM_FM_CONTROL       	0x1C4	//Frame Manager Control
+#define TL_IO_FM_CTL            	0xC4	//Frame Manager Control
 
-#define TL_MEM_FM_STATUS        0x1C8 //Frame Manager Status
-#define TL_IO_FM_STAT           0xC8 //Frame Manager Status
+#define TL_MEM_FM_STATUS        	0x1C8	//Frame Manager Status
+#define TL_IO_FM_STAT           	0xC8	//Frame Manager Status
 
-#define TL_MEM_FM_LINK_STAT1    0x1D0 //Frame Manager Link Status 1
-#define TL_IO_FM_LINK_STAT1     0xD0 //Frame Manager Link Status 1
+#define TL_MEM_FM_LINK_STAT1    	0x1D0	//Frame Manager Link Status 1
+#define TL_IO_FM_LINK_STAT1     	0xD0	//Frame Manager Link Status 1
 
-#define TL_MEM_FM_LINK_STAT2    0x1D4 //Frame Manager Link Status 2
-#define TL_IO_FM_LINK_STAT2     0xD4 //Frame Manager Link Status 2
+#define TL_MEM_FM_LINK_STAT2    	0x1D4	//Frame Manager Link Status 2
+#define TL_IO_FM_LINK_STAT2     	0xD4	//Frame Manager Link Status 2
 
-#define TL_MEM_FM_TIMEOUT2      0x1D8   // (W)
+#define TL_MEM_FM_TIMEOUT2      	0x1D8	// (W)
 
-#define TL_MEM_FM_BB_CREDIT0    0x1DC
+#define TL_MEM_FM_BB_CREDIT0    	0x1DC
 
-#define TL_MEM_FM_WWN_HI        0x1E0 //Frame Manager World Wide Name High
-#define TL_IO_FM_WWN_HI         0xE0 //Frame Manager World Wide Name High
+#define TL_MEM_FM_WWN_HI        	0x1E0	//Frame Manager World Wide Name High
+#define TL_IO_FM_WWN_HI         	0xE0	//Frame Manager World Wide Name High
 
-#define TL_MEM_FM_WWN_LO        0x1E4 //Frame Manager World Wide Name LOW
-#define TL_IO_FM_WWN_LO         0xE4 //Frame Manager World Wide Name Low
+#define TL_MEM_FM_WWN_LO        	0x1E4	//Frame Manager World Wide Name LOW
+#define TL_IO_FM_WWN_LO         	0xE4	//Frame Manager World Wide Name Low
 
-#define TL_MEM_FM_RCV_AL_PA     0x1E8 //Frame Manager AL_PA Received register
-#define TL_IO_FM_ALPA           0xE8 //Frame Manager AL_PA Received register
+#define TL_MEM_FM_RCV_AL_PA     	0x1E8	//Frame Manager AL_PA Received register
+#define TL_IO_FM_ALPA           	0xE8	//Frame Manager AL_PA Received register
 
-#define TL_MEM_FM_ED_TOV           0x1CC
+#define TL_MEM_FM_ED_TOV        	0x1CC
 
-#define TL_IO_ROMCTR            0xFA //TL PCI ROM Control Register
-#define TL_IO_PCIMCTR           0xFB //TL PCI Master Control Register
-#define TL_IO_SOFTRST           0xFC //Tachlite Configuration register
-#define TL_MEM_SOFTRST          0x1FC //Tachlite Configuration register
+#define TL_IO_ROMCTR            	0xFA	//TL PCI ROM Control Register
+#define TL_IO_PCIMCTR           	0xFB	//TL PCI Master Control Register
+#define TL_IO_SOFTRST           	0xFC	//Tachlite Configuration register
+#define TL_MEM_SOFTRST          	0x1FC	//Tachlite Configuration register
 
 // completion message types (bit 8 set means Interrupt generated)
 // CM_Type
-#define OUTBOUND_COMPLETION        0
-#define ERROR_IDLE_COMPLETION   0x01
-#define OUT_HI_PRI_COMPLETION   0x01
-#define INBOUND_MFS_COMPLETION  0x02
-#define INBOUND_000_COMPLETION  0x03
-#define INBOUND_SFS_COMPLETION  0x04  // Tachyon & TachLite
-#define ERQ_FROZEN_COMPLETION   0x06  // TachLite
-#define INBOUND_C1_TIMEOUT      0x05
-#define INBOUND_BUSIED_FRAME    0x06
-#define SFS_BUF_WARN            0x07
-#define FCP_FROZEN_COMPLETION   0x07  // TachLite
-#define MFS_BUF_WARN            0x08
-#define IMQ_BUF_WARN            0x09
-#define FRAME_MGR_INTERRUPT     0x0A
-#define READ_STATUS             0x0B
-#define INBOUND_SCSI_DATA_COMPLETION  0x0C
-#define INBOUND_FCP_XCHG_COMPLETION   0x0C  // TachLite
-#define INBOUND_SCSI_DATA_COMMAND     0x0D
-#define BAD_SCSI_FRAME                0x0E
-#define INB_SCSI_STATUS_COMPLETION    0x0F
-#define BUFFER_PROCESSED_COMPLETION   0x11
+
+#define OUTBOUND_COMPLETION     	   0
+#define ERROR_IDLE_COMPLETION   	0x01
+#define OUT_HI_PRI_COMPLETION   	0x01
+#define INBOUND_MFS_COMPLETION  	0x02
+#define INBOUND_000_COMPLETION  	0x03
+#define INBOUND_SFS_COMPLETION  	0x04	// Tachyon & TachLite
+#define ERQ_FROZEN_COMPLETION   	0x06	// TachLite
+#define INBOUND_C1_TIMEOUT      	0x05
+#define INBOUND_BUSIED_FRAME    	0x06
+#define SFS_BUF_WARN            	0x07
+#define FCP_FROZEN_COMPLETION   	0x07	// TachLite
+#define MFS_BUF_WARN            	0x08
+#define IMQ_BUF_WARN            	0x09
+#define FRAME_MGR_INTERRUPT     	0x0A
+#define READ_STATUS             	0x0B
+#define INBOUND_SCSI_DATA_COMPLETION  	0x0C
+#define INBOUND_FCP_XCHG_COMPLETION   	0x0C	// TachLite
+#define INBOUND_SCSI_DATA_COMMAND     	0x0D
+#define BAD_SCSI_FRAME                	0x0E
+#define INB_SCSI_STATUS_COMPLETION    	0x0F
+#define BUFFER_PROCESSED_COMPLETION   	0x11
 
 // FC-AL (Tachyon) Loop Port State Machine defs
 // (loop "Up" states)
-#define MONITORING 0x0
-#define ARBITRATING 0x1
-#define ARBITRAT_WON 0x2
-#define OPEN 0x3
-#define OPENED 0x4
-#define XMITTD_CLOSE 0x5
-#define RCVD_CLOSE 0x6
-#define TRANSFER 0x7
+#define MONITORING			0x0
+#define ARBITRATING			0x1
+#define ARBITRAT_WON			0x2
+#define OPEN				0x3
+#define OPENED				0x4
+#define XMITTD_CLOSE			0x5
+#define RCVD_CLOSE			0x6
+#define TRANSFER			0x7
 
 // (loop "Down" states)
-#define INITIALIZING 0x8
-#define O_I_INIT 0x9
-#define O_I_PROTOCOL 0xa
-#define O_I_LIP_RCVD 0xb
-#define HOST_CONTROL 0xc
-#define LOOP_FAIL 0xd
+#define INITIALIZING			0x8
+#define O_I_INIT			0x9
+#define O_I_PROTOCOL			0xa
+#define O_I_LIP_RCVD			0xb
+#define HOST_CONTROL			0xc
+#define LOOP_FAIL			0xd
 // (no 0xe)
-#define OLD_PORT 0xf
+#define OLD_PORT			0xf
 
 
 
 #define TACHYON_CHIP_INC
 #endif
-#endif /* CPQFCTSCHIP_H */
+#endif				/* CPQFCTSCHIP_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfcTScontrol.c linux-2.4.21/drivers/scsi/cpqfcTScontrol.c
--- linux-2.4.20/drivers/scsi/cpqfcTScontrol.c	2001-10-25 20:53:50.000000000 +0000
+++ linux-2.4.21/drivers/scsi/cpqfcTScontrol.c	2002-12-18 18:58:03.000000000 +0000
@@ -28,46 +28,40 @@
    Hewlitt Packard Manual Part Number 5968-1083E.
 */
 
-#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-
 #include <linux/blk.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/ioport.h>  // request_region() prototype
+#include <linux/ioport.h>	// request_region() prototype
 #include <linux/sched.h>
-#include <linux/slab.h>  // need "kfree" for ext. S/G pages
+#include <linux/slab.h>		// need "kfree" for ext. S/G pages
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/unistd.h>
-#include <asm/io.h>  // struct pt_regs for IRQ handler & Port I/O
+#include <asm/io.h>		// struct pt_regs for IRQ handler & Port I/O
 #include <asm/irq.h>
 #include <linux/spinlock.h>
 
 #include "sd.h"
-#include "hosts.h"   // Scsi_Host definition for INT handler
+#include "hosts.h"		// Scsi_Host definition for INT handler
 #include "cpqfcTSchip.h"
 #include "cpqfcTSstructs.h"
 
 //#define IMQ_DEBUG 1
 
 static void fcParseLinkStatusCounters(TACHYON * fcChip);
-static void CpqTsGetSFQEntry(TACHYON * fcChip, 
-	      USHORT pi, ULONG * buffr, BOOLEAN UpdateChip); 
+static void CpqTsGetSFQEntry(TACHYON * fcChip, u16 pi, u32 * buffr, u8 UpdateChip);
 
-static void 
-cpqfc_free_dma_consistent(CPQFCHBA *cpqfcHBAdata)
+static void cpqfc_free_dma_consistent(CPQFCHBA * cpqfcHBAdata)
 {
-  	// free up the primary EXCHANGES struct and Link Q
+	// free up the primary EXCHANGES struct and Link Q
 	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
 
 	if (fcChip->Exchanges != NULL)
-		pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_EXCHANGES),
-			fcChip->Exchanges, fcChip->exch_dma_handle);
+		pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_EXCHANGES), fcChip->Exchanges, fcChip->exch_dma_handle);
 	fcChip->Exchanges = NULL;
 	if (cpqfcHBAdata->fcLQ != NULL)
-		pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_LINK_QUE),
-			cpqfcHBAdata->fcLQ, cpqfcHBAdata->fcLQ_dma_handle);
+		pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_LINK_QUE), cpqfcHBAdata->fcLQ, cpqfcHBAdata->fcLQ_dma_handle);
 	cpqfcHBAdata->fcLQ = NULL;
 }
 
@@ -76,281 +70,236 @@
 // in non-symbolic (i.e. memory dump) debugging
 // opcode defines placement of Queues (e.g. local/external RAM)
 
-int CpqTsCreateTachLiteQues( void* pHBA, int opcode)
+int CpqTsCreateTachLiteQues(void *pHBA, int opcode)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) pHBA;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+
+	int iStatus = 0;
+	unsigned long ulAddr;
+	dma_addr_t ERQdma, IMQdma, SPQdma, SESTdma;
+	int i;
+
+	// NOTE! fcMemManager() will return system virtual addresses.
+	// System (kernel) virtual addresses, though non-paged, still
+	// aren't physical addresses.  Convert to PHYSICAL_ADDRESS for Tachyon's
+	// DMA use.
+	ENTER("CreateTachLiteQues");
+
+
+	// Allocate primary EXCHANGES array...
+	fcChip->Exchanges = NULL;
+	cpqfcHBAdata->fcLQ = NULL;
+
+	printk("Allocating %u for %u Exchanges ", (u32) sizeof(FC_EXCHANGES), TACH_MAX_XID);
+	fcChip->Exchanges = pci_alloc_consistent(cpqfcHBAdata->PciDev, sizeof(FC_EXCHANGES), &fcChip->exch_dma_handle);
+	printk("@ %p\n", fcChip->Exchanges);
 
-  int iStatus=0;
-  unsigned long ulAddr;
-  dma_addr_t ERQdma, IMQdma, SPQdma, SESTdma;
-  int i;
-
-  // NOTE! fcMemManager() will return system virtual addresses.
-  // System (kernel) virtual addresses, though non-paged, still
-  // aren't physical addresses.  Convert to PHYSICAL_ADDRESS for Tachyon's
-  // DMA use.
-  ENTER("CreateTachLiteQues");
-
-
-  // Allocate primary EXCHANGES array...
-  fcChip->Exchanges = NULL;
-  cpqfcHBAdata->fcLQ = NULL;
-  
-  printk("Allocating %u for %u Exchanges ", 
-	  (ULONG)sizeof(FC_EXCHANGES), TACH_MAX_XID);
-  fcChip->Exchanges = pci_alloc_consistent(cpqfcHBAdata->PciDev, 
-			sizeof(FC_EXCHANGES), &fcChip->exch_dma_handle);
-  printk("@ %p\n", fcChip->Exchanges);
-
-  if( fcChip->Exchanges == NULL ) // fatal error!!
-  {
-    printk("pci_alloc_consistent failure on Exchanges: fatal error\n");
-    return -1;
-  }
-  // zero out the entire EXCHANGE space
-  memset( fcChip->Exchanges, 0, sizeof( FC_EXCHANGES));  
-
-
-  printk("Allocating %u for LinkQ ", (ULONG)sizeof(FC_LINK_QUE));
-  cpqfcHBAdata->fcLQ = pci_alloc_consistent(cpqfcHBAdata->PciDev,
-				 sizeof( FC_LINK_QUE), &cpqfcHBAdata->fcLQ_dma_handle);
-  printk("@ %p (%u elements)\n", cpqfcHBAdata->fcLQ, FC_LINKQ_DEPTH);
-  memset( cpqfcHBAdata->fcLQ, 0, sizeof( FC_LINK_QUE));
-
-  if( cpqfcHBAdata->fcLQ == NULL ) // fatal error!!
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("pci_alloc_consistent() failure on fc Link Que: fatal error\n");
-    return -1;
-  }
-  // zero out the entire EXCHANGE space
-  memset( cpqfcHBAdata->fcLQ, 0, sizeof( FC_LINK_QUE));  
-  
-  // Verify that basic Tach I/O registers are not NULL  
-  if( !fcChip->Registers.ReMapMemBase )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("HBA base address NULL: fatal error\n");
-    return -1;
-  }
-
-
-  // Initialize the fcMemManager memory pairs (stores allocated/aligned
-  // pairs for future freeing)
-  memset( cpqfcHBAdata->dynamic_mem, 0, sizeof(cpqfcHBAdata->dynamic_mem));
-  
-
-  // Allocate Tach's Exchange Request Queue (each ERQ entry 32 bytes)
-  
-  fcChip->ERQ = fcMemManager( cpqfcHBAdata->PciDev, 
-			&cpqfcHBAdata->dynamic_mem[0], 
-			sizeof( TachLiteERQ ), 32*(ERQ_LEN), 0L, &ERQdma);
-  if( !fcChip->ERQ )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("pci_alloc_consistent/alignment failure on ERQ: fatal error\n");
-    return -1;
-  }
-  fcChip->ERQ->length = ERQ_LEN-1;
-  ulAddr = (ULONG) ERQdma; 
+	if (fcChip->Exchanges == NULL)	// fatal error!!
+	{
+		printk("pci_alloc_consistent failure on Exchanges: fatal error\n");
+		return -1;
+	}
+	// zero out the entire EXCHANGE space
+	memset(fcChip->Exchanges, 0, sizeof(FC_EXCHANGES));
+
+
+	printk("Allocating %u for LinkQ ", (u32) sizeof(FC_LINK_QUE));
+	cpqfcHBAdata->fcLQ = pci_alloc_consistent(cpqfcHBAdata->PciDev, sizeof(FC_LINK_QUE), &cpqfcHBAdata->fcLQ_dma_handle);
+	printk("@ %p (%u elements)\n", cpqfcHBAdata->fcLQ, FC_LINKQ_DEPTH);
+	memset(cpqfcHBAdata->fcLQ, 0, sizeof(FC_LINK_QUE));
+
+	if (cpqfcHBAdata->fcLQ == NULL)	// fatal error!!
+	{
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk("pci_alloc_consistent() failure on fc Link Que: fatal error\n");
+		return -1;
+	}
+	// zero out the entire EXCHANGE space
+	memset(cpqfcHBAdata->fcLQ, 0, sizeof(FC_LINK_QUE));
+
+	// Verify that basic Tach I/O registers are not NULL  
+	if (!fcChip->Registers.ReMapMemBase) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk("HBA base address NULL: fatal error\n");
+		return -1;
+	}
+
+	// Initialize the fcMemManager memory pairs (stores allocated/aligned
+	// pairs for future freeing)
+	memset(cpqfcHBAdata->dynamic_mem, 0, sizeof(cpqfcHBAdata->dynamic_mem));
+
+
+	// Allocate Tach's Exchange Request Queue (each ERQ entry 32 bytes)
+
+	fcChip->ERQ = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], sizeof(TachLiteERQ), 32 * (ERQ_LEN), 0L, &ERQdma);
+	if (!fcChip->ERQ) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk("pci_alloc_consistent/alignment failure on ERQ: fatal error\n");
+		return -1;
+	}
+	fcChip->ERQ->length = ERQ_LEN - 1;
+	ulAddr = (u32) ERQdma;
 #if BITS_PER_LONG > 32
-  if( (ulAddr >> 32) )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk(" FATAL! ERQ ptr %p exceeds Tachyon's 32-bit register size\n",
-		    (void*)ulAddr);
-    return -1;  // failed
-  }
+	if ((ulAddr >> 32)) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk(" FATAL! ERQ ptr %p exceeds Tachyon's 32-bit register size\n", (void *) ulAddr);
+		return -1;	// failed
+	}
 #endif
-  fcChip->ERQ->base = (ULONG)ulAddr;  // copy for quick reference
+	fcChip->ERQ->base = (u32) ulAddr;	// copy for quick reference
 
 
-  // Allocate Tach's Inbound Message Queue (32 bytes per entry)
-  
-  fcChip->IMQ = fcMemManager( cpqfcHBAdata->PciDev, 
-		  &cpqfcHBAdata->dynamic_mem[0],
-		  sizeof( TachyonIMQ ), 32*(IMQ_LEN), 0L, &IMQdma );
-  if( !fcChip->IMQ )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("pci_alloc_consistent/alignment failure on IMQ: fatal error\n");
-    return -1;
-  }
-  fcChip->IMQ->length = IMQ_LEN-1;
+	// Allocate Tach's Inbound Message Queue (32 bytes per entry)
 
-  ulAddr = IMQdma;
+	fcChip->IMQ = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], sizeof(TachyonIMQ), 32 * (IMQ_LEN), 0L, &IMQdma);
+	if (!fcChip->IMQ) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk("pci_alloc_consistent/alignment failure on IMQ: fatal error\n");
+		return -1;
+	}
+	fcChip->IMQ->length = IMQ_LEN - 1;
+
+	ulAddr = IMQdma;
 #if BITS_PER_LONG > 32
-  if( (ulAddr >> 32) )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n",
-		    (void*)ulAddr);
-    return -1;  // failed
-  }
+	if ((ulAddr >> 32)) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n", (void *) ulAddr);
+		return -1;	// failed
+	}
 #endif
-  fcChip->IMQ->base = (ULONG)ulAddr;  // copy for quick reference
+	fcChip->IMQ->base = (u32) ulAddr;	// copy for quick reference
 
 
-  // Allocate Tach's  Single Frame Queue (64 bytes per entry)
-  fcChip->SFQ = fcMemManager( cpqfcHBAdata->PciDev, 
-		  &cpqfcHBAdata->dynamic_mem[0],
-		  sizeof( TachLiteSFQ ), 64*(SFQ_LEN),0L, &SPQdma );
-  if( !fcChip->SFQ )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("pci_alloc_consistent/alignment failure on SFQ: fatal error\n");
-    return -1;
-  }
-  fcChip->SFQ->length = SFQ_LEN-1;      // i.e. Que length [# entries -
-                                       // min. 32; max.  4096 (0xffff)]
-  
-  ulAddr = SPQdma;
+	// Allocate Tach's  Single Frame Queue (64 bytes per entry)
+	fcChip->SFQ = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], sizeof(TachLiteSFQ), 64 * (SFQ_LEN), 0L, &SPQdma);
+	if (!fcChip->SFQ) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk("pci_alloc_consistent/alignment failure on SFQ: fatal error\n");
+		return -1;
+	}
+	fcChip->SFQ->length = SFQ_LEN - 1;	// i.e. Que length [# entries -
+	// min. 32; max.  4096 (0xffff)]
+
+	ulAddr = SPQdma;
 #if BITS_PER_LONG > 32
-  if( (ulAddr >> 32) )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n",
-		    (void*)ulAddr);
-    return -1;  // failed
-  }
+	if ((ulAddr >> 32)) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n", (void *) ulAddr);
+		return -1;	// failed
+	}
 #endif
-  fcChip->SFQ->base = (ULONG)ulAddr;  // copy for quick reference
+	fcChip->SFQ->base = (u32) ulAddr;	// copy for quick reference
 
 
-  // Allocate SCSI Exchange State Table; aligned nearest @sizeof
-  // power-of-2 boundary
-  // LIVE DANGEROUSLY!  Assume the boundary for SEST mem will
-  // be on physical page (e.g. 4k) boundary.
-  printk("Allocating %u for TachSEST for %u Exchanges\n", 
-		 (ULONG)sizeof(TachSEST), TACH_SEST_LEN);
-  fcChip->SEST = fcMemManager( cpqfcHBAdata->PciDev,
-		  &cpqfcHBAdata->dynamic_mem[0],
-		  sizeof(TachSEST),  4, 0L, &SESTdma );
-//		  sizeof(TachSEST),  64*TACH_SEST_LEN, 0L );
-  if( !fcChip->SEST )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("pci_alloc_consistent/alignment failure on SEST: fatal error\n");
-    return -1;
-  }
+	// Allocate SCSI Exchange State Table; aligned nearest @sizeof
+	// power-of-2 boundary
+	// LIVE DANGEROUSLY!  Assume the boundary for SEST mem will
+	// be on physical page (e.g. 4k) boundary.
+	printk("Allocating %u for TachSEST for %u Exchanges\n", (u32) sizeof(TachSEST), TACH_SEST_LEN);
+	fcChip->SEST = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], sizeof(TachSEST), 4, 0L, &SESTdma);
+//                sizeof(TachSEST),  64*TACH_SEST_LEN, 0L );
+	if (!fcChip->SEST) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk("pci_alloc_consistent/alignment failure on SEST: fatal error\n");
+		return -1;
+	}
 
-  for( i=0; i < TACH_SEST_LEN; i++)  // for each exchange
-      fcChip->SEST->sgPages[i] = NULL;
+	for (i = 0; i < TACH_SEST_LEN; i++)	// for each exchange
+		fcChip->SEST->sgPages[i] = NULL;
 
-  fcChip->SEST->length = TACH_SEST_LEN;  // e.g. DON'T subtract one 
-                                       // (TL/TS UG, pg 153)
+	fcChip->SEST->length = TACH_SEST_LEN;	// e.g. DON'T subtract one 
+	// (TL/TS UG, pg 153)
 
-  ulAddr = SESTdma; 
+	ulAddr = SESTdma;
 #if BITS_PER_LONG > 32
-  if( (ulAddr >> 32) )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n",
-		    (void*)ulAddr);
-    return -1;  // failed
-  }
+	if ((ulAddr >> 32)) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n", (void *) ulAddr);
+		return -1;	// failed
+	}
 #endif
-  fcChip->SEST->base = (ULONG)ulAddr;  // copy for quick reference
+	fcChip->SEST->base = (u32) ulAddr;	// copy for quick reference
+
+
+	// Now that structures are defined,
+	// fill in Tachyon chip registers...
+
+	// EEEEEEEE  EXCHANGE REQUEST QUEUE
 
+	writel(fcChip->ERQ->base, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
 
-			      // Now that structures are defined,
-			      // fill in Tachyon chip registers...
+	writel(fcChip->ERQ->length, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_LENGTH));
 
-			      // EEEEEEEE  EXCHANGE REQUEST QUEUE
 
-  writel( fcChip->ERQ->base, 
-    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
-      
-  writel( fcChip->ERQ->length,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_LENGTH));
-     
+	fcChip->ERQ->producerIndex = 0L;
+	writel(fcChip->ERQ->producerIndex, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX));
 
-  fcChip->ERQ->producerIndex = 0L;
-  writel( fcChip->ERQ->producerIndex,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX));
-      
 
-		// NOTE! write consumer index last, since the write
-		// causes Tachyon to process the other registers
+	// NOTE! write consumer index last, since the write
+	// causes Tachyon to process the other registers
 
-  ulAddr = ((unsigned long)&fcChip->ERQ->consumerIndex - 
-		(unsigned long)fcChip->ERQ) + (unsigned long) ERQdma;
+	ulAddr = ((unsigned long) &fcChip->ERQ->consumerIndex - (unsigned long) fcChip->ERQ) + (unsigned long) ERQdma;
 
-  // NOTE! Tachyon DMAs to the ERQ consumer Index host
-		// address; must be correctly aligned
-  writel( (ULONG)ulAddr,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_CONSUMER_INDEX_ADR));
+	// NOTE! Tachyon DMAs to the ERQ consumer Index host
+	// address; must be correctly aligned
+	writel((u32) ulAddr, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_CONSUMER_INDEX_ADR));
 
 
 
-				 // IIIIIIIIIIIII  INBOUND MESSAGE QUEUE
-				 // Tell Tachyon where the Que starts
+	// IIIIIIIIIIIII  INBOUND MESSAGE QUEUE
+	// Tell Tachyon where the Que starts
 
-  // set the Host's pointer for Tachyon to access
+	// set the Host's pointer for Tachyon to access
 
-  printk("  cpqfcTS: writing IMQ BASE %Xh  ", fcChip->IMQ->base );
-  writel( fcChip->IMQ->base, 
-    (fcChip->Registers.ReMapMemBase + IMQ_BASE));
+	printk("  cpqfcTS: writing IMQ BASE %Xh  ", fcChip->IMQ->base);
+	writel(fcChip->IMQ->base, (fcChip->Registers.ReMapMemBase + IMQ_BASE));
 
-  writel( fcChip->IMQ->length,
-    (fcChip->Registers.ReMapMemBase + IMQ_LENGTH));
+	writel(fcChip->IMQ->length, (fcChip->Registers.ReMapMemBase + IMQ_LENGTH));
 
-  writel( fcChip->IMQ->consumerIndex,
-    (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
+	writel(fcChip->IMQ->consumerIndex, (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
 
 
-		// NOTE: TachLite DMAs to the producerIndex host address
-		// must be correctly aligned with address bits 1-0 cleared
-    // Writing the BASE register clears the PI register, so write it last
-  ulAddr = ((unsigned long)&fcChip->IMQ->producerIndex - 
-		(unsigned long)fcChip->IMQ) + (unsigned long) IMQdma;
+	// NOTE: TachLite DMAs to the producerIndex host address
+	// must be correctly aligned with address bits 1-0 cleared
+	// Writing the BASE register clears the PI register, so write it last
+	ulAddr = ((unsigned long) &fcChip->IMQ->producerIndex - (unsigned long) fcChip->IMQ) + (unsigned long) IMQdma;
 
 #if BITS_PER_LONG > 32
-  if( (ulAddr >> 32) )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n",
-		    (void*)ulAddr);
-    return -1;  // failed
-  }
+	if ((ulAddr >> 32)) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n", (void *) ulAddr);
+		return -1;	// failed
+	}
 #endif
 //#if DBG
-  printk("  PI %Xh\n", (ULONG)ulAddr );
+	printk("  PI %Xh\n", (u32) ulAddr);
 //#endif
-  writel( (ULONG)ulAddr, 
-    (fcChip->Registers.ReMapMemBase + IMQ_PRODUCER_INDEX));
+	writel((u32) ulAddr, (fcChip->Registers.ReMapMemBase + IMQ_PRODUCER_INDEX));
+
 
 
+	// SSSSSSSSSSSSSSS SINGLE FRAME SEQUENCE
+	// Tell TachLite where the Que starts
 
-				 // SSSSSSSSSSSSSSS SINGLE FRAME SEQUENCE
-				 // Tell TachLite where the Que starts
+	writel(fcChip->SFQ->base, (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_BASE));
 
-  writel( fcChip->SFQ->base, 
-    (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_BASE));
+	writel(fcChip->SFQ->length, (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_LENGTH));
 
-  writel( fcChip->SFQ->length,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_LENGTH));
 
+	// tell TachLite where SEST table is & how long
+	writel(fcChip->SEST->base, (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE));
 
-         // tell TachLite where SEST table is & how long
-  writel( fcChip->SEST->base,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE));
+	printk("  cpqfcTS: SEST %p(virt): Wrote base %Xh @ %p\n", fcChip->SEST, fcChip->SEST->base, fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE);
 
-  printk("  cpqfcTS: SEST %p(virt): Wrote base %Xh @ %p\n",
-    fcChip->SEST, fcChip->SEST->base, 
-    fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE);
+	writel(fcChip->SEST->length, (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_LENGTH));
 
-  writel( fcChip->SEST->length,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_LENGTH));
-      
-  writel( (TL_EXT_SG_PAGE_COUNT-1),
-    (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_SG_PAGE));
+	writel((TL_EXT_SG_PAGE_COUNT - 1), (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_SG_PAGE));
 
 
-  LEAVE("CreateTachLiteQues");
+	LEAVE("CreateTachLiteQues");
 
-  return iStatus;
+	return iStatus;
 }
 
 
@@ -361,83 +310,79 @@
 
 int CpqTsResetTachLite(void *pHBA, int type)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  ULONG ulBuff, i;
-  int ret_status=0; // def. success
-
-  ENTER("ResetTach");
-  
-  switch(type)
-  {
-
-    case CLEAR_FCPORTS:
-
-      // in case he was running previously, mask Tach's interrupt
-      writeb( 0, (fcChip->Registers.ReMapMemBase + IINTEN));
-      
-     // de-allocate mem for any Logged in ports
-      // (e.g., our module is unloading)
-      // search the forward linked list, de-allocating
-      // the memory we allocated when the port was initially logged in
-      {
-        PFC_LOGGEDIN_PORT pLoggedInPort = fcChip->fcPorts.pNextPort;
-        PFC_LOGGEDIN_PORT ptr;
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) pHBA;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	u32 ulBuff, i;
+	int ret_status = 0;	// def. success
+
+	ENTER("ResetTach");
+
+	switch (type) {
+
+	case CLEAR_FCPORTS:
+
+		// in case he was running previously, mask Tach's interrupt
+		writeb(0, (fcChip->Registers.ReMapMemBase + IINTEN));
+
+		// de-allocate mem for any Logged in ports
+		// (e.g., our module is unloading)
+		// search the forward linked list, de-allocating
+		// the memory we allocated when the port was initially logged in
+		{
+			PFC_LOGGEDIN_PORT pLoggedInPort = fcChip->fcPorts.pNextPort;
+			PFC_LOGGEDIN_PORT ptr;
 //        printk("checking for allocated LoggedInPorts...\n");
-			
-        while( pLoggedInPort )
-        {
-          ptr = pLoggedInPort;
-          pLoggedInPort = ptr->pNextPort;
-//	  printk("kfree(%p) on FC LoggedInPort port_id 0x%06lX\n",
-//			  ptr, ptr->port_id);
-          kfree( ptr );
-        }
-      }
-      // (continue resetting hardware...)
-
-    case 1:                   // RESTART Tachyon (power-up state)
-
-      // in case he was running previously, mask Tach's interrupt
-      writeb( 0, (fcChip->Registers.ReMapMemBase + IINTEN));
-			      // turn OFF laser (NOTE: laser is turned
-                              // off during reset, because GPIO4 is cleared
-                              // to 0 by reset action - see TLUM, sec 7.22)
-                              // However, CPQ 64-bit HBAs have a "health
-                              // circuit" which keeps laser ON for a brief
-                              // period after it is turned off ( < 1s)
-      
-      fcChip->LaserControl( fcChip->Registers.ReMapMemBase, 0);
-  
-
-
-            // soft reset timing constraints require:
-            //   1. set RST to 1
-            //   2. read SOFTRST register 
-            //      (128 times per R. Callison code)
-            //   3. clear PCI ints
-            //   4. clear RST to 0
-      writel( 0xff000001L,
-        (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
-        
-      for( i=0; i<128; i++)
-        ulBuff = readl( fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST);
-
-        // clear the soft reset
-      for( i=0; i<8; i++)
-  	writel( 0, (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
-
-               
-
-			       // clear out our copy of Tach regs,
-			       // because they must be invalid now,
-			       // since TachLite reset all his regs.
-      CpqTsDestroyTachLiteQues(cpqfcHBAdata,0); // remove Host-based Que structs
-      cpqfcTSClearLinkStatusCounters(fcChip);  // clear our s/w accumulators
-                               // lower bits give GBIC info
-      fcChip->Registers.TYstatus.value = 
-	              readl( fcChip->Registers.TYstatus.address );
-      break;
+
+			while (pLoggedInPort) {
+				ptr = pLoggedInPort;
+				pLoggedInPort = ptr->pNextPort;
+//        printk("kfree(%p) on FC LoggedInPort port_id 0x%06lX\n",
+//                        ptr, ptr->port_id);
+				kfree(ptr);
+			}
+		}
+		// (continue resetting hardware...)
+
+	case 1:		// RESTART Tachyon (power-up state)
+
+		// in case he was running previously, mask Tach's interrupt
+		writeb(0, (fcChip->Registers.ReMapMemBase + IINTEN));
+		// turn OFF laser (NOTE: laser is turned
+		// off during reset, because GPIO4 is cleared
+		// to 0 by reset action - see TLUM, sec 7.22)
+		// However, CPQ 64-bit HBAs have a "health
+		// circuit" which keeps laser ON for a brief
+		// period after it is turned off ( < 1s)
+
+		fcChip->LaserControl(fcChip->Registers.ReMapMemBase, 0);
+
+
+
+		// soft reset timing constraints require:
+		//   1. set RST to 1
+		//   2. read SOFTRST register 
+		//      (128 times per R. Callison code)
+		//   3. clear PCI ints
+		//   4. clear RST to 0
+		writel(0xff000001L, (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
+
+		for (i = 0; i < 128; i++)
+			ulBuff = readl(fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST);
+
+		// clear the soft reset
+		for (i = 0; i < 8; i++)
+			writel(0, (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
+
+
+
+		// clear out our copy of Tach regs,
+		// because they must be invalid now,
+		// since TachLite reset all his regs.
+		CpqTsDestroyTachLiteQues(cpqfcHBAdata, 0);	// remove Host-based Que structs
+		cpqfcTSClearLinkStatusCounters(fcChip);	// clear our s/w accumulators
+		// lower bits give GBIC info
+		fcChip->Registers.TYstatus.value = readl(fcChip->Registers.TYstatus.address);
+		break;
 
 /*
     case 2:                   // freeze SCSI
@@ -447,12 +392,12 @@
 
     break;
 */
-    default:
-      ret_status = -1;  // invalid option passed to RESET function
-      break;
-  }
-  LEAVE("ResetTach");
-  return ret_status;
+	default:
+		ret_status = -1;	// invalid option passed to RESET function
+		break;
+	}
+	LEAVE("ResetTach");
+	return ret_status;
 }
 
 
@@ -461,18 +406,18 @@
 
 
 // 'addrBase' is IOBaseU for both TachLite and (older) Tachyon
-int CpqTsLaserControl( void* addrBase, int opcode )
+int CpqTsLaserControl(void *addrBase, int opcode)
 {
-  ULONG dwBuff;
+	u32 dwBuff;
 
-  dwBuff = readl((addrBase + TL_MEM_TACH_CONTROL) ); // read TL Control reg
-                                                    // (change only bit 4)
-  if( opcode == 1)
-    dwBuff |= ~0xffffffefL; // set - ON
-  else
-    dwBuff &= 0xffffffefL;  // clear - OFF
-  writel( dwBuff, (addrBase + TL_MEM_TACH_CONTROL)); // write TL Control reg
-  return 0;
+	dwBuff = readl((addrBase + TL_MEM_TACH_CONTROL));	// read TL Control reg
+	// (change only bit 4)
+	if (opcode == 1)
+		dwBuff |= ~0xffffffefL;	// set - ON
+	else
+		dwBuff &= 0xffffffefL;	// clear - OFF
+	writel(dwBuff, (addrBase + TL_MEM_TACH_CONTROL));	// write TL Control reg
+	return 0;
 }
 
 
@@ -484,102 +429,93 @@
 //   external loopback (GBIC - no FC loop)
 //   no loopback: L_PORT, external cable from GBIC required
 
-int CpqTsInitializeFrameManager( void *pChip, int opcode)
+int CpqTsInitializeFrameManager(void *pChip, int opcode)
 {
-  PTACHYON fcChip;
-  int iStatus;
-  ULONG wwnLo, wwnHi; // for readback verification
-
-  ENTER("InitializeFrameManager");
-  fcChip = (PTACHYON)pChip;
-  if( !fcChip->Registers.ReMapMemBase )   // undefined controller?
-    return -1;
-
-  // TL/TS UG, pg. 184
-  // 0x0065 = 100ms for RT_TOV
-  // 0x01f5 = 500ms for ED_TOV
-  // 0x07D1 = 2000ms 
-  fcChip->Registers.ed_tov.value = 0x006507D1; 
-  writel( fcChip->Registers.ed_tov.value,
-    (fcChip->Registers.ed_tov.address));
-      
-
-  // Set LP_TOV to the FC-AL2 specified 2 secs.
-  // TL/TS UG, pg. 185
-  writel( 0x07d00010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
-
-
-  // Now try to read the WWN from the adapter's NVRAM
-  iStatus = CpqTsReadWriteWWN( fcChip, 1); // '1' for READ
-
-  if( iStatus )   // NVRAM read failed?
-  {
-    printk(" WARNING! HBA NVRAM WWN read failed - make alias\n");
-    // make up a WWN.  If NULL or duplicated on loop, FC loop may hang!
-
-
-    fcChip->Registers.wwn_hi = (__u32)jiffies;
-    fcChip->Registers.wwn_hi |= 0x50000000L;
-    fcChip->Registers.wwn_lo = 0x44556677L;
-  }
-
-  
-  writel( fcChip->Registers.wwn_hi, 
-	  fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI);
-  
-  writel( fcChip->Registers.wwn_lo, 
-	  fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
-	  
-
-  // readback for verification:
-  wwnHi = readl( fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI ); 
-          
-  wwnLo = readl( fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
-  // test for correct chip register WRITE/READ
-  DEBUG_PCI( printk("  WWN %08X%08X\n",
-    fcChip->Registers.wwn_hi, fcChip->Registers.wwn_lo ) );
-    
-  if( wwnHi != fcChip->Registers.wwn_hi ||
-      wwnLo != fcChip->Registers.wwn_lo )
-  {
-    printk( "cpqfcTS: WorldWideName register load failed\n");
-    return -1; // FAILED!
-  }
-
-
-
-			// set Frame Manager Initialize command
-  fcChip->Registers.FMcontrol.value = 0x06;
-
-  // Note: for test/debug purposes, we may use "Hard" address,
-  // but we completely support "soft" addressing, including
-  // dynamically changing our address.
-  if( fcChip->Options.intLoopback == 1 )            // internal loopback
-    fcChip->Registers.FMconfig.value = 0x0f002080L;
-  else if( fcChip->Options.extLoopback == 1 )            // internal loopback
-    fcChip->Registers.FMconfig.value = 0x0f004080L;
-  else                  // L_Port
-    fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start)
+	PTACHYON fcChip;
+	int iStatus;
+	u32 wwnLo, wwnHi;	// for readback verification
+
+	ENTER("InitializeFrameManager");
+	fcChip = (PTACHYON) pChip;
+	if (!fcChip->Registers.ReMapMemBase)	// undefined controller?
+		return -1;
+
+	// TL/TS UG, pg. 184
+	// 0x0065 = 100ms for RT_TOV
+	// 0x01f5 = 500ms for ED_TOV
+	// 0x07D1 = 2000ms 
+	fcChip->Registers.ed_tov.value = 0x006507D1;
+	writel(fcChip->Registers.ed_tov.value, (fcChip->Registers.ed_tov.address));
+
+
+	// Set LP_TOV to the FC-AL2 specified 2 secs.
+	// TL/TS UG, pg. 185
+	writel(0x07d00010, fcChip->Registers.ReMapMemBase + TL_MEM_FM_TIMEOUT2);
+
+
+	// Now try to read the WWN from the adapter's NVRAM
+	iStatus = CpqTsReadWriteWWN(fcChip, 1);	// '1' for READ
+
+	if (iStatus)		// NVRAM read failed?
+	{
+		printk(" WARNING! HBA NVRAM WWN read failed - make alias\n");
+		// make up a WWN.  If NULL or duplicated on loop, FC loop may hang!
+
+
+		fcChip->Registers.wwn_hi = (__u32) jiffies;
+		fcChip->Registers.wwn_hi |= 0x50000000L;
+		fcChip->Registers.wwn_lo = 0x44556677L;
+	}
+
+
+	writel(fcChip->Registers.wwn_hi, fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI);
+
+	writel(fcChip->Registers.wwn_lo, fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
+
+
+	// readback for verification:
+	wwnHi = readl(fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI);
+
+	wwnLo = readl(fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
+	// test for correct chip register WRITE/READ
+	DEBUG_PCI(printk("  WWN %08X%08X\n", fcChip->Registers.wwn_hi, fcChip->Registers.wwn_lo));
+
+	if (wwnHi != fcChip->Registers.wwn_hi || wwnLo != fcChip->Registers.wwn_lo) {
+		printk("cpqfcTS: WorldWideName register load failed\n");
+		return -1;	// FAILED!
+	}
+
+
+	// set Frame Manager Initialize command
+	fcChip->Registers.FMcontrol.value = 0x06;
+
+	// Note: for test/debug purposes, we may use "Hard" address,
+	// but we completely support "soft" addressing, including
+	// dynamically changing our address.
+	if (fcChip->Options.intLoopback == 1)	// internal loopback
+		fcChip->Registers.FMconfig.value = 0x0f002080L;
+	else if (fcChip->Options.extLoopback == 1)	// internal loopback
+		fcChip->Registers.FMconfig.value = 0x0f004080L;
+	else			// L_Port
+		fcChip->Registers.FMconfig.value = 0x55000100L;	// hard address (55h start)
 //    fcChip->Registers.FMconfig.value = 0x01000080L; // soft address (can't pick)
 //    fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start)
-		
-  // write config to FM
 
-  if( !fcChip->Options.intLoopback && !fcChip->Options.extLoopback )
-                               // (also need LASER for real LOOP)
-    fcChip->LaserControl( fcChip->Registers.ReMapMemBase, 1); // turn on LASER
-
-  writel( fcChip->Registers.FMconfig.value,
-    fcChip->Registers.FMconfig.address);
-    
-
-			       // issue INITIALIZE command to FM - ACTION!
-  writel( fcChip->Registers.FMcontrol.value,
-    fcChip->Registers.FMcontrol.address);
-    
-  LEAVE("InitializeFrameManager");
-  
-  return 0;
+	// write config to FM
+
+	if (!fcChip->Options.intLoopback && !fcChip->Options.extLoopback)
+		// (also need LASER for real LOOP)
+		fcChip->LaserControl(fcChip->Registers.ReMapMemBase, 1);	// turn on LASER
+
+	writel(fcChip->Registers.FMconfig.value, fcChip->Registers.FMconfig.address);
+
+
+	// issue INITIALIZE command to FM - ACTION!
+	writel(fcChip->Registers.FMcontrol.value, fcChip->Registers.FMcontrol.address);
+
+	LEAVE("InitializeFrameManager");
+
+	return 0;
 }
 
 
@@ -588,102 +524,94 @@
 
 // This "look ahead" function examines the IMQ for occurence of
 // "type".  Returns 1 if found, 0 if not.
-static int PeekIMQEntry( PTACHYON fcChip, ULONG type)
+static int PeekIMQEntry(PTACHYON fcChip, u32 type)
 {
-  ULONG CI = fcChip->IMQ->consumerIndex;
-  ULONG PI = fcChip->IMQ->producerIndex; // snapshot of IMQ indexes
-  
-  while( CI != PI )
-  {                             // proceed with search
-    if( (++CI) >= IMQ_LEN ) CI = 0; // rollover check
-    
-    switch( type )
-    {
-      case ELS_LILP_FRAME:
-      {
-      // first, we need to find an Inbound Completion message,
-      // If we find it, check the incoming frame payload (1st word)
-      // for LILP frame
-        if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x104 )
-        { 
-          TachFCHDR_GCMND* fchs;
-          ULONG ulFibreFrame[2048/4];  // max DWORDS in incoming FC Frame
-	  USHORT SFQpi = (USHORT)(fcChip->IMQ->QEntry[CI].word[0] & 0x0fffL);
-
-	  CpqTsGetSFQEntry( fcChip,
-            SFQpi,        // SFQ producer ndx         
-	    ulFibreFrame, // contiguous dest. buffer
-	    FALSE);       // DON'T update chip--this is a "lookahead"
-          
-	  fchs = (TachFCHDR_GCMND*)&ulFibreFrame;
-          if( fchs->pl[0] == ELS_LILP_FRAME)
-	  {
-            return 1; // found the LILP frame!
-	  }
-	  else
-	  {
-	    // keep looking...
-	  }
-	}  
-      }
-      break;
+	u32 CI = fcChip->IMQ->consumerIndex;
+	u32 PI = fcChip->IMQ->producerIndex;	// snapshot of IMQ indexes
 
-      case OUTBOUND_COMPLETION:
-        if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x00 )
-	{
+	while (CI != PI) {	// proceed with search
+		if ((++CI) >= IMQ_LEN)
+			CI = 0;	// rollover check
+
+		switch (type) {
+		case ELS_LILP_FRAME:
+			{
+				// first, we need to find an Inbound Completion message,
+				// If we find it, check the incoming frame payload (1st word)
+				// for LILP frame
+				if ((fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x104) {
+					TachFCHDR_GCMND *fchs;
+					u32 ulFibreFrame[2048 / 4];	// max DWORDS in incoming FC Frame
+					u16 SFQpi = (u16) (fcChip->IMQ->QEntry[CI].word[0] & 0x0fffL);
+
+					CpqTsGetSFQEntry(fcChip, SFQpi,	// SFQ producer ndx         
+							 ulFibreFrame,	// contiguous dest. buffer
+							 FALSE);	// DON'T update chip--this is a "lookahead"
+
+					fchs = (TachFCHDR_GCMND *) & ulFibreFrame;
+					if (fchs->pl[0] == ELS_LILP_FRAME) {
+						return 1;	// found the LILP frame!
+					} else {
+						// keep looking...
+					}
+				}
+			}
+			break;
+
+		case OUTBOUND_COMPLETION:
+			if ((fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x00) {
+
+				// any OCM errors?
+				if (fcChip->IMQ->QEntry[CI].word[2] & 0x7a000000L)
+					return 1;	// found OCM error
+			}
+			break;
 
-          // any OCM errors?
-          if( fcChip->IMQ->QEntry[CI].word[2] & 0x7a000000L )
-            return 1;   	    // found OCM error
-	}
-      break;
 
 
-      
-      default:
-      break;
-    }
-  }
-  return 0; // failed to find "type"
+		default:
+			break;
+		}
+	}
+	return 0;		// failed to find "type"
 }
 
-			
-static void SetTachTOV( CPQFCHBA* cpqfcHBAdata)
+
+static void SetTachTOV(CPQFCHBA * cpqfcHBAdata)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip; 
-  
-  // TL/TS UG, pg. 184
-  // 0x0065 = 100ms for RT_TOV
-  // 0x01f5 = 500ms for ED_TOV
-  // 0x07d1 = 2000ms for ED_TOV
-
-  // SANMark Level 1 requires an "initialization backoff"
-  // (See "SANMark Test Suite Level 1":
-  // initialization_timeout.fcal.SANMark-1.fc)
-  // We have to use 2sec, 24sec, then 128sec when login/
-  // port discovery processes fail to complete.
-  
-  // when port discovery completes (logins done), we set
-  // ED_TOV to 500ms -- this is the normal operational case
-  // On the first Link Down, we'll move to 2 secs (7D1 ms)
-  if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x1f5)
-    fcChip->Registers.ed_tov.value = 0x006507D1; 
-  
-  // If we get another LST after we moved TOV to 2 sec,
-  // increase to 24 seconds (5DC1 ms) per SANMark!
-  else if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x7D1)
-    fcChip->Registers.ed_tov.value = 0x00655DC1; 
-
-  // If we get still another LST, set the max TOV (Tachyon
-  // has only 16 bits for ms timer, so the max is 65.5 sec)
-  else if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x5DC1)
-    fcChip->Registers.ed_tov.value = 0x0065FFFF; 
-
-  writel( fcChip->Registers.ed_tov.value,
-    (fcChip->Registers.ed_tov.address));
-  // keep the same 2sec LP_TOV 
-  writel( 0x07D00010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
-}	
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+
+	// TL/TS UG, pg. 184
+	// 0x0065 = 100ms for RT_TOV
+	// 0x01f5 = 500ms for ED_TOV
+	// 0x07d1 = 2000ms for ED_TOV
+
+	// SANMark Level 1 requires an "initialization backoff"
+	// (See "SANMark Test Suite Level 1":
+	// initialization_timeout.fcal.SANMark-1.fc)
+	// We have to use 2sec, 24sec, then 128sec when login/
+	// port discovery processes fail to complete.
+
+	// when port discovery completes (logins done), we set
+	// ED_TOV to 500ms -- this is the normal operational case
+	// On the first Link Down, we'll move to 2 secs (7D1 ms)
+	if ((fcChip->Registers.ed_tov.value & 0xFFFF) <= 0x1f5)
+		fcChip->Registers.ed_tov.value = 0x006507D1;
+
+	// If we get another LST after we moved TOV to 2 sec,
+	// increase to 24 seconds (5DC1 ms) per SANMark!
+	else if ((fcChip->Registers.ed_tov.value & 0xFFFF) <= 0x7D1)
+		fcChip->Registers.ed_tov.value = 0x00655DC1;
+
+	// If we get still another LST, set the max TOV (Tachyon
+	// has only 16 bits for ms timer, so the max is 65.5 sec)
+	else if ((fcChip->Registers.ed_tov.value & 0xFFFF) <= 0x5DC1)
+		fcChip->Registers.ed_tov.value = 0x0065FFFF;
+
+	writel(fcChip->Registers.ed_tov.value, (fcChip->Registers.ed_tov.address));
+	// keep the same 2sec LP_TOV 
+	writel(0x07D00010, fcChip->Registers.ReMapMemBase + TL_MEM_FM_TIMEOUT2);
+}
 
 
 // The IMQ is an array with IMQ_LEN length, each element (QEntry)
@@ -709,924 +637,844 @@
 
 int CpqTsProcessIMQEntry(void *host)
 {
-  struct Scsi_Host *HostAdapter = (struct Scsi_Host *)host;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip; 
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  int iStatus;
-  USHORT i, RPCset, DPCset;
-  ULONG x_ID;
-  ULONG ulBuff, dwStatus;
-  TachFCHDR_GCMND* fchs;
-  ULONG ulFibreFrame[2048/4];  // max number of DWORDS in incoming Fibre Frame
-  UCHAR ucInboundMessageType;  // Inbound CM, dword 3 "type" field
-
-  ENTER("ProcessIMQEntry");
-   
-
-				// check TachLite's IMQ producer index -
-				// is a new message waiting for us?
-				// equal indexes means empty que
+	struct Scsi_Host *HostAdapter = (struct Scsi_Host *) host;
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	int iStatus;
+	u16 i, RPCset, DPCset;
+	u32 x_ID;
+	u32 ulBuff, dwStatus;
+	TachFCHDR_GCMND *fchs;
+	u32 ulFibreFrame[2048 / 4];	// max number of DWORDS in incoming Fibre Frame
+	u8 ucInboundMessageType;	// Inbound CM, dword 3 "type" field
+
+	ENTER("ProcessIMQEntry");
+
+
+	// check TachLite's IMQ producer index -
+	// is a new message waiting for us?
+	// equal indexes means empty que
 
-  if( fcChip->IMQ->producerIndex != fcChip->IMQ->consumerIndex )
-  {                             // need to process message
+	if (fcChip->IMQ->producerIndex != fcChip->IMQ->consumerIndex) {	// need to process message
 
 
 #ifdef IMQ_DEBUG
-    printk("PI %X, CI %X  type: %X\n", 
-      fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex,
-      fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type);
-#endif                                
-    // Examine Completion Messages in IMQ
-    // what CM_Type?
-    switch( (UCHAR)(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type
-                    & 0xffL) )
-    {
-    case OUTBOUND_COMPLETION:
-
-      // Remarks:
-      // x_IDs (OX_ID, RX_ID) are partitioned by SEST entries
-      // (starting at 0), and SFS entries (starting at
-      // SEST_LEN -- outside the SEST space).
-      // Psuedo code:
-      // x_ID (OX_ID or RX_ID) from message is Trans_ID or SEST index
-      // range check - x_ID
-      //   if x_ID outside 'Transactions' length, error - exit
-      // if any OCM error, copy error status to Exchange slot
-      // if FCP ASSIST transaction (x_ID within SEST),
-      //   call fcComplete (to App)
-      // ...
-
-
-      ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1];
-      x_ID = ulBuff & 0x7fffL;     // lower 14 bits SEST_Index/Trans_ID
-                                     // Range check CM OX/RX_ID value...
-      if( x_ID < TACH_MAX_XID )   // don't go beyond array space
-      {
-
-
-	if( ulBuff & 0x20000000L ) // RPC -Response Phase Complete?
-          RPCset = 1;              // (SEST transactions only)
-        else
-          RPCset = 0;
-
-        if( ulBuff & 0x40000000L ) // DPC -Data Phase Complete?
-          DPCset = 1;              // (SEST transactions only)
-        else
-          DPCset = 0;
-                // set the status for this Outbound transaction's ID
-        dwStatus = 0L;
-        if( ulBuff & 0x10000000L ) // SPE? (SEST Programming Error)
-            dwStatus |= SESTPROG_ERR;
-
-        ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2];
-        if( ulBuff & 0x7a000000L ) // any other errs?
-        {
-          if( ulBuff & 0x40000000L )
-            dwStatus |= INV_ENTRY;
-          if( ulBuff & 0x20000000L )
-            dwStatus |= FRAME_TO;        // FTO
-          if( ulBuff & 0x10000000L )
-            dwStatus |= HOSTPROG_ERR;
-          if( ulBuff & 0x08000000L )
-            dwStatus |= LINKFAIL_TX;
-          if( ulBuff & 0x02000000L )
-            dwStatus |= ABORTSEQ_NOTIFY;  // ASN
-        }
-
-	  
-	if( dwStatus )          // any errors?
-        {
-                  // set the Outbound Completion status
-          Exchanges->fcExchange[ x_ID ].status |= dwStatus;
-
-          // if this Outbound frame was for a SEST entry, automatically
-          // reque it in the case of LINKFAIL (it will restart on PDISC)
-          if( x_ID < TACH_SEST_LEN )
-          {
-
-            printk(" #OCM error %Xh x_ID %X# ", 
-		    dwStatus, x_ID);
-
-	    Exchanges->fcExchange[x_ID].timeOut = 30000; // seconds default
-                                                 
-
-	    // We Q ABTS for each exchange.
-	    // NOTE: We can get FRAME_TO on bad alpa (device gone).  Since
-	    // bad alpa is reported before FRAME_TO, examine the status
-	    // flags to see if the device is removed.  If so, DON'T
-	    // post an ABTS, since it will be terminated by the bad alpa
-	    // message.
-	    if( dwStatus & FRAME_TO ) // check for device removed...
-	    {
-	      if( !(Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) )
-	      { 
-		// presumes device is still there: send ABTS.
-  
-                cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
-	      }
-	    }
-	    else  // Abort all other errors
-	    {
-              cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
-	    }
-
-            // if the HPE bit is set, we have to CLose the LOOP
-            // (see TL/TS UG, pg. 239)
-
-            if( dwStatus &= HOSTPROG_ERR )
-            // set CL bit (see TL/TS UG, pg. 172)
-              writel( 4, fcChip->Registers.FMcontrol.address);
-          }
-        }
-          // NOTE: we don't necessarily care about ALL completion messages...
-                                      // SCSI resp. complete OR
-        if( ((x_ID < TACH_SEST_LEN) && RPCset)|| 
-             (x_ID >= TACH_SEST_LEN) )  // non-SCSI command
-        {
-              // exchange done; complete to upper levels with status
-              // (if necessary) and free the exchange slot
-            
-
-          if( x_ID >= TACH_SEST_LEN ) // Link Service Outbound frame?
-                                    // A Request or Reply has been sent
-          {                         // signal waiting WorkerThread
-
-            up( cpqfcHBAdata->TYOBcomplete);   // frame is OUT of Tach
-
-                                    // WorkerThread will complete Xchng
-          }
-          else  // X_ID is for FCP assist (SEST)
-          {
-              // TBD (target mode)
+		printk("PI %X, CI %X  type: %X\n", fcChip->IMQ->producerIndex, fcChip->IMQ->consumerIndex, fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type);
+#endif
+		// Examine Completion Messages in IMQ
+		// what CM_Type?
+		switch ((u8) (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type & 0xffL)) {
+		case OUTBOUND_COMPLETION:
+
+			// Remarks:
+			// x_IDs (OX_ID, RX_ID) are partitioned by SEST entries
+			// (starting at 0), and SFS entries (starting at
+			// SEST_LEN -- outside the SEST space).
+			// Psuedo code:
+			// x_ID (OX_ID or RX_ID) from message is Trans_ID or SEST index
+			// range check - x_ID
+			//   if x_ID outside 'Transactions' length, error - exit
+			// if any OCM error, copy error status to Exchange slot
+			// if FCP ASSIST transaction (x_ID within SEST),
+			//   call fcComplete (to App)
+			// ...
+
+
+			ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1];
+			x_ID = ulBuff & 0x7fffL;	// lower 14 bits SEST_Index/Trans_ID
+			// Range check CM OX/RX_ID value...
+			if (x_ID < TACH_MAX_XID)	// don't go beyond array space
+			{
+
+
+				if (ulBuff & 0x20000000L)	// RPC -Response Phase Complete?
+					RPCset = 1;	// (SEST transactions only)
+				else
+					RPCset = 0;
+
+				if (ulBuff & 0x40000000L)	// DPC -Data Phase Complete?
+					DPCset = 1;	// (SEST transactions only)
+				else
+					DPCset = 0;
+				// set the status for this Outbound transaction's ID
+				dwStatus = 0L;
+				if (ulBuff & 0x10000000L)	// SPE? (SEST Programming Error)
+					dwStatus |= SESTPROG_ERR;
+
+				ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2];
+				if (ulBuff & 0x7a000000L)	// any other errs?
+				{
+					if (ulBuff & 0x40000000L)
+						dwStatus |= INV_ENTRY;
+					if (ulBuff & 0x20000000L)
+						dwStatus |= FRAME_TO;	// FTO
+					if (ulBuff & 0x10000000L)
+						dwStatus |= HOSTPROG_ERR;
+					if (ulBuff & 0x08000000L)
+						dwStatus |= LINKFAIL_TX;
+					if (ulBuff & 0x02000000L)
+						dwStatus |= ABORTSEQ_NOTIFY;	// ASN
+				}
+
+
+				if (dwStatus)	// any errors?
+				{
+					// set the Outbound Completion status
+					Exchanges->fcExchange[x_ID].status |= dwStatus;
+
+					// if this Outbound frame was for a SEST entry, automatically
+					// reque it in the case of LINKFAIL (it will restart on PDISC)
+					if (x_ID < TACH_SEST_LEN) {
+
+						printk(" #OCM error %Xh x_ID %X# ", dwStatus, x_ID);
+
+						Exchanges->fcExchange[x_ID].timeOut = 30000;	// seconds default
+
+
+						// We Q ABTS for each exchange.
+						// NOTE: We can get FRAME_TO on bad alpa (device gone).  Since
+						// bad alpa is reported before FRAME_TO, examine the status
+						// flags to see if the device is removed.  If so, DON'T
+						// post an ABTS, since it will be terminated by the bad alpa
+						// message.
+						if (dwStatus & FRAME_TO)	// check for device removed...
+						{
+							if (!(Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)) {
+								// presumes device is still there: send ABTS.
+
+								cpqfcTSPutLinkQue(cpqfcHBAdata, BLS_ABTS, &x_ID);
+							}
+						} else	// Abort all other errors
+						{
+							cpqfcTSPutLinkQue(cpqfcHBAdata, BLS_ABTS, &x_ID);
+						}
+
+						// if the HPE bit is set, we have to CLose the LOOP
+						// (see TL/TS UG, pg. 239)
+
+						if (dwStatus &= HOSTPROG_ERR)
+							// set CL bit (see TL/TS UG, pg. 172)
+							writel(4, fcChip->Registers.FMcontrol.address);
+					}
+				}
+				// NOTE: we don't necessarily care about ALL completion messages...
+				// SCSI resp. complete OR
+				if (((x_ID < TACH_SEST_LEN) && RPCset) || (x_ID >= TACH_SEST_LEN))	// non-SCSI command
+				{
+					// exchange done; complete to upper levels with status
+					// (if necessary) and free the exchange slot
+
+
+					if (x_ID >= TACH_SEST_LEN)	// Link Service Outbound frame?
+						// A Request or Reply has been sent
+					{	// signal waiting WorkerThread
+
+						up(cpqfcHBAdata->TYOBcomplete);	// frame is OUT of Tach
+
+						// WorkerThread will complete Xchng
+					} else	// X_ID is for FCP assist (SEST)
+					{
+						// TBD (target mode)
 //            fcCompleteExchange( fcChip, x_ID); // TRE completed
-          }
-        }
-      }
-      else  // ERROR CONDITION!  bogus x_ID in completion message
-      {
-
-        printk(" ProcessIMQ (OBCM) x_id out of range %Xh\n", x_ID);
-
-      }
+					}
+				}
+			} else	// ERROR CONDITION!  bogus x_ID in completion message
+			{
 
+				printk(" ProcessIMQ (OBCM) x_id out of range %Xh\n", x_ID);
 
+			}
 
-          // Load the Frame Manager's error counters.  We check them here
-          // because presumably the link is up and healthy enough for the
-          // counters to be meaningful (i.e., don't check them while loop
-          // is initializing).
-      fcChip->Registers.FMLinkStatus1.value =    // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus1.address);
-                  
-      fcChip->Registers.FMLinkStatus2.value =    // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus2.address);
-            
 
-      fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators
-    break;
 
+			// Load the Frame Manager's error counters.  We check them here
+			// because presumably the link is up and healthy enough for the
+			// counters to be meaningful (i.e., don't check them while loop
+			// is initializing).
+			fcChip->Registers.FMLinkStatus1.value =	// get TL's counter
+			    readl(fcChip->Registers.FMLinkStatus1.address);
 
+			fcChip->Registers.FMLinkStatus2.value =	// get TL's counter
+			    readl(fcChip->Registers.FMLinkStatus2.address);
 
-    case ERROR_IDLE_COMPLETION:  // TachLite Error Idle...
-    
-    // We usually get this when the link goes down during heavy traffic.
-    // For now, presume that if SEST Exchanges are open, we will
-    // get this as our cue to INVALIDATE all SEST entries
-    // (and we OWN all the SEST entries).
-    // See TL/TS UG, pg. 53
-    
-      for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
-      {
-
-        // Does this VALid SEST entry need to be invalidated for Abort?
-        fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF; 
-      }
-      
-      CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachyon, if Link OK
 
-    break;
+			fcParseLinkStatusCounters(fcChip);	// load into 6 s/w accumulators
+			break;
+
+
+
+		case ERROR_IDLE_COMPLETION:	// TachLite Error Idle...
+
+			// We usually get this when the link goes down during heavy traffic.
+			// For now, presume that if SEST Exchanges are open, we will
+			// get this as our cue to INVALIDATE all SEST entries
+			// (and we OWN all the SEST entries).
+			// See TL/TS UG, pg. 53
+
+			for (x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) {
+
+				// Does this VALid SEST entry need to be invalidated for Abort?
+				fcChip->SEST->u[x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
+			}
+
+			CpqTsUnFreezeTachlite(fcChip, 2);	// unfreeze Tachyon, if Link OK
+
+			break;
+
+
+		case INBOUND_SFS_COMPLETION:	//0x04
+			// NOTE! we must process this SFQ message to avoid SFQ filling
+			// up and stopping TachLite.  Incoming commands are placed here,
+			// as well as 'unknown' frames (e.g. LIP loop position data)
+			// write this CM's producer index to global...
+			// TL/TS UG, pg 234:
+			// Type: 0 - reserved
+			//       1 - Unassisted FCP
+			//       2 - BAD FCP
+			//       3 - Unkown Frame
+			//       4-F reserved
+
 
+			fcChip->SFQ->producerIndex = (u16)
+			    (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] & 0x0fffL);
 
-    case INBOUND_SFS_COMPLETION:  //0x04
-          // NOTE! we must process this SFQ message to avoid SFQ filling
-          // up and stopping TachLite.  Incoming commands are placed here,
-          // as well as 'unknown' frames (e.g. LIP loop position data)
-          // write this CM's producer index to global...
-          // TL/TS UG, pg 234:
-          // Type: 0 - reserved
-          //       1 - Unassisted FCP
-          //       2 - BAD FCP
-          //       3 - Unkown Frame
-          //       4-F reserved
-
-
-      fcChip->SFQ->producerIndex = (USHORT)
-        (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] & 0x0fffL);
-
-
-      ucInboundMessageType = 0;  // default to useless frame
-
-        // we can only process two Types: 1, Unassisted FCP, and 3, Unknown
-        // Also, we aren't interested in processing frame fragments
-        // so don't Que anything with 'LKF' bit set
-      if( !(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] 
-        & 0x40000000) )  // 'LKF' link failure bit clear?
-      {
-        ucInboundMessageType = (UCHAR)  // ICM DWord3, "Type"
-        (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] & 0x0fL);
-      }
-      else
-      {
-	fcChip->fcStats.linkFailRX++;
+
+			ucInboundMessageType = 0;	// default to useless frame
+
+			// we can only process two Types: 1, Unassisted FCP, and 3, Unknown
+			// Also, we aren't interested in processing frame fragments
+			// so don't Que anything with 'LKF' bit set
+			if (!(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2]
+			      & 0x40000000))	// 'LKF' link failure bit clear?
+			{
+				ucInboundMessageType = (u8)	// ICM DWord3, "Type"
+				    (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] & 0x0fL);
+			} else {
+				fcChip->fcStats.linkFailRX++;
 //        printk("LKF (link failure) bit set on inbound message\n");
-      }
+			}
+
+			// clears SFQ entry from Tachyon buffer; copies to contiguous ulBuff
+			CpqTsGetSFQEntry(fcChip,	// i.e. this Device Object
+					 (u16) fcChip->SFQ->producerIndex,	// SFQ producer ndx         
+					 ulFibreFrame, TRUE);	// contiguous destination buffer, update chip
+
+			// analyze the incoming frame outside the INT handler...
+			// (i.e., Worker)
+
+			if (ucInboundMessageType == 1) {
+				fchs = (TachFCHDR_GCMND *) ulFibreFrame;	// cast to examine IB frame
+				// don't fill up our Q with garbage - only accept FCP-CMND  
+				// or XRDY frames
+				if ((fchs->d_id & 0xFF000000) == 0x06000000)	// CMND
+				{
+					// someone sent us a SCSI command
 
-          // clears SFQ entry from Tachyon buffer; copies to contiguous ulBuff
-      CpqTsGetSFQEntry(
-        fcChip,                  // i.e. this Device Object
-        (USHORT)fcChip->SFQ->producerIndex,  // SFQ producer ndx         
-        ulFibreFrame, TRUE);    // contiguous destination buffer, update chip
-                     
-        // analyze the incoming frame outside the INT handler...
-        // (i.e., Worker)
-
-      if( ucInboundMessageType == 1 )
-      {
-        fchs = (TachFCHDR_GCMND*)ulFibreFrame; // cast to examine IB frame
-        // don't fill up our Q with garbage - only accept FCP-CMND  
-        // or XRDY frames
-        if( (fchs->d_id & 0xFF000000) == 0x06000000 ) // CMND
-        {
-	  // someone sent us a SCSI command
-	  
 //          fcPutScsiQue( cpqfcHBAdata, 
 //                        SFQ_UNASSISTED_FCP, ulFibreFrame); 
-	}
-	else if( ((fchs->d_id & 0xFF000000) == 0x07000000) || // RSP (status)
-            (fchs->d_id & 0xFF000000) == 0x05000000 )  // XRDY  
-	{
-	  ULONG x_ID;
-	  // Unfortunately, ABTS requires a Freeze on the chip so
-	  // we can modify the shared memory SEST.  When frozen,
-	  // any received Exchange frames cannot be processed by
-	  // Tachyon, so they will be dumped in here.  It is too
-	  // complex to attempt the reconstruct these frames in
-	  // the correct Exchange context, so we simply seek to
-	  // find status or transfer ready frames, and cause the
-	  // exchange to complete with errors before the timeout
-	  // expires.  We use a Linux Scsi Cmnd result code that
-	  // causes immediate retry.
-	  
-
-	  // Do we have an open exchange that matches this s_id
-	  // and ox_id?
-	  for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
-	  {
-            if( (fchs->s_id & 0xFFFFFF) == 
-                 (Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF) 
-		       &&
-                (fchs->ox_rx_id & 0xFFFF0000) == 
-                 (Exchanges->fcExchange[x_ID].fchs.ox_rx_id & 0xFFFF0000) )
-	    {
-    //          printk(" #R/X frame x_ID %08X# ", fchs->ox_rx_id );
-              // simulate the anticipated error - since the
-	      // SEST was frozen, frames were lost...
-              Exchanges->fcExchange[ x_ID ].status |= SFQ_FRAME;
-              
-	      // presumes device is still there: send ABTS.
-              cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
-	      break;  // done
-	    }
-	  }
-	}
-	  
-      }
-          
-      else if( ucInboundMessageType == 3)
-      {
-        // FC Link Service frames (e.g. PLOGI, ACC) come in here.  
-        cpqfcTSPutLinkQue( cpqfcHBAdata, SFQ_UNKNOWN, ulFibreFrame); 
-                          
-      }
+				} else if (((fchs->d_id & 0xFF000000) == 0x07000000) ||	// RSP (status)
+					   (fchs->d_id & 0xFF000000) == 0x05000000)	// XRDY  
+				{
+					u32 x_ID;
+					// Unfortunately, ABTS requires a Freeze on the chip so
+					// we can modify the shared memory SEST.  When frozen,
+					// any received Exchange frames cannot be processed by
+					// Tachyon, so they will be dumped in here.  It is too
+					// complex to attempt the reconstruct these frames in
+					// the correct Exchange context, so we simply seek to
+					// find status or transfer ready frames, and cause the
+					// exchange to complete with errors before the timeout
+					// expires.  We use a Linux Scsi Cmnd result code that
+					// causes immediate retry.
+
+
+					// Do we have an open exchange that matches this s_id
+					// and ox_id?
+					for (x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) {
+						if ((fchs->s_id & 0xFFFFFF) == (Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF)
+						    && (fchs->ox_rx_id & 0xFFFF0000) == (Exchanges->fcExchange[x_ID].fchs.ox_rx_id & 0xFFFF0000)) {
+							//          printk(" #R/X frame x_ID %08X# ", fchs->ox_rx_id );
+							// simulate the anticipated error - since the
+							// SEST was frozen, frames were lost...
+							Exchanges->fcExchange[x_ID].status |= SFQ_FRAME;
+
+							// presumes device is still there: send ABTS.
+							cpqfcTSPutLinkQue(cpqfcHBAdata, BLS_ABTS, &x_ID);
+							break;	// done
+						}
+					}
+				}
+
+			}
+
+			else if (ucInboundMessageType == 3) {
+				// FC Link Service frames (e.g. PLOGI, ACC) come in here.  
+				cpqfcTSPutLinkQue(cpqfcHBAdata, SFQ_UNKNOWN, ulFibreFrame);
+
+			}
 
-      else if( ucInboundMessageType == 2 ) // "bad FCP"?
-      {
+			else if (ucInboundMessageType == 2)	// "bad FCP"?
+			{
 #ifdef IMQ_DEBUG
-        printk("Bad FCP incoming frame discarded\n");
+				printk("Bad FCP incoming frame discarded\n");
 #endif
-      }
+			}
 
-      else // don't know this type
-      {
-#ifdef IMQ_DEBUG 
-        printk("Incoming frame discarded, type: %Xh\n", ucInboundMessageType);
+			else	// don't know this type
+			{
+#ifdef IMQ_DEBUG
+				printk("Incoming frame discarded, type: %Xh\n", ucInboundMessageType);
 #endif
-      }
-        
-        // Check the Frame Manager's error counters.  We check them here
-        // because presumably the link is up and healthy enough for the
-        // counters to be meaningful (i.e., don't check them while loop
-        // is initializing).
-      fcChip->Registers.FMLinkStatus1.value =    // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus1.address);
-                  
-
-      fcChip->Registers.FMLinkStatus2.value =    // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus2.address);
-                
-
-      break;
+			}
 
+			// Check the Frame Manager's error counters.  We check them here
+			// because presumably the link is up and healthy enough for the
+			// counters to be meaningful (i.e., don't check them while loop
+			// is initializing).
+			fcChip->Registers.FMLinkStatus1.value =	// get TL's counter
+			    readl(fcChip->Registers.FMLinkStatus1.address);
 
 
+			fcChip->Registers.FMLinkStatus2.value =	// get TL's counter
+			    readl(fcChip->Registers.FMLinkStatus2.address);
 
-                    // We get this CM because we issued a freeze
-                    // command to stop outbound frames.  We issue the
-                    // freeze command at Link Up time; when this message
-                    // is received, the ERQ base can be switched and PDISC
-                    // frames can be sent.
-
-      
-    case ERQ_FROZEN_COMPLETION:  // note: expect ERQ followed immediately
-                                 // by FCP when freezing TL
-      fcChip->Registers.TYstatus.value =         // read what's frozen
-        readl(fcChip->Registers.TYstatus.address);
-      // (do nothing; wait for FCP frozen message)
-      break;
-    case FCP_FROZEN_COMPLETION:
-      
-      fcChip->Registers.TYstatus.value =         // read what's frozen
-        readl(fcChip->Registers.TYstatus.address);
-      
-      // Signal the kernel thread to proceed with SEST modification
-      up( cpqfcHBAdata->TachFrozen);
-
-      break;
 
+			break;
 
 
-    case INBOUND_C1_TIMEOUT:
-    case MFS_BUF_WARN:
-    case IMQ_BUF_WARN:
-    break;
 
 
+			// We get this CM because we issued a freeze
+			// command to stop outbound frames.  We issue the
+			// freeze command at Link Up time; when this message
+			// is received, the ERQ base can be switched and PDISC
+			// frames can be sent.
 
 
+		case ERQ_FROZEN_COMPLETION:	// note: expect ERQ followed immediately
+			// by FCP when freezing TL
+			fcChip->Registers.TYstatus.value =	// read what's frozen
+			    readl(fcChip->Registers.TYstatus.address);
+			// (do nothing; wait for FCP frozen message)
+			break;
+		case FCP_FROZEN_COMPLETION:
 
-        // In older Tachyons, we 'clear' the internal 'core' interrupt state
-        // by reading the FMstatus register.  In newer TachLite (Tachyon),
-        // we must WRITE the register
-        // to clear the condition (TL/TS UG, pg 179)
-    case FRAME_MGR_INTERRUPT:
-    {
-      PFC_LOGGEDIN_PORT pLoggedInPort; 
-
-      fcChip->Registers.FMstatus.value = 
-        readl( fcChip->Registers.FMstatus.address );
-                
-      // PROBLEM: It is possible, especially with "dumb" hubs that
-      // don't automatically LIP on by-pass of ports that are going
-      // away, for the hub by-pass process to destroy critical 
-      // ordered sets of a frame.  The result of this is a hung LPSM
-      // (Loop Port State Machine), which on Tachyon results in a
-      // (default 2 sec) Loop State Timeout (LST) FM message.  We 
-      // want to avoid this relatively huge timeout by detecting
-      // likely scenarios which will result in LST.
-      // To do this, we could examine FMstatus for Loss of Synchronization
-      // and/or Elastic Store (ES) errors.  Of these, Elastic Store is better
-      // because we get this indication more quickly than the LOS.
-      // Not all ES errors are harmfull, so we don't want to LIP on every
-      // ES.  Instead, on every ES, detect whether our LPSM in in one
-      // of the LST states: ARBITRATING, OPEN, OPENED, XMITTED CLOSE,
-      // or RECEIVED CLOSE.  (See TL/TS UG, pg. 181)
-      // If any of these LPSM states are detected
-      // in combination with the LIP while LDn is not set, 
-      // send an FM init (LIP F7,F7 for loops)!
-      // It is critical to the physical link stability NOT to reset (LIP)
-      // more than absolutely necessary; this is a basic premise of the
-      // SANMark level 1 spec.
-      {
-	ULONG Lpsm = (fcChip->Registers.FMstatus.value & 0xF0) >>4;
-	
-	if( (fcChip->Registers.FMstatus.value & 0x400)  // ElasticStore?
-                      &&
-            !(fcChip->Registers.FMstatus.value & 0x100) // NOT LDn
-	              &&
-            !(fcChip->Registers.FMstatus.value & 0x1000)) // NOT LF
-	{
-	  if( (Lpsm != 0) || // not MONITORING? or
-	      !(Lpsm & 0x8) )// not already offline?
-	  {
-	  // now check the particular LST states...
-            if( (Lpsm == ARBITRATING) || (Lpsm == OPEN) ||
-	      (Lpsm == OPENED)      || (Lpsm == XMITTD_CLOSE) ||
-	      (Lpsm == RCVD_CLOSE) )
-	    {
-	      // re-init the loop before it hangs itself!
-              printk(" #req FMinit on E-S: LPSM %Xh# ",Lpsm);
-
-
-	      fcChip->fcStats.FMinits++;
-              writel( 6, fcChip->Registers.FMcontrol.address); // LIP
-	    }
-	  }
-	}
-	else if( fcChip->Registers.FMstatus.value & 0x40000 ) // LST?
-	{
-          printk(" #req FMinit on LST, LPSM %Xh# ",Lpsm);
-	 
-          fcChip->fcStats.FMinits++;
-          writel( 6, fcChip->Registers.FMcontrol.address);  // LIP
-	}  
-      }
-
-
-      // clear only the 'interrupting' type bits for this REG read
-      writel( (fcChip->Registers.FMstatus.value & 0xff3fff00L),
-        fcChip->Registers.FMstatus.address);
-                          
-
-               // copy frame manager status to unused ULONG slot
-      fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] =
-          fcChip->Registers.FMstatus.value; // (for debugging)
-
-
-          // Load the Frame Manager's error counters.  We check them here
-          // because presumably the link is up and healthy enough for the
-          // counters to be meaningful (i.e., don't check them while loop
-          // is initializing).
-      fcChip->Registers.FMLinkStatus1.value =   // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus1.address);
-            
-      fcChip->Registers.FMLinkStatus2.value =   // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus2.address);
-          
-          // Get FM BB_Credit Zero Reg - does not clear on READ
-      fcChip->Registers.FMBB_CreditZero.value =   // get TL's counter
-        readl(fcChip->Registers.FMBB_CreditZero.address);
-            
-
-
-      fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators
-
-
-               // LINK DOWN
-
-      if( fcChip->Registers.FMstatus.value & 0x100L ) // Link DOWN bit
-      {                                 
-	
-#ifdef IMQ_DEBUG
-        printk("LinkDn\n");
-#endif
-        printk(" #LDn# ");
-        
-        fcChip->fcStats.linkDown++;
-        
-	SetTachTOV( cpqfcHBAdata);  // must set according to SANMark
+			fcChip->Registers.TYstatus.value =	// read what's frozen
+			    readl(fcChip->Registers.TYstatus.address);
 
-	// Check the ERQ - force it to be "empty" to prevent Tach
-	// from sending out frames before we do logins.
+			// Signal the kernel thread to proceed with SEST modification
+			up(cpqfcHBAdata->TachFrozen);
 
+			break;
+
+
+
+		case INBOUND_C1_TIMEOUT:
+		case MFS_BUF_WARN:
+		case IMQ_BUF_WARN:
+			break;
+
+
+
+
+
+			// In older Tachyons, we 'clear' the internal 'core' interrupt state
+			// by reading the FMstatus register.  In newer TachLite (Tachyon),
+			// we must WRITE the register
+			// to clear the condition (TL/TS UG, pg 179)
+		case FRAME_MGR_INTERRUPT:
+			{
+				PFC_LOGGEDIN_PORT pLoggedInPort;
+
+				fcChip->Registers.FMstatus.value = readl(fcChip->Registers.FMstatus.address);
+
+				// PROBLEM: It is possible, especially with "dumb" hubs that
+				// don't automatically LIP on by-pass of ports that are going
+				// away, for the hub by-pass process to destroy critical 
+				// ordered sets of a frame.  The result of this is a hung LPSM
+				// (Loop Port State Machine), which on Tachyon results in a
+				// (default 2 sec) Loop State Timeout (LST) FM message.  We 
+				// want to avoid this relatively huge timeout by detecting
+				// likely scenarios which will result in LST.
+				// To do this, we could examine FMstatus for Loss of Synchronization
+				// and/or Elastic Store (ES) errors.  Of these, Elastic Store is better
+				// because we get this indication more quickly than the LOS.
+				// Not all ES errors are harmfull, so we don't want to LIP on every
+				// ES.  Instead, on every ES, detect whether our LPSM in in one
+				// of the LST states: ARBITRATING, OPEN, OPENED, XMITTED CLOSE,
+				// or RECEIVED CLOSE.  (See TL/TS UG, pg. 181)
+				// If any of these LPSM states are detected
+				// in combination with the LIP while LDn is not set, 
+				// send an FM init (LIP F7,F7 for loops)!
+				// It is critical to the physical link stability NOT to reset (LIP)
+				// more than absolutely necessary; this is a basic premise of the
+				// SANMark level 1 spec.
+				{
+					u32 Lpsm = (fcChip->Registers.FMstatus.value & 0xF0) >> 4;
+
+					if ((fcChip->Registers.FMstatus.value & 0x400)	// ElasticStore?
+					    && !(fcChip->Registers.FMstatus.value & 0x100)	// NOT LDn
+					    && !(fcChip->Registers.FMstatus.value & 0x1000))	// NOT LF
+					{
+						if ((Lpsm != 0) ||	// not MONITORING? or
+						    !(Lpsm & 0x8))	// not already offline?
+						{
+							// now check the particular LST states...
+							if ((Lpsm == ARBITRATING) || (Lpsm == OPEN) || (Lpsm == OPENED) || (Lpsm == XMITTD_CLOSE) || (Lpsm == RCVD_CLOSE)) {
+								// re-init the loop before it hangs itself!
+								printk(" #req FMinit on E-S: LPSM %Xh# ", Lpsm);
+
+
+								fcChip->fcStats.FMinits++;
+								writel(6, fcChip->Registers.FMcontrol.address);	// LIP
+							}
+						}
+					} else if (fcChip->Registers.FMstatus.value & 0x40000)	// LST?
+					{
+						printk(" #req FMinit on LST, LPSM %Xh# ", Lpsm);
+
+						fcChip->fcStats.FMinits++;
+						writel(6, fcChip->Registers.FMcontrol.address);	// LIP
+					}
+				}
+
+
+				// clear only the 'interrupting' type bits for this REG read
+				writel((fcChip->Registers.FMstatus.value & 0xff3fff00L), fcChip->Registers.FMstatus.address);
+
+
+				// copy frame manager status to unused u32 slot
+				fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] = fcChip->Registers.FMstatus.value;	// (for debugging)
+
+
+				// Load the Frame Manager's error counters.  We check them here
+				// because presumably the link is up and healthy enough for the
+				// counters to be meaningful (i.e., don't check them while loop
+				// is initializing).
+				fcChip->Registers.FMLinkStatus1.value =	// get TL's counter
+				    readl(fcChip->Registers.FMLinkStatus1.address);
+
+				fcChip->Registers.FMLinkStatus2.value =	// get TL's counter
+				    readl(fcChip->Registers.FMLinkStatus2.address);
+
+				// Get FM BB_Credit Zero Reg - does not clear on READ
+				fcChip->Registers.FMBB_CreditZero.value =	// get TL's counter
+				    readl(fcChip->Registers.FMBB_CreditZero.address);
+
+
+
+				fcParseLinkStatusCounters(fcChip);	// load into 6 s/w accumulators
+
+
+				// LINK DOWN
+
+				if (fcChip->Registers.FMstatus.value & 0x100L)	// Link DOWN bit
+				{
 
-  	if( fcChip->ERQ->producerIndex != fcChip->ERQ->consumerIndex)
-	{
-//	  printk("#ERQ PI != CI#");
-          CpqTsFreezeTachlite( fcChip, 1); // freeze ERQ only	  
-	  fcChip->ERQ->producerIndex = fcChip->ERQ->consumerIndex = 0;
- 	  writel( fcChip->ERQ->base, 
-	    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
-          // re-writing base forces ERQ PI to equal CI
-  
-	}
-		
-	// link down transition occurred -- port_ids can change
-        // on next LinkUp, so we must invalidate current logins
-        // (and any I/O in progress) until PDISC or PLOGI/PRLI
-        // completes
-        {
-          pLoggedInPort = &fcChip->fcPorts; 
-          while( pLoggedInPort ) // for all ports which are expecting
-                                 // PDISC after the next LIP, set the
-                                 // logoutTimer
-          {
-
-	    if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec?
-            {
-              pLoggedInPort->LOGO_timer = 3;  // we want 2 seconds
-                                              // but Timer granularity
-                                              // is 1 second
-            }
-                                // suspend any I/O in progress until
-                                // PDISC received...
-            pLoggedInPort->prli = FALSE;   // block FCP-SCSI commands
-	    
-            pLoggedInPort = pLoggedInPort->pNextPort;
-          }  // ... all Previously known ports checked
-        }
-        
-	// since any hot plugging device may NOT support LILP frames
-	// (such as early Tachyon chips), clear this flag indicating
-	// we shouldn't use (our copy of) a LILP map.
-	// If we receive an LILP frame, we'll set it again.
-	fcChip->Options.LILPin = 0; // our LILPmap is invalid
-        cpqfcHBAdata->PortDiscDone = 0; // must re-validate FC ports!
-
-          // also, we want to invalidate (i.e. INITIATOR_ABORT) any
-          // open Login exchanges, in case the LinkDown happened in the
-          // middle of logins.  It's possible that some ports already
-          // ACCepted login commands which we have not processed before
-          // another LinkDown occurred.  Any accepted Login exhanges are
-          // invalidated by LinkDown, even before they are acknowledged.
-          // It's also possible for a port to have a Queued Reply or Request
-          // for login which was interrupted by LinkDown; it may come later,
-          // but it will be unacceptable to us.
-
-          // we must scan the entire exchange space, find every Login type
-          // originated by us, and abort it. This is NOT an abort due to
-          // timeout, so we don't actually send abort to the other port -
-          // we just complete it to free up the fcExchange slot.
-
-        for( i=TACH_SEST_LEN; i< TACH_MAX_XID; i++)
-        {                     // looking for Extended Link Serv.Exchanges
-          if( Exchanges->fcExchange[i].type == ELS_PDISC ||
-              Exchanges->fcExchange[i].type == ELS_PLOGI ||
-              Exchanges->fcExchange[i].type == ELS_PRLI ) 
-          {
-              // ABORT the exchange!
 #ifdef IMQ_DEBUG
-            printk("Originator ABORT x_id %Xh, type %Xh, port_id %Xh on LDn\n",
-              i, Exchanges->fcExchange[i].type,
-            Exchanges->fcExchange[i].fchs.d_id);
+					printk("LinkDn\n");
 #endif
+					printk(" #LDn# ");
 
-            Exchanges->fcExchange[i].status |= INITIATOR_ABORT;
-            cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, i); // abort on LDn
-          }
-        }
-
-      }
-
-             // ################   LINK UP   ##################
-      if( fcChip->Registers.FMstatus.value & 0x200L ) // Link Up bit
-      {                                 // AL_PA could have changed
-
-          // We need the following code, duplicated from LinkDn condition,
-          // because it's possible for the Tachyon to re-initialize (hard
-          // reset) without ever getting a LinkDn indication.
-        pLoggedInPort = &fcChip->fcPorts; 
-        while( pLoggedInPort )   // for all ports which are expecting
-                                 // PDISC after the next LIP, set the
-                                 // logoutTimer
-        {
-          if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec?
-          {
-            pLoggedInPort->LOGO_timer = 3;  // we want 2 seconds
-                                              // but Timer granularity
-                                              // is 1 second
-             
-                                  // suspend any I/O in progress until
-                                  // PDISC received...
-
-          }
-          pLoggedInPort = pLoggedInPort->pNextPort;
-        }  // ... all Previously known ports checked
- 
-          // CpqTs acquired AL_PA in register AL_PA (ACQ_ALPA)
-        fcChip->Registers.rcv_al_pa.value = 
-          readl(fcChip->Registers.rcv_al_pa.address);
- 
-	// Now, if our acquired address is DIFFERENT from our
-        // previous one, we are not allow to do PDISC - we
-        // must go back to PLOGI, which will terminate I/O in
-        // progress for ALL logged in FC devices...
-	// (This is highly unlikely).
+					fcChip->fcStats.linkDown++;
 
-	if( (fcChip->Registers.my_al_pa & 0xFF) != 
-	    ((fcChip->Registers.rcv_al_pa.value >> 16) &0xFF) )
-	{
+					SetTachTOV(cpqfcHBAdata);	// must set according to SANMark
 
-//	  printk(" #our HBA port_id changed!# "); // FC port_id changed!!	
+					// Check the ERQ - force it to be "empty" to prevent Tach
+					// from sending out frames before we do logins.
 
-	  pLoggedInPort = &fcChip->fcPorts; 
-          while( pLoggedInPort ) // for all ports which are expecting
-                                 // PDISC after the next LIP, set the
-                                 // logoutTimer
-          {
-	    pLoggedInPort->pdisc  = FALSE;
-            pLoggedInPort->prli = FALSE;
-            pLoggedInPort = pLoggedInPort->pNextPort;
-          }  // ... all Previously known ports checked
-
-	  // when the port_id changes, we must terminate
-	  // all open exchanges.
-          cpqfcTSTerminateExchange( cpqfcHBAdata, NULL, PORTID_CHANGED);
-
-	}
-	               
-	// Replace the entire 24-bit port_id.  We only know the
-	// lower 8 bits (alpa) from Tachyon; if a FLOGI is done,
-	// we'll get the upper 16-bits from the FLOGI ACC frame.
-	// If someone plugs into Fabric switch, we'll do FLOGI and
-	// get full 24-bit port_id; someone could then remove and
-	// hot-plug us into a dumb hub.  If we send a 24-bit PLOGI
-	// to a "private" loop device, it might blow up.
-	// Consequently, we force the upper 16-bits of port_id to
-	// be re-set on every LinkUp transition
-        fcChip->Registers.my_al_pa =
-          (fcChip->Registers.rcv_al_pa.value >> 16) & 0xFF;
-
-              
-              // copy frame manager status to unused ULONG slot
-        fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] =
-          fcChip->Registers.my_al_pa; // (for debugging)
-
-              // for TachLite, we need to write the acquired al_pa
-              // back into the FMconfig register, because after
-              // first initialization, the AQ (prev. acq.) bit gets
-              // set, causing TL FM to use the AL_PA field in FMconfig.
-              // (In Tachyon, FM writes the acquired AL_PA for us.)
-        ulBuff = readl( fcChip->Registers.FMconfig.address);
-        ulBuff &= 0x00ffffffL;  // mask out current al_pa
-        ulBuff |= ( fcChip->Registers.my_al_pa << 24 ); // or in acq. al_pa
-        fcChip->Registers.FMconfig.value = ulBuff; // copy it back
-        writel( fcChip->Registers.FMconfig.value,  // put in TachLite
-          fcChip->Registers.FMconfig.address);
-            
 
+					if (fcChip->ERQ->producerIndex != fcChip->ERQ->consumerIndex) {
+//        printk("#ERQ PI != CI#");
+						CpqTsFreezeTachlite(fcChip, 1);	// freeze ERQ only     
+						fcChip->ERQ->producerIndex = fcChip->ERQ->consumerIndex = 0;
+						writel(fcChip->ERQ->base, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
+						// re-writing base forces ERQ PI to equal CI
+
+					}
+					// link down transition occurred -- port_ids can change
+					// on next LinkUp, so we must invalidate current logins
+					// (and any I/O in progress) until PDISC or PLOGI/PRLI
+					// completes
+					{
+						pLoggedInPort = &fcChip->fcPorts;
+						while (pLoggedInPort)	// for all ports which are expecting
+							// PDISC after the next LIP, set the
+							// logoutTimer
+						{
+
+							if (pLoggedInPort->pdisc)	// expecting PDISC within 2 sec?
+							{
+								pLoggedInPort->LOGO_timer = 3;	// we want 2 seconds
+								// but Timer granularity
+								// is 1 second
+							}
+							// suspend any I/O in progress until
+							// PDISC received...
+							pLoggedInPort->prli = FALSE;	// block FCP-SCSI commands
+
+							pLoggedInPort = pLoggedInPort->pNextPort;
+						}	// ... all Previously known ports checked
+					}
+
+					// since any hot plugging device may NOT support LILP frames
+					// (such as early Tachyon chips), clear this flag indicating
+					// we shouldn't use (our copy of) a LILP map.
+					// If we receive an LILP frame, we'll set it again.
+					fcChip->Options.LILPin = 0;	// our LILPmap is invalid
+					cpqfcHBAdata->PortDiscDone = 0;	// must re-validate FC ports!
+
+					// also, we want to invalidate (i.e. INITIATOR_ABORT) any
+					// open Login exchanges, in case the LinkDown happened in the
+					// middle of logins.  It's possible that some ports already
+					// ACCepted login commands which we have not processed before
+					// another LinkDown occurred.  Any accepted Login exhanges are
+					// invalidated by LinkDown, even before they are acknowledged.
+					// It's also possible for a port to have a Queued Reply or Request
+					// for login which was interrupted by LinkDown; it may come later,
+					// but it will be unacceptable to us.
+
+					// we must scan the entire exchange space, find every Login type
+					// originated by us, and abort it. This is NOT an abort due to
+					// timeout, so we don't actually send abort to the other port -
+					// we just complete it to free up the fcExchange slot.
+
+					for (i = TACH_SEST_LEN; i < TACH_MAX_XID; i++) {	// looking for Extended Link Serv.Exchanges
+						if (Exchanges->fcExchange[i].type == ELS_PDISC || Exchanges->fcExchange[i].type == ELS_PLOGI || Exchanges->fcExchange[i].type == ELS_PRLI) {
+							// ABORT the exchange!
 #ifdef IMQ_DEBUG
-        printk("#LUp %Xh, FMstat 0x%08X#", 
-		fcChip->Registers.my_al_pa, fcChip->Registers.FMstatus.value);
+							printk("Originator ABORT x_id %Xh, type %Xh, port_id %Xh on LDn\n", i, Exchanges->fcExchange[i].type, Exchanges->fcExchange[i].fchs.d_id);
 #endif
 
-              // also set the WRITE-ONLY My_ID Register (for Fabric
-              // initialization)
-        writel( fcChip->Registers.my_al_pa,
-          fcChip->Registers.ReMapMemBase +TL_MEM_TACH_My_ID);
-          
-
-        fcChip->fcStats.linkUp++;
-
-                                     // reset TL statistics counters
-                                     // (we ignore these error counters
-                                     // while link is down)
-        ulBuff =                     // just reset TL's counter
-                 readl( fcChip->Registers.FMLinkStatus1.address);
-          
-        ulBuff =                     // just reset TL's counter
-                 readl( fcChip->Registers.FMLinkStatus2.address);
-
-          // for initiator, need to start verifying ports (e.g. PDISC)
+							Exchanges->fcExchange[i].status |= INITIATOR_ABORT;
+							cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, i);	// abort on LDn
+						}
+					}
+
+				}
+				// ################   LINK UP   ##################
+				if (fcChip->Registers.FMstatus.value & 0x200L)	// Link Up bit
+				{	// AL_PA could have changed
+
+					// We need the following code, duplicated from LinkDn condition,
+					// because it's possible for the Tachyon to re-initialize (hard
+					// reset) without ever getting a LinkDn indication.
+					pLoggedInPort = &fcChip->fcPorts;
+					while (pLoggedInPort)	// for all ports which are expecting
+						// PDISC after the next LIP, set the
+						// logoutTimer
+					{
+						if (pLoggedInPort->pdisc)	// expecting PDISC within 2 sec?
+						{
+							pLoggedInPort->LOGO_timer = 3;	// we want 2 seconds
+							// but Timer granularity
+							// is 1 second
+
+							// suspend any I/O in progress until
+							// PDISC received...
+
+						}
+						pLoggedInPort = pLoggedInPort->pNextPort;
+					}	// ... all Previously known ports checked
+
+					// CpqTs acquired AL_PA in register AL_PA (ACQ_ALPA)
+					fcChip->Registers.rcv_al_pa.value = readl(fcChip->Registers.rcv_al_pa.address);
+
+					// Now, if our acquired address is DIFFERENT from our
+					// previous one, we are not allow to do PDISC - we
+					// must go back to PLOGI, which will terminate I/O in
+					// progress for ALL logged in FC devices...
+					// (This is highly unlikely).
+
+					if ((fcChip->Registers.my_al_pa & 0xFF) != ((fcChip->Registers.rcv_al_pa.value >> 16) & 0xFF)) {
+
+//        printk(" #our HBA port_id changed!# "); // FC port_id changed!!       
+
+						pLoggedInPort = &fcChip->fcPorts;
+						while (pLoggedInPort)	// for all ports which are expecting
+							// PDISC after the next LIP, set the
+							// logoutTimer
+						{
+							pLoggedInPort->pdisc = FALSE;
+							pLoggedInPort->prli = FALSE;
+							pLoggedInPort = pLoggedInPort->pNextPort;
+						}	// ... all Previously known ports checked
+
+						// when the port_id changes, we must terminate
+						// all open exchanges.
+						cpqfcTSTerminateExchange(cpqfcHBAdata, NULL, PORTID_CHANGED);
+
+					}
+					// Replace the entire 24-bit port_id.  We only know the
+					// lower 8 bits (alpa) from Tachyon; if a FLOGI is done,
+					// we'll get the upper 16-bits from the FLOGI ACC frame.
+					// If someone plugs into Fabric switch, we'll do FLOGI and
+					// get full 24-bit port_id; someone could then remove and
+					// hot-plug us into a dumb hub.  If we send a 24-bit PLOGI
+					// to a "private" loop device, it might blow up.
+					// Consequently, we force the upper 16-bits of port_id to
+					// be re-set on every LinkUp transition
+					fcChip->Registers.my_al_pa = (fcChip->Registers.rcv_al_pa.value >> 16) & 0xFF;
+
+
+					// copy frame manager status to unused u32 slot
+					fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] = fcChip->Registers.my_al_pa;	// (for debugging)
+
+					// for TachLite, we need to write the acquired al_pa
+					// back into the FMconfig register, because after
+					// first initialization, the AQ (prev. acq.) bit gets
+					// set, causing TL FM to use the AL_PA field in FMconfig.
+					// (In Tachyon, FM writes the acquired AL_PA for us.)
+					ulBuff = readl(fcChip->Registers.FMconfig.address);
+					ulBuff &= 0x00ffffffL;	// mask out current al_pa
+					ulBuff |= (fcChip->Registers.my_al_pa << 24);	// or in acq. al_pa
+					fcChip->Registers.FMconfig.value = ulBuff;	// copy it back
+					writel(fcChip->Registers.FMconfig.value,	// put in TachLite
+					       fcChip->Registers.FMconfig.address);
 
 
+#ifdef IMQ_DEBUG
+					printk("#LUp %Xh, FMstat 0x%08X#", fcChip->Registers.my_al_pa, fcChip->Registers.FMstatus.value);
+#endif
 
-         
-      
-      
-	CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachlite, if Link OK
-	
-	// Tachyon creates an interesting problem for us on LILP frames.
-	// Instead of writing the incoming LILP frame into the SFQ before
-	// indicating LINK UP (the actual order of events), Tachyon tells
-	// us LINK UP, and later us the LILP.  So we delay, then examine the
-	// IMQ for an Inbound CM (x04); if found, we can set
-	// LINKACTIVE after processing the LILP.  Otherwise, just proceed.
-	// Since Tachyon imposes this time delay (and doesn't tell us
-	// what it is), we have to impose a delay before "Peeking" the IMQ
-	// for Tach hardware (DMA) delivery.
-	// Processing LILP is required by SANMark
-	udelay( 1000);  // microsec delay waiting for LILP (if it comes)
-        if( PeekIMQEntry( fcChip, ELS_LILP_FRAME) )
-	{  // found SFQ LILP, which will post LINKACTIVE	  
-//	  printk("skipping LINKACTIVE post\n");
+					// also set the WRITE-ONLY My_ID Register (for Fabric
+					// initialization)
+					writel(fcChip->Registers.my_al_pa, fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
+
+
+					fcChip->fcStats.linkUp++;
+
+					// reset TL statistics counters
+					// (we ignore these error counters
+					// while link is down)
+					ulBuff =	// just reset TL's counter
+					    readl(fcChip->Registers.FMLinkStatus1.address);
+
+					ulBuff =	// just reset TL's counter
+					    readl(fcChip->Registers.FMLinkStatus2.address);
+
+					// for initiator, need to start verifying ports (e.g. PDISC)
 
-	}
-	else
-          cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, ulFibreFrame);  
-      }
 
 
 
-      // ******* Set Fabric Login indication ********
-      if( fcChip->Registers.FMstatus.value & 0x2000 )
-      {
-	printk(" #Fabric# ");
-        fcChip->Options.fabric = 1;
-      }
-      else
-        fcChip->Options.fabric = 0;
-
-      
-      
-                             // ******* LIP(F8,x) or BAD AL_PA? ********
-      if( fcChip->Registers.FMstatus.value & 0x30000L )
-      {
-                        // copy the error AL_PAs
-        fcChip->Registers.rcv_al_pa.value = 
-          readl(fcChip->Registers.rcv_al_pa.address);
-            
-                        // Bad AL_PA?
-        if( fcChip->Registers.FMstatus.value & 0x10000L )
-        {
-          PFC_LOGGEDIN_PORT pLoggedInPort;
-        
-                       // copy "BAD" al_pa field
-          fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] =
-              (fcChip->Registers.rcv_al_pa.value & 0xff00L) >> 8;
-
-	  pLoggedInPort = fcFindLoggedInPort( fcChip,
-            NULL,     // DON'T search Scsi Nexus
-            fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1], // port id
-            NULL,     // DON'T search linked list for FC WWN
-            NULL);    // DON'T care about end of list
- 
-	  if( pLoggedInPort )
-	  {
-            // Just in case we got this BAD_ALPA because a device
-	    // quietly disappeared (can happen on non-managed hubs such 
-	    // as the Vixel Rapport 1000),
-	    // do an Implicit Logout.  We never expect this on a Logged
-	    // in port (but do expect it on port discovery).
-	    // (As a reasonable alternative, this could be changed to 
-	    // simply start the implicit logout timer, giving the device
-	    // several seconds to "come back".)
-	    // 
-	    printk(" #BAD alpa %Xh# ",
-		   fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1]);
-            cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);
-	  }
-        }
-                        // LIP(f8,x)?
-        if( fcChip->Registers.FMstatus.value & 0x20000L )
-        {
-                        // for debugging, copy al_pa field
-          fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] =
-              (fcChip->Registers.rcv_al_pa.value & 0xffL);
-                        // get the other port's al_pa
-                        // (one that sent LIP(F8,?) )
-        }
-      }
-
-                             // Elastic store err
-      if( fcChip->Registers.FMstatus.value & 0x400L )
-      {
-            // don't count e-s if loop is down!
-        if( !(USHORT)(fcChip->Registers.FMstatus.value & 0x80) )
-          fcChip->fcStats.e_stores++;
-          
-      }
-    }
-    break;
-
 
-    case INBOUND_FCP_XCHG_COMPLETION:  // 0x0C
 
-    // Remarks:
-    // On Tachlite TL/TS, we get this message when the data phase
-    // of a SEST inbound transfer is complete.  For example, if a WRITE command
-    // was received with OX_ID 0, we might respond with XFER_RDY with
-    // RX_ID 8001.  This would start the SEST controlled data phases.  When
-    // all data frames are received, we get this inbound completion. This means
-    // we should send a status frame to complete the status phase of the 
-    // FCP-SCSI exchange, using the same OX_ID,RX_ID that we used for data
-    // frames.
-    // See Outbound CM discussion of x_IDs
-    // Psuedo Code
-    //   Get SEST index (x_ID)
-    //     x_ID out of range, return (err condition)
-    //   set status bits from 2nd dword
-    //   free transactionID & SEST entry
-    //   call fcComplete with transactionID & status
-
-      ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0];
-      x_ID = ulBuff & 0x7fffL;  // lower 14 bits SEST_Index/Trans_ID
-                                // (mask out MSB "direction" bit)
-                                // Range check CM OX/RX_ID value...
-      if( x_ID < TACH_SEST_LEN )  // don't go beyond SEST array space
-      {
+					CpqTsUnFreezeTachlite(fcChip, 2);	// unfreeze Tachlite, if Link OK
+
+					// Tachyon creates an interesting problem for us on LILP frames.
+					// Instead of writing the incoming LILP frame into the SFQ before
+					// indicating LINK UP (the actual order of events), Tachyon tells
+					// us LINK UP, and later us the LILP.  So we delay, then examine the
+					// IMQ for an Inbound CM (x04); if found, we can set
+					// LINKACTIVE after processing the LILP.  Otherwise, just proceed.
+					// Since Tachyon imposes this time delay (and doesn't tell us
+					// what it is), we have to impose a delay before "Peeking" the IMQ
+					// for Tach hardware (DMA) delivery.
+					// Processing LILP is required by SANMark
+					udelay(1000);	// microsec delay waiting for LILP (if it comes)
+					if (PeekIMQEntry(fcChip, ELS_LILP_FRAME)) {	// found SFQ LILP, which will post LINKACTIVE          
+//        printk("skipping LINKACTIVE post\n");
+
+					} else
+						cpqfcTSPutLinkQue(cpqfcHBAdata, LINKACTIVE, ulFibreFrame);
+				}
+
+
+				// ******* Set Fabric Login indication ********
+				if (fcChip->Registers.FMstatus.value & 0x2000) {
+					printk(" #Fabric# ");
+					fcChip->Options.fabric = 1;
+				} else
+					fcChip->Options.fabric = 0;
+
+
+
+				// ******* LIP(F8,x) or BAD AL_PA? ********
+				if (fcChip->Registers.FMstatus.value & 0x30000L) {
+					// copy the error AL_PAs
+					fcChip->Registers.rcv_al_pa.value = readl(fcChip->Registers.rcv_al_pa.address);
+
+					// Bad AL_PA?
+					if (fcChip->Registers.FMstatus.value & 0x10000L) {
+						PFC_LOGGEDIN_PORT pLoggedInPort;
+
+						// copy "BAD" al_pa field
+						fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] = (fcChip->Registers.rcv_al_pa.value & 0xff00L) >> 8;
+
+						pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// DON'T search Scsi Nexus
+										   fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1],	// port id
+										   NULL,	// DON'T search linked list for FC WWN
+										   NULL);	// DON'T care about end of list
+
+						if (pLoggedInPort) {
+							// Just in case we got this BAD_ALPA because a device
+							// quietly disappeared (can happen on non-managed hubs such 
+							// as the Vixel Rapport 1000),
+							// do an Implicit Logout.  We never expect this on a Logged
+							// in port (but do expect it on port discovery).
+							// (As a reasonable alternative, this could be changed to 
+							// simply start the implicit logout timer, giving the device
+							// several seconds to "come back".)
+							// 
+							printk(" #BAD alpa %Xh# ", fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1]);
+							cpqfcTSImplicitLogout(cpqfcHBAdata, pLoggedInPort);
+						}
+					}
+					// LIP(f8,x)?
+					if (fcChip->Registers.FMstatus.value & 0x20000L) {
+						// for debugging, copy al_pa field
+						fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] = (fcChip->Registers.rcv_al_pa.value & 0xffL);
+						// get the other port's al_pa
+						// (one that sent LIP(F8,?) )
+					}
+				}
+				// Elastic store err
+				if (fcChip->Registers.FMstatus.value & 0x400L) {
+					// don't count e-s if loop is down!
+					if (!(u16) (fcChip->Registers.FMstatus.value & 0x80))
+						fcChip->fcStats.e_stores++;
+
+				}
+			}
+			break;
+
+
+		case INBOUND_FCP_XCHG_COMPLETION:	// 0x0C
+
+			// Remarks:
+			// On Tachlite TL/TS, we get this message when the data phase
+			// of a SEST inbound transfer is complete.  For example, if a WRITE command
+			// was received with OX_ID 0, we might respond with XFER_RDY with
+			// RX_ID 8001.  This would start the SEST controlled data phases.  When
+			// all data frames are received, we get this inbound completion. This means
+			// we should send a status frame to complete the status phase of the 
+			// FCP-SCSI exchange, using the same OX_ID,RX_ID that we used for data
+			// frames.
+			// See Outbound CM discussion of x_IDs
+			// Psuedo Code
+			//   Get SEST index (x_ID)
+			//     x_ID out of range, return (err condition)
+			//   set status bits from 2nd dword
+			//   free transactionID & SEST entry
+			//   call fcComplete with transactionID & status
+
+			ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0];
+			x_ID = ulBuff & 0x7fffL;	// lower 14 bits SEST_Index/Trans_ID
+			// (mask out MSB "direction" bit)
+			// Range check CM OX/RX_ID value...
+			if (x_ID < TACH_SEST_LEN)	// don't go beyond SEST array space
+			{
 
 //#define FCP_COMPLETION_DBG 1
 #ifdef FCP_COMPLETION_DBG
-        printk(" FCP_CM x_ID %Xh, status %Xh, Cmnd %p\n", 
-          x_ID, ulBuff, Exchanges->fcExchange[x_ID].Cmnd);
+				printk(" FCP_CM x_ID %Xh, status %Xh, Cmnd %p\n", x_ID, ulBuff, Exchanges->fcExchange[x_ID].Cmnd);
 #endif
-        if( ulBuff & 0x08000000L ) // RPC -Response Phase Complete - or -
-                                   // time to send response frame?
-          RPCset = 1;             // (SEST transaction)
-        else
-          RPCset = 0;
-                // set the status for this Inbound SCSI transaction's ID
-        dwStatus = 0L;
-        if( ulBuff & 0x70000000L ) // any errs?
-        {
-          
-          if( ulBuff & 0x40000000L )
-            dwStatus |= LINKFAIL_RX;
-          
-	  if( ulBuff & 0x20000000L )
-            dwStatus |= COUNT_ERROR;
-          
-          if( ulBuff & 0x10000000L )
-            dwStatus |= OVERFLOW;
-        }
-      
-	
-	  // FCP transaction done - copy status
-        Exchanges->fcExchange[ x_ID ].status = dwStatus;
-
-
-        // Did the exchange get an FCP-RSP response frame?
-        // (Note the little endian/big endian FC payload difference)
-
-        if( RPCset )             // SEST transaction Response frame rec'd
-        {
-    	  // complete the command in our driver...
-          cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev,fcChip, x_ID);
-
-        }  // end "RPCset"
-	
-        else  // ("target" logic)
-        {
-            // Tachlite says all data frames have been received - now it's time
-            // to analyze data transfer (successful?), then send a response 
-            // frame for this exchange
-
-          ulFibreFrame[0] = x_ID; // copy for later reference
-
-          // if this was a TWE, we have to send satus response
-          if( Exchanges->fcExchange[ x_ID].type == SCSI_TWE )
-	  {
+				if (ulBuff & 0x08000000L)	// RPC -Response Phase Complete - or -
+					// time to send response frame?
+					RPCset = 1;	// (SEST transaction)
+				else
+					RPCset = 0;
+				// set the status for this Inbound SCSI transaction's ID
+				dwStatus = 0L;
+				if (ulBuff & 0x70000000L)	// any errs?
+				{
+
+					if (ulBuff & 0x40000000L)
+						dwStatus |= LINKFAIL_RX;
+
+					if (ulBuff & 0x20000000L)
+						dwStatus |= COUNT_ERROR;
+
+					if (ulBuff & 0x10000000L)
+						dwStatus |= OVERFLOW;
+				}
+
+				// FCP transaction done - copy status
+				Exchanges->fcExchange[x_ID].status = dwStatus;
+
+
+				// Did the exchange get an FCP-RSP response frame?
+				// (Note the little endian/big endian FC payload difference)
+
+				if (RPCset)	// SEST transaction Response frame rec'd
+				{
+					// complete the command in our driver...
+					cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, x_ID);
+
+				}	// end "RPCset"
+
+				else	// ("target" logic)
+				{
+					// Tachlite says all data frames have been received - now it's time
+					// to analyze data transfer (successful?), then send a response 
+					// frame for this exchange
+
+					ulFibreFrame[0] = x_ID;	// copy for later reference
+
+					// if this was a TWE, we have to send satus response
+					if (Exchanges->fcExchange[x_ID].type == SCSI_TWE) {
 //            fcPutScsiQue( cpqfcHBAdata, 
 //                NEED_FCP_RSP, ulFibreFrame);  // (ulFibreFrame not used here)
-	  }
-        }
-      }
-      else  // ERROR CONDITION!  bogus x_ID in completion message
-      {
-        printk("IN FCP_XCHG: bad x_ID: %Xh\n", x_ID);
-      }
+					}
+				}
+			} else	// ERROR CONDITION!  bogus x_ID in completion message
+			{
+				printk("IN FCP_XCHG: bad x_ID: %Xh\n", x_ID);
+			}
 
-    break;
+			break;
 
 
 
 
-    case INBOUND_SCSI_DATA_COMMAND:
-    case BAD_SCSI_FRAME:
-    case INB_SCSI_STATUS_COMPLETION:
-    case BUFFER_PROCESSED_COMPLETION:
-    break;
-    }
+		case INBOUND_SCSI_DATA_COMMAND:
+		case BAD_SCSI_FRAME:
+		case INB_SCSI_STATUS_COMPLETION:
+		case BUFFER_PROCESSED_COMPLETION:
+			break;
+		}
+
+		// Tachyon is producing;
+		// we are consuming
+		fcChip->IMQ->consumerIndex++;	// increment OUR consumerIndex
+		if (fcChip->IMQ->consumerIndex >= IMQ_LEN)	// check for rollover
+			fcChip->IMQ->consumerIndex = 0L;	// reset it
+
+
+		if (fcChip->IMQ->producerIndex == fcChip->IMQ->consumerIndex) {	// all Messages are processed -
+			iStatus = 0;	// no more messages to process
+
+		} else
+			iStatus = 1;	// more messages to process
+
+		// update TachLite's ConsumerIndex... (clears INTA_L)
+		// NOTE: according to TL/TS UG, the 
+		// "host must return completion messages in sequential order".
+		// Does this mean one at a time, in the order received?  We
+		// presume so.
+
+		writel(fcChip->IMQ->consumerIndex, (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
 
-					   // Tachyon is producing;
-					   // we are consuming
-    fcChip->IMQ->consumerIndex++;             // increment OUR consumerIndex
-    if( fcChip->IMQ->consumerIndex >= IMQ_LEN)// check for rollover
-      fcChip->IMQ->consumerIndex = 0L;        // reset it
-
-
-    if( fcChip->IMQ->producerIndex == fcChip->IMQ->consumerIndex )
-    {                           // all Messages are processed -
-      iStatus = 0;              // no more messages to process
-
-    }
-    else
-      iStatus = 1;              // more messages to process
-
-    // update TachLite's ConsumerIndex... (clears INTA_L)
-    // NOTE: according to TL/TS UG, the 
-    // "host must return completion messages in sequential order".
-    // Does this mean one at a time, in the order received?  We
-    // presume so.
-
-    writel( fcChip->IMQ->consumerIndex,
-      (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
-		    
 #if IMQ_DEBUG
-    printk("Process IMQ: writing consumer ndx %d\n ", 
-      fcChip->IMQ->consumerIndex);
-    printk("PI %X, CI %X\n", 
-    fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex );
+		printk("Process IMQ: writing consumer ndx %d\n ", fcChip->IMQ->consumerIndex);
+		printk("PI %X, CI %X\n", fcChip->IMQ->producerIndex, fcChip->IMQ->consumerIndex);
 #endif
-  
 
 
-  }
-  else
-  {
-   // hmmm... why did we get interrupted/called with no message?
-    iStatus = -1;               // nothing to process
+
+	} else {
+		// hmmm... why did we get interrupted/called with no message?
+		iStatus = -1;	// nothing to process
 #if IMQ_DEBUG
-    printk("Process IMQ: no message PI %Xh  CI %Xh", 
-      fcChip->IMQ->producerIndex,
-      fcChip->IMQ->consumerIndex);
+		printk("Process IMQ: no message PI %Xh  CI %Xh", fcChip->IMQ->producerIndex, fcChip->IMQ->consumerIndex);
 #endif
-  }
+	}
 
-  LEAVE("ProcessIMQEntry");
-  
-  return iStatus;
+	LEAVE("ProcessIMQEntry");
+
+	return iStatus;
 }
 
 
@@ -1648,31 +1496,29 @@
 //  -1 on fatal error
 //   0 on success
 
-int CpqTsInitializeTachLite( void *pHBA, int opcode1, int opcode2)
+int CpqTsInitializeTachLite(void *pHBA, int opcode1, int opcode2)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  ULONG ulBuff;
-  UCHAR bBuff;
-  int iStatus=-1;  // assume failure
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) pHBA;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	u32 ulBuff;
+	u8 bBuff;
+	int iStatus = -1;	// assume failure
 
-  ENTER("InitializeTachLite");
+	ENTER("InitializeTachLite");
 
-  // verify board's base address (sanity check)
+	// verify board's base address (sanity check)
 
-  if( !fcChip->Registers.ReMapMemBase)                // NULL address for card?
-    return -1;                         // FATAL error!
+	if (!fcChip->Registers.ReMapMemBase)	// NULL address for card?
+		return -1;	// FATAL error!
 
 
 
-  switch( opcode1 )
-  {
-    case 1:       // restore hardware to power-on (hard) restart
+	switch (opcode1) {
+	case 1:		// restore hardware to power-on (hard) restart
 
 
-      iStatus = fcChip->ResetTachyon( 
-		  cpqfcHBAdata, opcode2); // laser off, reset hardware
-				      // de-allocate aligned buffers
+		iStatus = fcChip->ResetTachyon(cpqfcHBAdata, opcode2);	// laser off, reset hardware
+		// de-allocate aligned buffers
 
 
 /* TBD      // reset FC link Q (producer and consumer = 0)
@@ -1680,17 +1526,17 @@
 
 */
 
-      if( iStatus )
-        break;
+		if (iStatus)
+			break;
 
-    case 2:       // Config PCI/Tachyon registers
-      // NOTE: For Tach TL/TS, bit 31 must be set to 1.  For TS chips, a read
-      // of bit 31 indicates state of M66EN signal; if 1, chip may run at 
-      // 33-66MHz  (see TL/TS UG, pg 159)
+	case 2:		// Config PCI/Tachyon registers
+		// NOTE: For Tach TL/TS, bit 31 must be set to 1.  For TS chips, a read
+		// of bit 31 indicates state of M66EN signal; if 1, chip may run at 
+		// 33-66MHz  (see TL/TS UG, pg 159)
 
-      ulBuff = 0x80000000;  // TachLite Configuration Register
+		ulBuff = 0x80000000;	// TachLite Configuration Register
 
-      writel( ulBuff, fcChip->Registers.TYconfig.address);
+		writel(ulBuff, fcChip->Registers.TYconfig.address);
 //      ulBuff = 0x0147L;  // CpqTs PCI CFGCMD register
 //      WritePCIConfiguration( fcChip->Backplane.bus,
 //                           fcChip->Backplane.slot, TLCFGCMD, ulBuff, 4);
@@ -1698,80 +1544,70 @@
 //      ReadPCIConfiguration( fcChip->Backplane.bus,
 //                           fcChip->Backplane.slot, TLCFGCMD, &ulBuff, 4);
 
-      // read back for reference...
-      fcChip->Registers.TYconfig.value = 
-         readl( fcChip->Registers.TYconfig.address );
-
-      // what is the PCI bus width?
-      pci_read_config_byte( cpqfcHBAdata->PciDev,
-                                0x43, // PCIMCTR offset
-                                &bBuff);
-      
-      fcChip->Registers.PCIMCTR = bBuff;
-
-      // set string identifying the chip on the circuit board
-
-      fcChip->Registers.TYstatus.value =
-        readl( fcChip->Registers.TYstatus.address);
-      
-      {
+		// read back for reference...
+		fcChip->Registers.TYconfig.value = readl(fcChip->Registers.TYconfig.address);
+
+		// what is the PCI bus width?
+		pci_read_config_byte(cpqfcHBAdata->PciDev, 0x43,	// PCIMCTR offset
+				     &bBuff);
+
+		fcChip->Registers.PCIMCTR = bBuff;
+
+		// set string identifying the chip on the circuit board
+
+		fcChip->Registers.TYstatus.value = readl(fcChip->Registers.TYstatus.address);
+
+		{
 // Now that we are supporting multiple boards, we need to change
 // this logic to check for PCI vendor/device IDs...
 // for now, quick & dirty is simply checking Chip rev
-	
-	ULONG RevId = (fcChip->Registers.TYstatus.value &0x3E0)>>5;
-	UCHAR Minor = (UCHAR)(RevId & 0x3);
-	UCHAR Major = (UCHAR)((RevId & 0x1C) >>2);
-  
-        printk("  HBA Tachyon RevId %d.%d\n", Major, Minor);
-  	if( (Major == 1) && (Minor == 2) )
-        {
-	  sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS12);
-
-	}
-	else if( (Major == 1) && (Minor == 3) )
-        {
-	  sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS13);
-	}
-	else if( (Major == 2) && (Minor == 1) )
-        {
-	  sprintf( cpqfcHBAdata->fcChip.Name, SAGILENT_XL2_21);
-	}
-	else
-	  sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE_UNKNOWN);
-      }
+
+			u32 RevId = (fcChip->Registers.TYstatus.value & 0x3E0) >> 5;
+			u8 Minor = (u8) (RevId & 0x3);
+			u8 Major = (u8) ((RevId & 0x1C) >> 2);
+
+			printk("  HBA Tachyon RevId %d.%d\n", Major, Minor);
+			if ((Major == 1) && (Minor == 2)) {
+				sprintf(cpqfcHBAdata->fcChip.Name, STACHLITE66_TS12);
+
+			} else if ((Major == 1) && (Minor == 3)) {
+				sprintf(cpqfcHBAdata->fcChip.Name, STACHLITE66_TS13);
+			} else if ((Major == 2) && (Minor == 1)) {
+				sprintf(cpqfcHBAdata->fcChip.Name, SAGILENT_XL2_21);
+			} else
+				sprintf(cpqfcHBAdata->fcChip.Name, STACHLITE_UNKNOWN);
+		}
 
 
 
-    case 3:       // allocate mem, set Tachyon Que registers
-      iStatus = CpqTsCreateTachLiteQues( cpqfcHBAdata, opcode2);
+	case 3:		// allocate mem, set Tachyon Que registers
+		iStatus = CpqTsCreateTachLiteQues(cpqfcHBAdata, opcode2);
+
+		if (iStatus)
+			break;
+
+		// now that the Queues exist, Tach can DMA to them, so
+		// we can begin processing INTs
+		// INTEN register - enable INT (TachLite interrupt)
+		writeb(0x1F, fcChip->Registers.ReMapMemBase + IINTEN);
+
+		// Fall through
+	case 4:		// Config Fame Manager, Init Loop Command, laser on
+
+		// L_PORT or loopback
+		// depending on Options
+		iStatus = CpqTsInitializeFrameManager(fcChip, 0);
+		if (iStatus) {
+			// failed to initialize Frame Manager
+			break;
+		}
 
-      if( iStatus )
-        break;
-
-      // now that the Queues exist, Tach can DMA to them, so
-      // we can begin processing INTs
-      // INTEN register - enable INT (TachLite interrupt)
-      writeb( 0x1F, fcChip->Registers.ReMapMemBase + IINTEN);
-
-	// Fall through
-    case 4:       // Config Fame Manager, Init Loop Command, laser on
-
-                 // L_PORT or loopback
-                 // depending on Options
-      iStatus = CpqTsInitializeFrameManager( fcChip,0 );
-      if( iStatus )
-      {
-           // failed to initialize Frame Manager
-	      break;
-      }
-
-    default:
-      break;
-  }
-  LEAVE("InitializeTachLite");
-  
-  return iStatus;
+	default:
+		break;
+	}
+	LEAVE("InitializeTachLite");
+
+	return iStatus;
 }
 
 
@@ -1782,101 +1618,86 @@
 // Order of allocation: see other function
 
 
-int CpqTsDestroyTachLiteQues( void *pHBA, int opcode)
+int CpqTsDestroyTachLiteQues(void *pHBA, int opcode)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  USHORT i, iStatus=0;
-  void* vPtr;  // mem Align manager sets this to the freed address on success
-  unsigned long ulPtr;  // for 64-bit pointer cast (e.g. Alpa machine)
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  PSGPAGES j, next;
-
-  ENTER("DestroyTachLiteQues");
-
-  if( fcChip->SEST )
-  {
-                // search out and free Pool for Extended S/G list pages
-
-    for( i=0; i < TACH_SEST_LEN; i++)  // for each exchange
-    {
-      // It's possible that extended S/G pages were allocated, mapped, and
-      // not cleared due to error conditions or O/S driver termination.
-      // Make sure they're all gone.
-      if (Exchanges->fcExchange[i].Cmnd != NULL) 
-      	cpqfc_pci_unmap(cpqfcHBAdata->PciDev, Exchanges->fcExchange[i].Cmnd, 
-			fcChip, i); // undo DMA mappings.
-
-      for (j=fcChip->SEST->sgPages[i] ; j != NULL ; j = next) {
-		next = j->next;
-		kfree(j);
-      }
-      fcChip->SEST->sgPages[i] = NULL;
-    }
-    ulPtr = (unsigned long)fcChip->SEST;
-    vPtr = fcMemManager( cpqfcHBAdata->PciDev, 
-		    &cpqfcHBAdata->dynamic_mem[0],
-		    0,0, (ULONG)ulPtr, NULL ); // 'free' mem
-    fcChip->SEST = 0L;  // null invalid ptr
-    if( !vPtr )
-    {
-      printk("SEST mem not freed\n");
-      iStatus = -1;
-    }
-  }
-
-  if( fcChip->SFQ )
-  {
-
-    ulPtr = (unsigned long)fcChip->SFQ;
-    vPtr = fcMemManager( cpqfcHBAdata->PciDev, 
-		    &cpqfcHBAdata->dynamic_mem[0],
-		    0,0, (ULONG)ulPtr, NULL ); // 'free' mem
-    fcChip->SFQ = 0L;  // null invalid ptr
-    if( !vPtr )
-    {
-      printk("SFQ mem not freed\n");
-      iStatus = -2;
-    }
-  }
-
-
-  if( fcChip->IMQ )
-  {
-      // clear Indexes to show empty Queue
-    fcChip->IMQ->producerIndex = 0;
-    fcChip->IMQ->consumerIndex = 0;
-
-    ulPtr = (unsigned long)fcChip->IMQ;
-    vPtr = fcMemManager( cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0],
-		    0,0, (ULONG)ulPtr, NULL ); // 'free' mem
-    fcChip->IMQ = 0L;  // null invalid ptr
-    if( !vPtr )
-    {
-      printk("IMQ mem not freed\n");
-      iStatus = -3;
-    }
-  }
-
-  if( fcChip->ERQ )         // release memory blocks used by the queues
-  {
-    ulPtr = (unsigned long)fcChip->ERQ;
-    vPtr = fcMemManager( cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0],
-		    0,0, (ULONG)ulPtr, NULL ); // 'free' mem
-    fcChip->ERQ = 0L;  // null invalid ptr
-    if( !vPtr )
-    {
-      printk("ERQ mem not freed\n");
-      iStatus = -4;
-    }
-  }
-    
-  // free up the primary EXCHANGES struct and Link Q
-  cpqfc_free_dma_consistent(cpqfcHBAdata);
-  
-  LEAVE("DestroyTachLiteQues");
-  
-  return iStatus;     // non-zero (failed) if any memory not freed
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) pHBA;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	u16 i, iStatus = 0;
+	void *vPtr;		// mem Align manager sets this to the freed address on success
+	unsigned long ulPtr;	// for 64-bit pointer cast (e.g. Alpa machine)
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	PSGPAGES j, next;
+
+	ENTER("DestroyTachLiteQues");
+
+	if (fcChip->SEST) {
+		// search out and free Pool for Extended S/G list pages
+
+		for (i = 0; i < TACH_SEST_LEN; i++)	// for each exchange
+		{
+			// It's possible that extended S/G pages were allocated, mapped, and
+			// not cleared due to error conditions or O/S driver termination.
+			// Make sure they're all gone.
+			if (Exchanges->fcExchange[i].Cmnd != NULL)
+				cpqfc_pci_unmap(cpqfcHBAdata->PciDev, Exchanges->fcExchange[i].Cmnd, fcChip, i);	// undo DMA mappings.
+
+			for (j = fcChip->SEST->sgPages[i]; j != NULL; j = next) {
+				next = j->next;
+				kfree(j);
+			}
+			fcChip->SEST->sgPages[i] = NULL;
+		}
+		ulPtr = (unsigned long) fcChip->SEST;
+		vPtr = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], 0, 0, (u32) ulPtr, NULL);	// 'free' mem
+		fcChip->SEST = 0L;	// null invalid ptr
+		if (!vPtr) {
+			printk("SEST mem not freed\n");
+			iStatus = -1;
+		}
+	}
+
+	if (fcChip->SFQ) {
+
+		ulPtr = (unsigned long) fcChip->SFQ;
+		vPtr = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], 0, 0, (u32) ulPtr, NULL);	// 'free' mem
+		fcChip->SFQ = 0L;	// null invalid ptr
+		if (!vPtr) {
+			printk("SFQ mem not freed\n");
+			iStatus = -2;
+		}
+	}
+
+
+	if (fcChip->IMQ) {
+		// clear Indexes to show empty Queue
+		fcChip->IMQ->producerIndex = 0;
+		fcChip->IMQ->consumerIndex = 0;
+
+		ulPtr = (unsigned long) fcChip->IMQ;
+		vPtr = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], 0, 0, (u32) ulPtr, NULL);	// 'free' mem
+		fcChip->IMQ = 0L;	// null invalid ptr
+		if (!vPtr) {
+			printk("IMQ mem not freed\n");
+			iStatus = -3;
+		}
+	}
+
+	if (fcChip->ERQ)	// release memory blocks used by the queues
+	{
+		ulPtr = (unsigned long) fcChip->ERQ;
+		vPtr = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], 0, 0, (u32) ulPtr, NULL);	// 'free' mem
+		fcChip->ERQ = 0L;	// null invalid ptr
+		if (!vPtr) {
+			printk("ERQ mem not freed\n");
+			iStatus = -4;
+		}
+	}
+	// free up the primary EXCHANGES struct and Link Q
+	cpqfc_free_dma_consistent(cpqfcHBAdata);
+
+	LEAVE("DestroyTachLiteQues");
+
+	return iStatus;		// non-zero (failed) if any memory not freed
 }
 
 
@@ -1896,44 +1717,35 @@
 //   length from the completion message.  The caller passes a buffer large
 //   enough for the complete message (max 2k).
 
-static void CpqTsGetSFQEntry(
-         PTACHYON fcChip,
-         USHORT producerNdx,
-         ULONG *ulDestPtr,            // contiguous destination buffer
-	 BOOLEAN UpdateChip)
+static void CpqTsGetSFQEntry(PTACHYON fcChip, u16 producerNdx, u32 * ulDestPtr,	// contiguous destination buffer
+			     u8 UpdateChip)
 {
-  ULONG total_bytes=0;
-  ULONG consumerIndex = fcChip->SFQ->consumerIndex;
-  
-				// check passed copy of SFQ producer index -
-				// is a new message waiting for us?
-				// equal indexes means SFS is copied
-
-  while( producerNdx != consumerIndex )
-  {                             // need to process message
-    total_bytes += 64;   // maintain count to prevent writing past buffer
-                   // don't allow copies over Fibre Channel defined length!
-    if( total_bytes <= 2048 )
-    {
-      memcpy( ulDestPtr, 
-              &fcChip->SFQ->QEntry[consumerIndex],
-              64 );  // each SFQ entry is 64 bytes
-      ulDestPtr += 16;   // advance pointer to next 64 byte block
-    }
-		         // Tachyon is producing,
-                         // and we are consuming
-
-    if( ++consumerIndex >= SFQ_LEN)// check for rollover
-      consumerIndex = 0L;        // reset it
-  }
-
-  // if specified, update the Tachlite chip ConsumerIndex...
-  if( UpdateChip )
-  {
-    fcChip->SFQ->consumerIndex = consumerIndex;
-    writel( fcChip->SFQ->consumerIndex,
-      fcChip->Registers.SFQconsumerIndex.address);
-  }
+	u32 total_bytes = 0;
+	u32 consumerIndex = fcChip->SFQ->consumerIndex;
+
+	// check passed copy of SFQ producer index -
+	// is a new message waiting for us?
+	// equal indexes means SFS is copied
+
+	while (producerNdx != consumerIndex) {	// need to process message
+		total_bytes += 64;	// maintain count to prevent writing past buffer
+		// don't allow copies over Fibre Channel defined length!
+		if (total_bytes <= 2048) {
+			memcpy(ulDestPtr, &fcChip->SFQ->QEntry[consumerIndex], 64);	// each SFQ entry is 64 bytes
+			ulDestPtr += 16;	// advance pointer to next 64 byte block
+		}
+		// Tachyon is producing,
+		// and we are consuming
+
+		if (++consumerIndex >= SFQ_LEN)	// check for rollover
+			consumerIndex = 0L;	// reset it
+	}
+
+	// if specified, update the Tachlite chip ConsumerIndex...
+	if (UpdateChip) {
+		fcChip->SFQ->consumerIndex = consumerIndex;
+		writel(fcChip->SFQ->consumerIndex, fcChip->Registers.SFQconsumerIndex.address);
+	}
 }
 
 
@@ -1944,42 +1756,38 @@
 // we routinely RESUME by clearing these bits, but only if the loop is up
 // to avoid ERROR IDLE messages forever.
 
-void CpqTsUnFreezeTachlite( void *pChip, int type )
+void CpqTsUnFreezeTachlite(void *pChip, int type)
 {
-  PTACHYON fcChip = (PTACHYON)pChip;
-  fcChip->Registers.TYcontrol.value = 
-    readl(fcChip->Registers.TYcontrol.address);
-            
-  // (bit 4 of value is GBIC LASER)
-  // if we 'unfreeze' the core machines before the loop is healthy
-  // (i.e. FLT, OS, LS failure bits set in FMstatus)
-  // we can get 'error idle' messages forever.  Verify that
-  // FMstatus (Link Status) is OK before unfreezing.
-
-  if( !(fcChip->Registers.FMstatus.value & 0x07000000L) && // bits clear?
-      !(fcChip->Registers.FMstatus.value & 0x80  ))  // Active LPSM?
-  {
-    fcChip->Registers.TYcontrol.value &=  ~0x300L; // clear FEQ, FFA
-    if( type == 1 )  // unfreeze ERQ only
-    {
+	PTACHYON fcChip = (PTACHYON) pChip;
+	fcChip->Registers.TYcontrol.value = readl(fcChip->Registers.TYcontrol.address);
+
+	// (bit 4 of value is GBIC LASER)
+	// if we 'unfreeze' the core machines before the loop is healthy
+	// (i.e. FLT, OS, LS failure bits set in FMstatus)
+	// we can get 'error idle' messages forever.  Verify that
+	// FMstatus (Link Status) is OK before unfreezing.
+
+	if (!(fcChip->Registers.FMstatus.value & 0x07000000L) &&	// bits clear?
+	    !(fcChip->Registers.FMstatus.value & 0x80))	// Active LPSM?
+	{
+		fcChip->Registers.TYcontrol.value &= ~0x300L;	// clear FEQ, FFA
+		if (type == 1)	// unfreeze ERQ only
+		{
 //      printk("Unfreezing ERQ\n");
-      fcChip->Registers.TYcontrol.value |= 0x10000L; // set REQ
-    }
-    else             // unfreeze both ERQ and FCP-ASSIST (SEST)
-    {
+			fcChip->Registers.TYcontrol.value |= 0x10000L;	// set REQ
+		} else		// unfreeze both ERQ and FCP-ASSIST (SEST)
+		{
 //      printk("Unfreezing ERQ & FCP-ASSIST\n");
 
-                     // set ROF, RIF, REQ - resume Outbound FCP, Inbnd FCP, ERQ
-      fcChip->Registers.TYcontrol.value |= 0x70000L; // set ROF, RIF, REQ
-    }
-
-    writel( fcChip->Registers.TYcontrol.value,
-      fcChip->Registers.TYcontrol.address);
-              
-  }
-          // readback for verify (TachLite still frozen?)
-  fcChip->Registers.TYstatus.value = 
-    readl(fcChip->Registers.TYstatus.address);
+			// set ROF, RIF, REQ - resume Outbound FCP, Inbnd FCP, ERQ
+			fcChip->Registers.TYcontrol.value |= 0x70000L;	// set ROF, RIF, REQ
+		}
+
+		writel(fcChip->Registers.TYcontrol.value, fcChip->Registers.TYcontrol.address);
+
+	}
+	// readback for verify (TachLite still frozen?)
+	fcChip->Registers.TYstatus.value = readl(fcChip->Registers.TYstatus.address);
 }
 
 
@@ -1990,21 +1798,19 @@
 // This freeze function will result in FCP & ERQ FROZEN completion
 // messages (per argument "type").
 
-void CpqTsFreezeTachlite( void *pChip, int type )
+void CpqTsFreezeTachlite(void *pChip, int type)
 {
-  PTACHYON fcChip = (PTACHYON)pChip;
-  fcChip->Registers.TYcontrol.value = 
-    readl(fcChip->Registers.TYcontrol.address);
-    
-                     //set FFA, FEQ - freezes SCSI assist and ERQ
-  if( type == 1)    // freeze ERQ only
-    fcChip->Registers.TYcontrol.value |= 0x100L; // (bit 4 is laser)
-  else              // freeze both FCP assists (SEST) and ERQ
-    fcChip->Registers.TYcontrol.value |= 0x300L; // (bit 4 is laser)
-  
-  writel( fcChip->Registers.TYcontrol.value,
-    fcChip->Registers.TYcontrol.address);
-              
+	PTACHYON fcChip = (PTACHYON) pChip;
+	fcChip->Registers.TYcontrol.value = readl(fcChip->Registers.TYcontrol.address);
+
+	//set FFA, FEQ - freezes SCSI assist and ERQ
+	if (type == 1)		// freeze ERQ only
+		fcChip->Registers.TYcontrol.value |= 0x100L;	// (bit 4 is laser)
+	else			// freeze both FCP assists (SEST) and ERQ
+		fcChip->Registers.TYcontrol.value |= 0x300L;	// (bit 4 is laser)
+
+	writel(fcChip->Registers.TYcontrol.value, fcChip->Registers.TYcontrol.address);
+
 }
 
 
@@ -2018,8 +1824,8 @@
 
 void fcParseLinkStatusCounters(PTACHYON fcChip)
 {
-  UCHAR bBuff;
-  ULONG ulBuff;
+	u8 bBuff;
+	u32 ulBuff;
 
 
 // The BB0 timer usually increments when TL is initialized, resulting
@@ -2028,61 +1834,58 @@
 // Also, reading the register does not clear it, so we have to keep an
 // additional static counter to detect rollover (yuk).
 
-  if( fcChip->fcStats.lastBB0timer == 0L)  // TL was reset? (ignore 1st values)
-  {
-                           // get TL's register counter - the "last" count
-    fcChip->fcStats.lastBB0timer = 
-      fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
-  }
-  else  // subsequent pass - check for rollover
-  {
-                              // "this" count
-    ulBuff = fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
-    if( fcChip->fcStats.lastBB0timer > ulBuff ) // rollover happened
-    {
-                                // counter advanced to max...
-      fcChip->fcStats.BB0_Timer += (0x00FFFFFFL - fcChip->fcStats.lastBB0timer);
-      fcChip->fcStats.BB0_Timer += ulBuff;  // plus some more
-
-
-    }
-    else // no rollover -- more counts or no change
-    {
-      fcChip->fcStats.BB0_Timer +=  (ulBuff - fcChip->fcStats.lastBB0timer);
+	if (fcChip->fcStats.lastBB0timer == 0L)	// TL was reset? (ignore 1st values)
+	{
+		// get TL's register counter - the "last" count
+		fcChip->fcStats.lastBB0timer = fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
+	} else			// subsequent pass - check for rollover
+	{
+		// "this" count
+		ulBuff = fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
+		if (fcChip->fcStats.lastBB0timer > ulBuff)	// rollover happened
+		{
+			// counter advanced to max...
+			fcChip->fcStats.BB0_Timer += (0x00FFFFFFL - fcChip->fcStats.lastBB0timer);
+			fcChip->fcStats.BB0_Timer += ulBuff;	// plus some more
+
+
+		} else		// no rollover -- more counts or no change
+		{
+			fcChip->fcStats.BB0_Timer += (ulBuff - fcChip->fcStats.lastBB0timer);
 
-    }
+		}
 
-    fcChip->fcStats.lastBB0timer = ulBuff;
-  }
+		fcChip->fcStats.lastBB0timer = ulBuff;
+	}
 
 
 
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 24);
-  fcChip->fcStats.LossofSignal += bBuff;
+	bBuff = (u8) (fcChip->Registers.FMLinkStatus1.value >> 24);
+	fcChip->fcStats.LossofSignal += bBuff;
 
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 16);
-  fcChip->fcStats.BadRXChar += bBuff;
+	bBuff = (u8) (fcChip->Registers.FMLinkStatus1.value >> 16);
+	fcChip->fcStats.BadRXChar += bBuff;
 
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 8);
-  fcChip->fcStats.LossofSync += bBuff;
+	bBuff = (u8) (fcChip->Registers.FMLinkStatus1.value >> 8);
+	fcChip->fcStats.LossofSync += bBuff;
 
 
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 24);
-  fcChip->fcStats.Rx_EOFa += bBuff;
+	bBuff = (u8) (fcChip->Registers.FMLinkStatus2.value >> 24);
+	fcChip->fcStats.Rx_EOFa += bBuff;
 
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 16);
-  fcChip->fcStats.Dis_Frm += bBuff;
+	bBuff = (u8) (fcChip->Registers.FMLinkStatus2.value >> 16);
+	fcChip->fcStats.Dis_Frm += bBuff;
 
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 8);
-  fcChip->fcStats.Bad_CRC += bBuff;
+	bBuff = (u8) (fcChip->Registers.FMLinkStatus2.value >> 8);
+	fcChip->fcStats.Bad_CRC += bBuff;
 }
 
 
 void cpqfcTSClearLinkStatusCounters(PTACHYON fcChip)
 {
-  ENTER("ClearLinkStatusCounters");
-  memset( &fcChip->fcStats, 0, sizeof( FCSTATS));
-  LEAVE("ClearLinkStatusCounters");
+	ENTER("ClearLinkStatusCounters");
+	memset(&fcChip->fcStats, 0, sizeof(FCSTATS));
+	LEAVE("ClearLinkStatusCounters");
 
 }
 
@@ -2110,77 +1913,74 @@
 // be correctly loaded by Tachyon silicon.  In the login payload, bytes
 // must be correctly swapped for Big Endian format.
 
-int CpqTsReadWriteWWN( PVOID pChip, int Read)
+int CpqTsReadWriteWWN(void * pChip, int Read)
 {
-  PTACHYON fcChip = (PTACHYON)pChip;
+	PTACHYON fcChip = (PTACHYON) pChip;
 #define NVRAM_SIZE 512
-  unsigned short i, count = NVRAM_SIZE;
-  UCHAR nvRam[NVRAM_SIZE], WWNbuf[8];
-  ULONG ulBuff;
-  int iStatus=-1;  // assume failure
-  int WWNoffset;
-
-  ENTER("ReadWriteWWN");
-  // Now try to read the WWN from the adapter's NVRAM
-
-  if( Read )  // READing NVRAM WWN?
-  {
-    ulBuff = cpqfcTS_ReadNVRAM( fcChip->Registers.TYstatus.address,
-                              fcChip->Registers.TYcontrol.address,
-                              count, &nvRam[0] );
-
-    if( ulBuff )   // NVRAM read successful?
-    {
-      iStatus = 0; // success!
-      
-                   // for engineering/ prototype boards, the data may be
-                   // invalid (GIGO, usually all "FF"); this prevents the
-                   // parse routine from working correctly, which means
-                   // nothing will be written to our passed buffer.
-
-      WWNoffset = cpqfcTS_GetNVRAM_data( WWNbuf, nvRam );
-
-      if( !WWNoffset ) // uninitialized NVRAM -- copy bytes directly
-      {
-        printk( "CAUTION: Copying NVRAM data on fcChip\n");
-        for( i= 0; i < 8; i++)
-          WWNbuf[i] = nvRam[i +0x2f]; // dangerous! some formats won't work
-      }
-      
-      fcChip->Registers.wwn_hi = 0L;
-      fcChip->Registers.wwn_lo = 0L;
-      for( i=0; i<4; i++)  // WWN bytes are big endian in NVRAM
-      {
-        ulBuff = 0L;
-        ulBuff = (ULONG)(WWNbuf[i]) << (8 * (3-i));
-        fcChip->Registers.wwn_hi |= ulBuff;
-      }
-      for( i=0; i<4; i++)  // WWN bytes are big endian in NVRAM
-      {
-        ulBuff = 0L;
-        ulBuff = (ULONG)(WWNbuf[i+4]) << (8 * (3-i));
-        fcChip->Registers.wwn_lo |= ulBuff;
-      }
-    }  // done reading
-    else
-    {
-
-      printk( "cpqfcTS: NVRAM read failed\n");
-
-    }
-  }
-
-  else  // WRITE
-  {
-
-    // NOTE: WRITE not supported & not used in released driver.
-
-   
-    printk("ReadWriteNRAM: can't write NVRAM; aborting write\n");
-  }
-  
-  LEAVE("ReadWriteWWN");
-  return iStatus;
+	unsigned short i, count = NVRAM_SIZE;
+	u8 nvRam[NVRAM_SIZE], WWNbuf[8];
+	u32 ulBuff;
+	int iStatus = -1;	// assume failure
+	int WWNoffset;
+
+	ENTER("ReadWriteWWN");
+	// Now try to read the WWN from the adapter's NVRAM
+
+	if (Read)		// READing NVRAM WWN?
+	{
+		ulBuff = cpqfcTS_ReadNVRAM(fcChip->Registers.TYstatus.address, fcChip->Registers.TYcontrol.address, count, &nvRam[0]);
+
+		if (ulBuff)	// NVRAM read successful?
+		{
+			iStatus = 0;	// success!
+
+			// for engineering/ prototype boards, the data may be
+			// invalid (GIGO, usually all "FF"); this prevents the
+			// parse routine from working correctly, which means
+			// nothing will be written to our passed buffer.
+
+			WWNoffset = cpqfcTS_GetNVRAM_data(WWNbuf, nvRam);
+
+			if (!WWNoffset)	// uninitialized NVRAM -- copy bytes directly
+			{
+				printk("CAUTION: Copying NVRAM data on fcChip\n");
+				for (i = 0; i < 8; i++)
+					WWNbuf[i] = nvRam[i + 0x2f];	// dangerous! some formats won't work
+			}
+
+			fcChip->Registers.wwn_hi = 0L;
+			fcChip->Registers.wwn_lo = 0L;
+			for (i = 0; i < 4; i++)	// WWN bytes are big endian in NVRAM
+			{
+				ulBuff = 0L;
+				ulBuff = (u32) (WWNbuf[i]) << (8 * (3 - i));
+				fcChip->Registers.wwn_hi |= ulBuff;
+			}
+			for (i = 0; i < 4; i++)	// WWN bytes are big endian in NVRAM
+			{
+				ulBuff = 0L;
+				ulBuff = (u32) (WWNbuf[i + 4]) << (8 * (3 - i));
+				fcChip->Registers.wwn_lo |= ulBuff;
+			}
+		}		// done reading
+		else {
+
+			printk("cpqfcTS: NVRAM read failed\n");
+
+		}
+	}
+
+	else			// WRITE
+	{
+
+		// NOTE: WRITE not supported & not used in released driver.
+
+
+		printk("ReadWriteNRAM: can't write NVRAM; aborting write\n");
+	}
+
+	LEAVE("ReadWriteWWN");
+	return iStatus;
 }
 
 
@@ -2192,39 +1992,36 @@
 // adapter does not use the NM24C03 chip, so this function only works on
 // Compaq's adapters.
 
-int CpqTsReadWriteNVRAM( PVOID pChip, PVOID buf, int Read)
+int CpqTsReadWriteNVRAM(void * pChip, void * buf, int Read)
 {
-  PTACHYON fcChip = (PTACHYON)pChip;
+	PTACHYON fcChip = (PTACHYON) pChip;
 #define NVRAM_SIZE 512
-  ULONG ulBuff;
-  UCHAR *ucPtr = buf; // cast caller's void ptr to UCHAR array
-  int iStatus=-1;  // assume failure
-
-     
-  if( Read )  // READing NVRAM?
-  {
-    ulBuff = cpqfcTS_ReadNVRAM(   // TRUE on success
-                fcChip->Registers.TYstatus.address,
-                fcChip->Registers.TYcontrol.address,
-                256,            // bytes to write
-                ucPtr );        // source ptr
-
-
-    if( ulBuff )
-      iStatus = 0; // success
-    else
-    {
+	u32 ulBuff;
+	u8 *ucPtr = buf;	// cast caller's void ptr to u8 array
+	int iStatus = -1;	// assume failure
+
+
+	if (Read)		// READing NVRAM?
+	{
+		ulBuff = cpqfcTS_ReadNVRAM(	// TRUE on success
+						  fcChip->Registers.TYstatus.address, fcChip->Registers.TYcontrol.address, 256,	// bytes to write
+						  ucPtr);	// source ptr
+
+
+		if (ulBuff)
+			iStatus = 0;	// success
+		else {
 #ifdef DBG
-      printk( "CAUTION: NVRAM read failed\n");
+			printk("CAUTION: NVRAM read failed\n");
 #endif
-    }
-  }  // done reading
+		}
+	}			// done reading
 
-  else  // WRITING NVRAM 
-  {
+	else			// WRITING NVRAM 
+	{
+
+		printk("cpqfcTS: WRITE of FC Controller's NVRAM disabled\n");
+	}
 
-    printk("cpqfcTS: WRITE of FC Controller's NVRAM disabled\n");
-  }
-    
-  return iStatus;
+	return iStatus;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfcTSi2c.c linux-2.4.21/drivers/scsi/cpqfcTSi2c.c
--- linux-2.4.20/drivers/scsi/cpqfcTSi2c.c	2000-09-21 20:22:05.000000000 +0000
+++ linux-2.4.21/drivers/scsi/cpqfcTSi2c.c	2002-12-18 18:58:05.000000000 +0000
@@ -25,121 +25,105 @@
 // Orignal source author unknown
 
 #include <linux/types.h>
-enum boolean { FALSE, TRUE } ;
-
-
-#ifndef UCHAR
-typedef __u8 UCHAR;
-#endif
-#ifndef BOOLEAN
-typedef __u8 BOOLEAN;
-#endif
-#ifndef USHORT
-typedef __u16 USHORT;
-#endif
-#ifndef ULONG
-typedef __u32 ULONG;
-#endif
-
-
 #include <linux/string.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
-#include <asm/io.h>  // struct pt_regs for IRQ handler & Port I/O
+#include <asm/io.h>		// struct pt_regs for IRQ handler & Port I/O
 
 #include "cpqfcTSchip.h"
 
-static void tl_i2c_tx_byte( void* GPIOout, UCHAR data );
-/*static BOOLEAN tl_write_i2c_page_portion( void* GPIOin, void* GPIOout,
-  USHORT startOffset,  // e.g. 0x2f for WWN start
-  USHORT count,
-  UCHAR *buf );
-*/
+static void tl_i2c_tx_byte(void *GPIOout, u8 data);
 
-//
-// Tachlite GPIO2, GPIO3 (I2C) DEFINES
-// The NVRAM chip NM24C03 defines SCL (serial clock) and SDA (serial data)
-// GPIO2 drives SDA, and GPIO3 drives SCL
-// 
-// Since Tachlite inverts the state of the GPIO 0-3 outputs, SET writes 0
-// and clear writes 1. The input lines (read in TL status) is NOT inverted
-// This really helps confuse the code and debugging.
+/*
+ * Tachlite GPIO2, GPIO3 (I2C) DEFINES
+ * The NVRAM chip NM24C03 defines SCL (serial clock) and SDA (serial data)
+ * GPIO2 drives SDA, and GPIO3 drives SCL
+ * 
+ * Since Tachlite inverts the state of the GPIO 0-3 outputs, SET writes 0
+ * and clear writes 1. The input lines (read in TL status) is NOT inverted
+ * This really helps confuse the code and debugging.
+ */
+ 
+#define SET_DATA_HI		0x0
+#define SET_DATA_LO		0x8
+#define SET_CLOCK_HI		0x0
+#define SET_CLOCK_LO		0x4
 
-#define SET_DATA_HI  0x0
-#define SET_DATA_LO  0x8
-#define SET_CLOCK_HI 0x0
-#define SET_CLOCK_LO 0x4
+#define SENSE_DATA_HI		0x8
+#define SENSE_DATA_LO		0x0
+#define SENSE_CLOCK_HI		0x4
+#define SENSE_CLOCK_LO		0x0
 
-#define SENSE_DATA_HI  0x8
-#define SENSE_DATA_LO  0x0
-#define SENSE_CLOCK_HI 0x4
-#define SENSE_CLOCK_LO 0x0
+#define SLAVE_READ_ADDRESS	0xA1
+#define SLAVE_WRITE_ADDRESS	0xA0
 
-#define SLAVE_READ_ADDRESS    0xA1
-#define SLAVE_WRITE_ADDRESS   0xA0
-					      
 
-static void i2c_delay(ULONG mstime);
-static void tl_i2c_clock_pulse( UCHAR , void* GPIOout);
-static UCHAR tl_read_i2c_data( void* );
+static void i2c_delay(u32 mstime);
+static void tl_i2c_clock_pulse(u8, void *GPIOout);
+static u8 tl_read_i2c_data(void *);
 
 
 //-----------------------------------------------------------------------------
 //
-//      Name:   I2C_RX_ACK
+//      Name:   tl_i2c_rx_ack
 //
 //      This routine receives an acknowledge over the I2C bus.
 //
 //-----------------------------------------------------------------------------
-static unsigned short tl_i2c_rx_ack( void* GPIOin, void* GPIOout )
+static unsigned short tl_i2c_rx_ack(void *GPIOin, void *GPIOout)
 {
-  unsigned long value;
+	unsigned long value;
 
 	// do clock pulse, let data line float high
-  tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
+	tl_i2c_clock_pulse(SET_DATA_HI, GPIOout);
 
 	// slave must drive data low for acknowledge
-  value = tl_read_i2c_data( GPIOin);
-  if (value & SENSE_DATA_HI )
-    return( FALSE );
+	value = tl_read_i2c_data(GPIOin);
+	if (value & SENSE_DATA_HI)
+		return 0;
 
-  return( TRUE );
+	return 1;
 }
+
 //-----------------------------------------------------------------------------
 //
-//      Name:   READ_I2C_REG
+//      Name:   tl_read_i2c_reg
 //
 //      This routine reads the I2C control register using the global
 //      IO address stored in gpioreg.
 //
 //-----------------------------------------------------------------------------
-static UCHAR tl_read_i2c_data( void* gpioreg )
+static u8 tl_read_i2c_data(void *gpioreg)
 {
-  return( (UCHAR)(readl( gpioreg ) & 0x08L) ); // GPIO3
+	return ((u8) (readl(gpioreg) & 0x08L));	// GPIO3
 }
+
 //-----------------------------------------------------------------------------
 //
-//      Name:   WRITE_I2C_REG
+//      Name:   tl_write_i2c_reg
 //
 //      This routine writes the I2C control register using the global
 //      IO address stored in gpioreg.
 //      In Tachlite, we don't want to modify other bits in TL Control reg.
 //
 //-----------------------------------------------------------------------------
-static void tl_write_i2c_reg( void* gpioregOUT, UCHAR value )
+static void tl_write_i2c_reg(void *gpioregOUT, u8 value)
 {
-  ULONG  temp;
+	u32 temp;
 
 	// First read the register and clear out the old bits
-  temp = readl( gpioregOUT ) & 0xfffffff3L;
+	temp = readl(gpioregOUT) & 0xfffffff3L;
 
 	// Now or in the new data and send it back out
-  writel( temp | value, gpioregOUT);
+	writel(temp | value, gpioregOUT);
+	
+	/* PCI posting ???? */
 }
+
 //-----------------------------------------------------------------------------
 //
-//      Name:   I2C_TX_START
+//      Name:   tl_i2c_tx_start
 //
 //      This routine transmits a start condition over the I2C bus.
 //      1. Set SCL (clock, GPIO2) HIGH, set SDA (data, GPIO3) HIGH,
@@ -149,165 +133,162 @@
 //      NOTE! In TL control reg., output 1 means chip sees LOW
 //
 //-----------------------------------------------------------------------------
-static unsigned short tl_i2c_tx_start( void* GPIOin, void* GPIOout )
+static unsigned short tl_i2c_tx_start(void *GPIOin, void *GPIOout)
 {
-  unsigned short i;
-  ULONG value;
+	unsigned short i;
+	u32 value;
 
-  if ( !(tl_read_i2c_data(GPIOin) & SENSE_DATA_HI))
-  {
-    // start with clock high, let data float high
-    tl_write_i2c_reg(  GPIOout, SET_DATA_HI | SET_CLOCK_HI );
-
-    // keep sending clock pulses if slave is driving data line
-    for (i = 0; i < 10; i++)
-    {
-      tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
-
-      if ( tl_read_i2c_data(GPIOin) & SENSE_DATA_HI )
-	break;
-    }
+	if (!(tl_read_i2c_data(GPIOin) & SENSE_DATA_HI)) {
+		// start with clock high, let data float high
+		tl_write_i2c_reg(GPIOout, SET_DATA_HI | SET_CLOCK_HI);
+
+		// keep sending clock pulses if slave is driving data line
+		for (i = 0; i < 10; i++) {
+			tl_i2c_clock_pulse(SET_DATA_HI, GPIOout);
+
+			if (tl_read_i2c_data(GPIOin) & SENSE_DATA_HI)
+				break;
+		}
 
 		// if he's still driving data low after 10 clocks, abort
-    value = tl_read_i2c_data( GPIOin ); // read status
-    if (!(value & 0x08) )
-      return( FALSE );
-  }
-
+		value = tl_read_i2c_data(GPIOin);	// read status
+		if (!(value & 0x08))
+			return 0;
+	}
 
 	// To START, bring data low while clock high
-  tl_write_i2c_reg(  GPIOout, SET_CLOCK_HI | SET_DATA_LO );
+	tl_write_i2c_reg(GPIOout, SET_CLOCK_HI | SET_DATA_LO);
 
-  i2c_delay(0);
+	udelay(5);
 
-  return( TRUE );                           // TX start successful
+	return 1;		// TX start successful
 }
+
 //-----------------------------------------------------------------------------
 //
-//      Name:   I2C_TX_STOP
+//      Name:   tl_i2c_tx_stop
 //
 //      This routine transmits a stop condition over the I2C bus.
 //
 //-----------------------------------------------------------------------------
 
-static unsigned short tl_i2c_tx_stop( void* GPIOin, void* GPIOout )
+static unsigned short tl_i2c_tx_stop(void *GPIOin, void *GPIOout)
 {
-  int i;
+	int i;
 
-  for (i = 0; i < 10; i++) 
-  {
-  // Send clock pulse, drive data line low
-    tl_i2c_clock_pulse( SET_DATA_LO, GPIOout );
+	for (i = 0; i < 10; i++) {
+		// Send clock pulse, drive data line low
+		tl_i2c_clock_pulse(SET_DATA_LO, GPIOout);
 
-  // To STOP, bring data high while clock high
-    tl_write_i2c_reg(  GPIOout, SET_DATA_HI | SET_CLOCK_HI );
+		// To STOP, bring data high while clock high
+		tl_write_i2c_reg(GPIOout, SET_DATA_HI | SET_CLOCK_HI);
 
-  // Give the data line time to float high
-    i2c_delay(0);
+		// Give the data line time to float high
+		udelay(5);
 
-  // If slave is driving data line low, there's a problem; retry
-    if ( tl_read_i2c_data(GPIOin) & SENSE_DATA_HI )
-      return( TRUE );  // TX STOP successful!
-  }
+		// If slave is driving data line low, there's a problem; retry
+		if (tl_read_i2c_data(GPIOin) & SENSE_DATA_HI)
+			return 1;	// TX STOP successful!
+	}
 
-  return( FALSE );                      // error
+	return 0;		// error
 }
+
 //-----------------------------------------------------------------------------
 //
-//      Name:   I2C_TX_uchar
+//      Name:   tl_i2c_tx_byte
 //
 //      This routine transmits a byte across the I2C bus.
 //
 //-----------------------------------------------------------------------------
-static void tl_i2c_tx_byte( void* GPIOout, UCHAR data )
+static void tl_i2c_tx_byte(void *GPIOout, u8 data)
 {
-  UCHAR bit;
+	u8 bit;
 
-  for (bit = 0x80; bit; bit >>= 1)
-  {
-    if( data & bit )
-      tl_i2c_clock_pulse( (UCHAR)SET_DATA_HI, GPIOout);
-    else
-      tl_i2c_clock_pulse( (UCHAR)SET_DATA_LO, GPIOout);
-  }  
+	for (bit = 0x80; bit; bit >>= 1) {
+		if (data & bit)
+			tl_i2c_clock_pulse((u8) SET_DATA_HI, GPIOout);
+		else
+			tl_i2c_clock_pulse((u8) SET_DATA_LO, GPIOout);
+	}
 }
+
 //-----------------------------------------------------------------------------
 //
-//      Name:   I2C_RX_uchar
+//      Name:   tl_i2c_rx_byte
 //
 //      This routine receives a byte across the I2C bus.
 //
 //-----------------------------------------------------------------------------
-static UCHAR tl_i2c_rx_byte( void* GPIOin, void* GPIOout )
+static u8 tl_i2c_rx_byte(void *GPIOin, void *GPIOout)
 {
-  UCHAR bit;
-  UCHAR data = 0;
+	u8 bit;
+	u8 data = 0;
 
 
-  for (bit = 0x80; bit; bit >>= 1) {
-    // do clock pulse, let data line float high
-    tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
+	for (bit = 0x80; bit; bit >>= 1) {
+		// do clock pulse, let data line float high
+		tl_i2c_clock_pulse(SET_DATA_HI, GPIOout);
 
-    // read data line
-    if ( tl_read_i2c_data( GPIOin) & 0x08 )
-      data |= bit;
-  }
+		// read data line
+		if (tl_read_i2c_data(GPIOin) & 0x08)
+			data |= bit;
+	}
 
-  return (data);
+	return (data);
 }
+
 //*****************************************************************************
 //*****************************************************************************
 // Function:   read_i2c_nvram
-// Arguments:  UCHAR count     number of bytes to read
-//             UCHAR *buf      area to store the bytes read
+// Arguments:  u8 count     number of bytes to read
+//             u8 *buf      area to store the bytes read
 // Returns:    0 - failed
 //             1 - success
 //*****************************************************************************
 //*****************************************************************************
-unsigned long cpqfcTS_ReadNVRAM( void* GPIOin, void* GPIOout , USHORT count,
-	UCHAR *buf )
+unsigned long cpqfcTS_ReadNVRAM(void *GPIOin, void *GPIOout, u16 count, u8 * buf)
 {
-  unsigned short i;
+	unsigned short i;
 
-  if( !( tl_i2c_tx_start(GPIOin, GPIOout) ))
-    return FALSE;
+	if (!(tl_i2c_tx_start(GPIOin, GPIOout)))
+		return 0;
 
-  // Select the NVRAM for "dummy" write, to set the address
-  tl_i2c_tx_byte( GPIOout , SLAVE_WRITE_ADDRESS );
-  if ( !tl_i2c_rx_ack(GPIOin, GPIOout ) )
-    return( FALSE );
-
-  // Now send the address where we want to start reading  
-  tl_i2c_tx_byte( GPIOout , 0 );
-  if ( !tl_i2c_rx_ack(GPIOin, GPIOout ) )
-    return( FALSE );
-
-  // Send a repeated start condition and select the
-  //  slave for reading now.
-  if( tl_i2c_tx_start(GPIOin, GPIOout) )
-    tl_i2c_tx_byte( GPIOout, SLAVE_READ_ADDRESS );
-
-  if ( !tl_i2c_rx_ack(GPIOin, GPIOout) )
-    return( FALSE );
-
-  // this loop will now read out the data and store it
-  //  in the buffer pointed to by buf
-  for ( i=0; i<count; i++) 
-  {
-    *buf++ = tl_i2c_rx_byte(GPIOin, GPIOout);
-
-    // Send ACK by holding data line low for 1 clock
-    if ( i < (count-1) )
-      tl_i2c_clock_pulse( 0x08, GPIOout );
-    else {
-	// Don't send ack for final byte
-      tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
-    }
-  }
+	// Select the NVRAM for "dummy" write, to set the address
+	tl_i2c_tx_byte(GPIOout, SLAVE_WRITE_ADDRESS);
+	if (!tl_i2c_rx_ack(GPIOin, GPIOout))
+		return 0;
+
+	// Now send the address where we want to start reading  
+	tl_i2c_tx_byte(GPIOout, 0);
+	if (!tl_i2c_rx_ack(GPIOin, GPIOout))
+		return 0;
+
+	// Send a repeated start condition and select the
+	//  slave for reading now.
+	if (tl_i2c_tx_start(GPIOin, GPIOout))
+		tl_i2c_tx_byte(GPIOout, SLAVE_READ_ADDRESS);
+
+	if (!tl_i2c_rx_ack(GPIOin, GPIOout))
+		return 0;
+
+	// this loop will now read out the data and store it
+	//  in the buffer pointed to by buf
+	for (i = 0; i < count; i++) {
+		*buf++ = tl_i2c_rx_byte(GPIOin, GPIOout);
+
+		// Send ACK by holding data line low for 1 clock
+		if (i < (count - 1))
+			tl_i2c_clock_pulse(0x08, GPIOout);
+		else {
+			// Don't send ack for final byte
+			tl_i2c_clock_pulse(SET_DATA_HI, GPIOout);
+		}
+	}
 
-  tl_i2c_tx_stop(GPIOin, GPIOout);
+	tl_i2c_tx_stop(GPIOin, GPIOout);
 
-  return( TRUE );
+	return 1;
 }
 
 //****************************************************************
@@ -320,22 +301,22 @@
 //
 //****************************************************************
 
-static void tl_set_clock(void* gpioreg)
+static void tl_set_clock(void *gpioreg)
 {
-  ULONG ret_val;
+	u32 ret_val;
 
-  ret_val = readl( gpioreg );
-  ret_val &= 0xffffffFBL;  // clear GPIO2 (SCL)
-  writel( ret_val, gpioreg);
+	ret_val = readl(gpioreg);
+	ret_val &= 0xffffffFBL;	// clear GPIO2 (SCL)
+	writel(ret_val, gpioreg);
 }
 
-static void tl_clr_clock(void* gpioreg)
+static void tl_clr_clock(void *gpioreg)
 {
-  ULONG ret_val;
+	u32 ret_val;
 
-  ret_val = readl( gpioreg );
-  ret_val |= SET_CLOCK_LO;
-  writel( ret_val, gpioreg);
+	ret_val = readl(gpioreg);
+	ret_val |= SET_CLOCK_LO;
+	writel(ret_val, gpioreg);
 }
 
 //*****************************************************************
@@ -345,33 +326,33 @@
 //
 //
 //*****************************************************************
-static void tl_i2c_clock_pulse( UCHAR value, void* GPIOout  )
+static void tl_i2c_clock_pulse(u8 value, void *GPIOout)
 {
-  ULONG ret_val;
+	u32 ret_val;
 
-  // clear the clock bit
-  tl_clr_clock( GPIOout );
+	// clear the clock bit
+	tl_clr_clock(GPIOout);
 
-  i2c_delay(0);
+	udelay(5);
 
 
-  // read the port to preserve non-I2C bits
-  ret_val = readl( GPIOout );
+	// read the port to preserve non-I2C bits
+	ret_val = readl(GPIOout);
 
-  // clear the data & clock bits
-  ret_val &= 0xFFFFFFf3;
+	// clear the data & clock bits
+	ret_val &= 0xFFFFFFf3;
 
-  // write the value passed in...
-  // data can only change while clock is LOW!
-  ret_val |= value;           // the data
-  ret_val |= SET_CLOCK_LO;    // the clock
-  writel( ret_val, GPIOout );
+	// write the value passed in...
+	// data can only change while clock is LOW!
+	ret_val |= value;	// the data
+	ret_val |= SET_CLOCK_LO;	// the clock
+	writel(ret_val, GPIOout);
 
-  i2c_delay(0);
+	udelay(5);
 
 
-  //set clock bit
-  tl_set_clock( GPIOout);
+	//set clock bit
+	tl_set_clock(GPIOout);
 }
 
 
@@ -384,110 +365,71 @@
 //
 //
 //*****************************************************************
-int cpqfcTS_GetNVRAM_data( UCHAR *wwnbuf, UCHAR *buf )
+int cpqfcTS_GetNVRAM_data(u8 * wwnbuf, u8 * buf)
 {
-  ULONG len;
-  ULONG sub_len;
-  ULONG ptr_inc;
-  ULONG i;
-  ULONG j;
-  UCHAR *data_ptr;
-  UCHAR  z;
-  UCHAR  name;
-  UCHAR  sub_name;
-  UCHAR  done;
-  int iReturn=0;  // def. 0 offset is failure to find WWN field
-  
-
-	  
-  data_ptr = (UCHAR *)buf;
-
-  done = FALSE;
-  i = 0;
-
-  while ( (i < 128) && (!done) ) 
-  {
-    z = data_ptr[i];\
-    if ( !(z & 0x80) )  
-    {	
-      len  = 1 + (z & 0x07);
-
-      name = (z & 0x78) >> 3;
-      if (name == 0x0F)
-        done = TRUE;
-    }
-    else 
-    {
-      name = z & 0x7F;
-      len  = 3 + data_ptr[i+1] + (data_ptr[i+2] << 8);
-           
-      switch (name) 
-      {
-      case 0x0D:
-	//
-	  j = i + 3;
-	  //
-	  if ( data_ptr[j] == 0x3b ) {
-	    len = 6;
-	    break;
-	  }
-
-	  while ( j<(i+len) ) {
-	    sub_name = (data_ptr[j] & 0x3f);
-	    sub_len  = data_ptr[j+1] + 
-	               (data_ptr[j+2] << 8);
-            ptr_inc  = sub_len + 3; 
-	    switch (sub_name) 
-	    {
-	    case 0x3C:
-              memcpy( wwnbuf, &data_ptr[j+3], 8);
-              iReturn = j+3;
-              break;
-            default:
-              break;
-	    }
-	    j += ptr_inc;
-          }
-	  break;
-        default:
-	  break;
-      }  
-    }  
-  //
-    i += len;
-  }  // end while 
-  return iReturn;
+	u32 len;
+	u32 sub_len;
+	u32 ptr_inc;
+	u32 i;
+	u32 j;
+	u8 *data_ptr;
+	u8 z;
+	u8 name;
+	u8 sub_name;
+	u8 done;
+	int ret = 0;	// def. 0 offset is failure to find WWN field
+
+
+
+	data_ptr = (u8 *) buf;
+
+	done = 0;
+	i = 0;
+
+	while (i < 128 && !done) {
+		z = data_ptr[i];
+		if (!(z & 0x80)) {
+			len = 1 + (z & 0x07);
+
+			name = (z & 0x78) >> 3;
+			if (name == 0x0F)
+				done = 1;
+		} else {
+			name = z & 0x7F;
+			len = 3 + data_ptr[i + 1] + (data_ptr[i + 2] << 8);
+
+			switch (name) {
+			case 0x0D:
+				//
+				j = i + 3;
+				//
+				if (data_ptr[j] == 0x3b) {
+					len = 6;
+					break;
+				}
+
+				while (j < (i + len)) {
+					sub_name = (data_ptr[j] & 0x3f);
+					sub_len = data_ptr[j + 1] + (data_ptr[j + 2] << 8);
+					ptr_inc = sub_len + 3;
+					switch (sub_name) {
+					case 0x3C:
+						memcpy(wwnbuf, &data_ptr[j + 3], 8);
+						ret = j + 3;
+						break;
+					default:
+						break;
+					}
+					j += ptr_inc;
+				}
+				break;
+			default:
+				break;
+			}
+		}
+		//
+		i += len;
+	}			// end while 
+	return ret;
 }
 
-
-
-
-
-// define a short 5 micro sec delay, and longer (ms) delay
-
-static void i2c_delay(ULONG mstime)
-{
-  ULONG i;
-  
-// NOTE: we only expect to use these delays when reading
-// our adapter's NVRAM, which happens only during adapter reset.
-// Delay technique from "Linux Device Drivers", A. Rubini 
-// (1st Ed.) pg 137.
-
-//  printk(" delay %lx  ", mstime);
-  if( mstime ) // ms delay?
-  {
-    // delay technique
-    for( i=0; i < mstime; i++)
-      udelay(1000); // 1ms per loop
-	
-  }
-  else  // 5 micro sec delay
-  
-    udelay( 5 ); // micro secs
-  
-//  printk("done\n");
-}
-
-
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfcTSinit.c linux-2.4.21/drivers/scsi/cpqfcTSinit.c
--- linux-2.4.20/drivers/scsi/cpqfcTSinit.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/scsi/cpqfcTSinit.c	2002-12-18 18:58:02.000000000 +0000
@@ -29,8 +29,6 @@
 */
 
 
-#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-
 #include <linux/blk.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -39,17 +37,16 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/timer.h>
-#include <linux/ioport.h>  // request_region() prototype
-#include <linux/vmalloc.h> // ioremap()
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,7)
+#include <linux/ioport.h>	// request_region() prototype
+#include <linux/slab.h>
+#include <linux/vmalloc.h>	// ioremap()
 #include <linux/completion.h>
-#endif
 #ifdef __alpha__
 #define __KERNEL_SYSCALLS__
 #endif
 #include <asm/unistd.h>
 #include <asm/io.h>
-#include <asm/uaccess.h>   // ioctl related
+#include <asm/uaccess.h>	// ioctl related
 #include <asm/irq.h>
 #include <linux/spinlock.h>
 #include "sd.h"
@@ -61,48 +58,21 @@
 
 #include "cpqfcTS.h"
 
-#include <linux/config.h>  
+#include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h> 
+#include <linux/version.h>
 
 /* Embedded module documentation macros - see module.h */
 MODULE_AUTHOR("Compaq Computer Corporation");
-MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA v. 2.1.1");
+MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA v. 2.1.2");
 MODULE_LICENSE("GPL");
-  
-int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, unsigned int reset_flags);
-
-// This struct was originally defined in 
-// /usr/src/linux/include/linux/proc_fs.h
-// since it's only partially implemented, we only use first
-// few fields...
-// NOTE: proc_fs changes in 2.4 kernel
-
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
-static struct proc_dir_entry proc_scsi_cpqfcTS =
-{
-  PROC_SCSI_CPQFCTS,           // ushort low_ino (enumerated list)
-  7,                           // ushort namelen
-  DEV_NAME,                    // const char* name
-  S_IFDIR | S_IRUGO | S_IXUGO, // mode_t mode
-  2                            // nlink_t nlink
-	                       // etc. ...
-};
 
+int cpqfcTS_TargetDeviceReset(Scsi_Device * ScsiDev, unsigned int reset_flags);
 
-#endif
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,7)
-#  define CPQFC_DECLARE_COMPLETION(x) DECLARE_COMPLETION(x)
-#  define CPQFC_WAITING waiting
-#  define CPQFC_COMPLETE(x) complete(x)
-#  define CPQFC_WAIT_FOR_COMPLETION(x) wait_for_completion(x);
-#else
-#  define CPQFC_DECLARE_COMPLETION(x) DECLARE_MUTEX_LOCKED(x)
-#  define CPQFC_WAITING sem
-#  define CPQFC_COMPLETE(x) up(x)
-#  define CPQFC_WAIT_FOR_COMPLETION(x) down(x)
-#endif
+#define CPQFC_DECLARE_COMPLETION(x) DECLARE_COMPLETION(x)
+#define CPQFC_WAITING waiting
+#define CPQFC_COMPLETE(x) complete(x)
+#define CPQFC_WAIT_FOR_COMPLETION(x) wait_for_completion(x);
 
 /* local function to load our per-HBA (local) data for chip
    registers, FC link state, all FC exchanges, etc.
@@ -112,120 +82,86 @@
    Name) are not necessary.
    
 */
-static void Cpqfc_initHBAdata( CPQFCHBA *cpqfcHBAdata, struct pci_dev *PciDev )
+static void Cpqfc_initHBAdata(CPQFCHBA * cpqfcHBAdata, struct pci_dev *PciDev)
 {
-             
-  cpqfcHBAdata->PciDev = PciDev; // copy PCI info ptr
 
-  // since x86 port space is 64k, we only need the lower 16 bits
-  cpqfcHBAdata->fcChip.Registers.IOBaseL = 
-    PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
-  
-  cpqfcHBAdata->fcChip.Registers.IOBaseU = 
-    PciDev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK;
-  
-  // 32-bit memory addresses
-  cpqfcHBAdata->fcChip.Registers.MemBase = 
-    PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK;
-
-  cpqfcHBAdata->fcChip.Registers.ReMapMemBase = 
-    ioremap( PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK,
-             0x200);
-  
-  cpqfcHBAdata->fcChip.Registers.RAMBase = 
-    PciDev->resource[4].start;
-  
-  cpqfcHBAdata->fcChip.Registers.SROMBase =  // NULL for HP TS adapter
-    PciDev->resource[5].start;
-  
-  // now the Tachlite chip registers
-  // the REGISTER struct holds both the physical address & last
-  // written value (some TL registers are WRITE ONLY)
-
-  cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_SFQ_CONSUMER_INDEX;
-
-  cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX;
-      
-  // TL Frame Manager
-  cpqfcHBAdata->fcChip.Registers.FMconfig.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONFIG;
-  cpqfcHBAdata->fcChip.Registers.FMcontrol.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONTROL;
-  cpqfcHBAdata->fcChip.Registers.FMstatus.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_STATUS;
-  cpqfcHBAdata->fcChip.Registers.FMLinkStatus1.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT1;
-  cpqfcHBAdata->fcChip.Registers.FMLinkStatus2.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT2;
-  cpqfcHBAdata->fcChip.Registers.FMBB_CreditZero.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_BB_CREDIT0;
-      
-      // TL Control Regs
-  cpqfcHBAdata->fcChip.Registers.TYconfig.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONFIG;
-  cpqfcHBAdata->fcChip.Registers.TYcontrol.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONTROL;
-  cpqfcHBAdata->fcChip.Registers.TYstatus.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_STATUS;
-  cpqfcHBAdata->fcChip.Registers.rcv_al_pa.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_RCV_AL_PA;
-  cpqfcHBAdata->fcChip.Registers.ed_tov.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_ED_TOV;
-
-
-  cpqfcHBAdata->fcChip.Registers.INTEN.address = 
-	        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTEN;
-  cpqfcHBAdata->fcChip.Registers.INTPEND.address = 
-	        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTPEND;
-  cpqfcHBAdata->fcChip.Registers.INTSTAT.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTSTAT;
-
-  DEBUG_PCI(printk("  cpqfcHBAdata->fcChip.Registers. :\n"));
-  DEBUG_PCI(printk("    IOBaseL = %x\n", 
-    cpqfcHBAdata->fcChip.Registers.IOBaseL));
-  DEBUG_PCI(printk("    IOBaseU = %x\n", 
-    cpqfcHBAdata->fcChip.Registers.IOBaseU));
-  
-  printk(" ioremap'd Membase: %p\n", cpqfcHBAdata->fcChip.Registers.ReMapMemBase);
-  
-  DEBUG_PCI(printk("    SFQconsumerIndex.address = %p\n", 
-    cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address));
-  DEBUG_PCI(printk("    ERQproducerIndex.address = %p\n", 
-    cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address));
-  DEBUG_PCI(printk("    TYconfig.address = %p\n", 
-    cpqfcHBAdata->fcChip.Registers.TYconfig.address));
-  DEBUG_PCI(printk("    FMconfig.address = %p\n", 
-    cpqfcHBAdata->fcChip.Registers.FMconfig.address));
-  DEBUG_PCI(printk("    FMcontrol.address = %p\n", 
-    cpqfcHBAdata->fcChip.Registers.FMcontrol.address));
-
-  // set default options for FC controller (chip)
-  cpqfcHBAdata->fcChip.Options.initiator = 1;  // default: SCSI initiator
-  cpqfcHBAdata->fcChip.Options.target = 0;     // default: SCSI target
-  cpqfcHBAdata->fcChip.Options.extLoopback = 0;// default: no loopback @GBIC
-  cpqfcHBAdata->fcChip.Options.intLoopback = 0;// default: no loopback inside chip
-
-  // set highest and lowest FC-PH version the adapter/driver supports
-  // (NOT strict compliance)
-  cpqfcHBAdata->fcChip.highest_FCPH_ver = FC_PH3;
-  cpqfcHBAdata->fcChip.lowest_FCPH_ver = FC_PH43;
-
-  // set function points for this controller / adapter
-  cpqfcHBAdata->fcChip.ResetTachyon = CpqTsResetTachLite;
-  cpqfcHBAdata->fcChip.FreezeTachyon = CpqTsFreezeTachlite;
-  cpqfcHBAdata->fcChip.UnFreezeTachyon = CpqTsUnFreezeTachlite;
-  cpqfcHBAdata->fcChip.CreateTachyonQues = CpqTsCreateTachLiteQues;
-  cpqfcHBAdata->fcChip.DestroyTachyonQues = CpqTsDestroyTachLiteQues;
-  cpqfcHBAdata->fcChip.InitializeTachyon = CpqTsInitializeTachLite;  
-  cpqfcHBAdata->fcChip.LaserControl = CpqTsLaserControl;  
-  cpqfcHBAdata->fcChip.ProcessIMQEntry = CpqTsProcessIMQEntry;
-  cpqfcHBAdata->fcChip.InitializeFrameManager = CpqTsInitializeFrameManager;;  
-  cpqfcHBAdata->fcChip.ReadWriteWWN = CpqTsReadWriteWWN;
-  cpqfcHBAdata->fcChip.ReadWriteNVRAM = CpqTsReadWriteNVRAM;
+	cpqfcHBAdata->PciDev = PciDev;	// copy PCI info ptr
+
+	// since x86 port space is 64k, we only need the lower 16 bits
+	cpqfcHBAdata->fcChip.Registers.IOBaseL = PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
+	cpqfcHBAdata->fcChip.Registers.IOBaseU = PciDev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK;
+
+	// 32-bit memory addresses
+	cpqfcHBAdata->fcChip.Registers.MemBase = PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK;
+	cpqfcHBAdata->fcChip.Registers.ReMapMemBase = ioremap(PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK, 0x200);
+	cpqfcHBAdata->fcChip.Registers.RAMBase = PciDev->resource[4].start;
+	cpqfcHBAdata->fcChip.Registers.SROMBase = PciDev->resource[5].start; // NULL for HP TS adapter
+
+	// now the Tachlite chip registers
+	// the REGISTER struct holds both the physical address & last
+	// written value (some TL registers are WRITE ONLY)
+
+	cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_SFQ_CONSUMER_INDEX;
+
+	cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX;
+
+	// TL Frame Manager
+	cpqfcHBAdata->fcChip.Registers.FMconfig.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONFIG;
+	cpqfcHBAdata->fcChip.Registers.FMcontrol.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONTROL;
+	cpqfcHBAdata->fcChip.Registers.FMstatus.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_STATUS;
+	cpqfcHBAdata->fcChip.Registers.FMLinkStatus1.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT1;
+	cpqfcHBAdata->fcChip.Registers.FMLinkStatus2.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT2;
+	cpqfcHBAdata->fcChip.Registers.FMBB_CreditZero.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_BB_CREDIT0;
+
+	// TL Control Regs
+	cpqfcHBAdata->fcChip.Registers.TYconfig.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONFIG;
+	cpqfcHBAdata->fcChip.Registers.TYcontrol.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONTROL;
+	cpqfcHBAdata->fcChip.Registers.TYstatus.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_STATUS;
+	cpqfcHBAdata->fcChip.Registers.rcv_al_pa.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_RCV_AL_PA;
+	cpqfcHBAdata->fcChip.Registers.ed_tov.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_ED_TOV;
+
+
+	cpqfcHBAdata->fcChip.Registers.INTEN.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTEN;
+	cpqfcHBAdata->fcChip.Registers.INTPEND.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTPEND;
+	cpqfcHBAdata->fcChip.Registers.INTSTAT.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTSTAT;
+
+	DEBUG_PCI(printk("  cpqfcHBAdata->fcChip.Registers. :\n"));
+	DEBUG_PCI(printk("    IOBaseL = %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseL));
+	DEBUG_PCI(printk("    IOBaseU = %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseU));
+
+	printk(" ioremap'd Membase: %p\n", cpqfcHBAdata->fcChip.Registers.ReMapMemBase);
+
+	DEBUG_PCI(printk("    SFQconsumerIndex.address = %p\n", cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address));
+	DEBUG_PCI(printk("    ERQproducerIndex.address = %p\n", cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address));
+	DEBUG_PCI(printk("    TYconfig.address = %p\n", cpqfcHBAdata->fcChip.Registers.TYconfig.address));
+	DEBUG_PCI(printk("    FMconfig.address = %p\n", cpqfcHBAdata->fcChip.Registers.FMconfig.address));
+	DEBUG_PCI(printk("    FMcontrol.address = %p\n", cpqfcHBAdata->fcChip.Registers.FMcontrol.address));
+
+	// set default options for FC controller (chip)
+	cpqfcHBAdata->fcChip.Options.initiator = 1;	// default: SCSI initiator
+	cpqfcHBAdata->fcChip.Options.target = 0;	// default: SCSI target
+	cpqfcHBAdata->fcChip.Options.extLoopback = 0;	// default: no loopback @GBIC
+	cpqfcHBAdata->fcChip.Options.intLoopback = 0;	// default: no loopback inside chip
+
+	// set highest and lowest FC-PH version the adapter/driver supports
+	// (NOT strict compliance)
+	cpqfcHBAdata->fcChip.highest_FCPH_ver = FC_PH3;
+	cpqfcHBAdata->fcChip.lowest_FCPH_ver = FC_PH43;
+
+	// set function points for this controller / adapter
+	cpqfcHBAdata->fcChip.ResetTachyon = CpqTsResetTachLite;
+	cpqfcHBAdata->fcChip.FreezeTachyon = CpqTsFreezeTachlite;
+	cpqfcHBAdata->fcChip.UnFreezeTachyon = CpqTsUnFreezeTachlite;
+	cpqfcHBAdata->fcChip.CreateTachyonQues = CpqTsCreateTachLiteQues;
+	cpqfcHBAdata->fcChip.DestroyTachyonQues = CpqTsDestroyTachLiteQues;
+	cpqfcHBAdata->fcChip.InitializeTachyon = CpqTsInitializeTachLite;
+	cpqfcHBAdata->fcChip.LaserControl = CpqTsLaserControl;
+	cpqfcHBAdata->fcChip.ProcessIMQEntry = CpqTsProcessIMQEntry;
+	cpqfcHBAdata->fcChip.InitializeFrameManager = CpqTsInitializeFrameManager;;
+	cpqfcHBAdata->fcChip.ReadWriteWWN = CpqTsReadWriteWWN;
+	cpqfcHBAdata->fcChip.ReadWriteNVRAM = CpqTsReadWriteNVRAM;
+
 
- 
 
 }
 
@@ -233,28 +169,27 @@
 /* (borrowed from linux/drivers/scsi/hosts.c) */
 static void launch_FCworker_thread(struct Scsi_Host *HostAdapter)
 {
-  DECLARE_MUTEX_LOCKED(sem);
+	DECLARE_MUTEX_LOCKED(sem);
+
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
+
+	ENTER("launch_FC_worker_thread");
 
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
+	cpqfcHBAdata->notify_wt = &sem;
 
-  ENTER("launch_FC_worker_thread");
-             
-  cpqfcHBAdata->notify_wt = &sem;
-
-  /* must unlock before kernel_thread(), for it may cause a reschedule. */
-  spin_unlock_irq(&io_request_lock);
-  kernel_thread((int (*)(void *))cpqfcTSWorkerThread, 
-                          (void *) HostAdapter, 0);
-  /*
-   * Now wait for the kernel error thread to initialize itself
-
-   */
-  down (&sem);
-  spin_lock_irq(&io_request_lock);
-  cpqfcHBAdata->notify_wt = NULL;
+	/* must unlock before kernel_thread(), for it may cause a reschedule. */
+	spin_unlock_irq(&io_request_lock);
+	kernel_thread((int (*)(void *)) cpqfcTSWorkerThread, (void *) HostAdapter, 0);
+	/*
+	 * Now wait for the kernel error thread to initialize itself
+
+	 */
+	down(&sem);
+	spin_lock_irq(&io_request_lock);
+	cpqfcHBAdata->notify_wt = NULL;
+
+	LEAVE("launch_FC_worker_thread");
 
-  LEAVE("launch_FC_worker_thread");
- 
 }
 
 
@@ -279,436 +214,396 @@
 };
 
 
-int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
+int cpqfcTS_detect(Scsi_Host_Template * ScsiHostTemplate)
 {
-  int NumberOfAdapters=0; // how many of our PCI adapters are found?
-  struct pci_dev *PciDev = NULL;
-  struct Scsi_Host *HostAdapter = NULL;
-  CPQFCHBA *cpqfcHBAdata = NULL; 
-  struct timer_list *cpqfcTStimer = NULL;
-  int i;
+	int NumberOfAdapters = 0;	// how many of our PCI adapters are found?
+	struct pci_dev *PciDev = NULL;
+	struct Scsi_Host *HostAdapter = NULL;
+	CPQFCHBA *cpqfcHBAdata = NULL;
+	struct timer_list *cpqfcTStimer = NULL;
+	int i;
 
-  ENTER("cpqfcTS_detect");
+	ENTER("cpqfcTS_detect");
 
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
-  ScsiHostTemplate->proc_dir = &proc_scsi_cpqfcTS;
+	ScsiHostTemplate->proc_dir = &proc_scsi_cpqfcTS;
 #else
-  ScsiHostTemplate->proc_name = "cpqfcTS";
+	ScsiHostTemplate->proc_name = "cpqfcTS";
 #endif
 
-  if( pci_present() == 0) // no PCI busses?
-  {
-    printk( "  no PCI bus?@#!\n");
-    return NumberOfAdapters;
-  }
-
-  for( i=0; i < HBA_TYPES; i++)
-  {
-    // look for all HBAs of each type
-
-    while((PciDev = pci_find_device(cpqfc_boards[i].vendor_id,
-				    cpqfc_boards[i].device_id, PciDev)))
-    {
-
-      if (pci_set_dma_mask(PciDev, CPQFCTS_DMA_MASK) != 0) {
-	printk(KERN_WARNING 
-		"cpqfc: HBA cannot support required DMA mask, skipping.\n");
-	continue;
-      }
-
-      // NOTE: (kernel 2.2.12-32) limits allocation to 128k bytes...
-      printk(" scsi_register allocating %d bytes for FC HBA\n",
-		      (ULONG)sizeof(CPQFCHBA));
-
-      HostAdapter = scsi_register( ScsiHostTemplate, sizeof( CPQFCHBA ) );
-      
-      if(HostAdapter == NULL)
-      	continue;
-      DEBUG_PCI( printk("  HBA found!\n"));
-      DEBUG_PCI( printk("  HostAdapter->PciDev->irq = %u\n", PciDev->irq) );
-      DEBUG_PCI(printk("  PciDev->baseaddress[0]= %lx\n", 
-				PciDev->resource[0].start));
-      DEBUG_PCI(printk("  PciDev->baseaddress[1]= %lx\n", 
-				PciDev->resource[1].start));
-      DEBUG_PCI(printk("  PciDev->baseaddress[2]= %lx\n", 
-				PciDev->resource[2].start));
-      DEBUG_PCI(printk("  PciDev->baseaddress[3]= %lx\n", 
-				PciDev->resource[3].start));
-
-      scsi_set_pci_device(HostAdapter, PciDev);      
-      HostAdapter->irq = PciDev->irq;  // copy for Scsi layers
-      
-      // HP Tachlite uses two (255-byte) ranges of Port I/O (lower & upper),
-      // for a total I/O port address space of 512 bytes.
-      // mask out the I/O port address (lower) & record
-      HostAdapter->io_port = (unsigned int)
-	     PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
-      HostAdapter->n_io_port = 0xff;
-      
-      // i.e., expect 128 targets (arbitrary number), while the
-      //  RA-4000 supports 32 LUNs
-      HostAdapter->max_id =  0;   // incremented as devices log in    
-      HostAdapter->max_lun = CPQFCTS_MAX_LUN;         // LUNs per FC device
-      HostAdapter->max_channel = CPQFCTS_MAX_CHANNEL; // multiple busses?
-      
-      // get the pointer to our HBA specific data... (one for
-      // each HBA on the PCI bus(ses)).
-      cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-      
-      // make certain our data struct is clear
-      memset( cpqfcHBAdata, 0, sizeof( CPQFCHBA ) );
-
-
-      // initialize our HBA info
-      cpqfcHBAdata->HBAnum = NumberOfAdapters;
-
-      cpqfcHBAdata->HostAdapter = HostAdapter; // back ptr
-      Cpqfc_initHBAdata( cpqfcHBAdata, PciDev ); // fill MOST fields
-     
-      cpqfcHBAdata->HBAnum = NumberOfAdapters;
-      cpqfcHBAdata->hba_spinlock = SPIN_LOCK_UNLOCKED;
-
-      // request necessary resources and check for conflicts
-      if( request_irq( HostAdapter->irq,
-		       cpqfcTS_intr_handler,
-	               SA_INTERRUPT | SA_SHIRQ,
-	               DEV_NAME,
-		       HostAdapter) )
-      {
-	printk(" IRQ %u already used\n", HostAdapter->irq);
-        scsi_unregister( HostAdapter);
-	continue;
-      }
-
-      // Since we have two 256-byte I/O port ranges (upper
-      // and lower), check them both
-      if( check_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff) )
-      {
-	printk("  cpqfcTS address in use: %x\n", 
-			cpqfcHBAdata->fcChip.Registers.IOBaseU);
-	free_irq( HostAdapter->irq, HostAdapter);
-        scsi_unregister( HostAdapter);
-	continue;
-      }	
-      
-      if( check_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff) )
-      {
-  	printk("  cpqfcTS address in use: %x\n", 
-	      			cpqfcHBAdata->fcChip.Registers.IOBaseL);
-	free_irq( HostAdapter->irq, HostAdapter);
-        scsi_unregister( HostAdapter);
-	continue;
-      }	
-      
-      // OK, we should be able to grab everything we need now.
-      request_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff, DEV_NAME);
-      request_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff, DEV_NAME);
-      DEBUG_PCI(printk("  Requesting 255 I/O addresses @ %x\n",
-        cpqfcHBAdata->fcChip.Registers.IOBaseL ));
-      DEBUG_PCI(printk("  Requesting 255 I/O addresses @ %x\n",
-        cpqfcHBAdata->fcChip.Registers.IOBaseU ));
-
-      
-      // start our kernel worker thread
-
-      launch_FCworker_thread(HostAdapter);
-
-
-      // start our TimerTask...
-
-      cpqfcTStimer = &cpqfcHBAdata->cpqfcTStimer;
-
-      init_timer( cpqfcTStimer); // Linux clears next/prev values
-      cpqfcTStimer->expires = jiffies + HZ; // one second
-      cpqfcTStimer->data = (unsigned long)cpqfcHBAdata; // this adapter
-      cpqfcTStimer->function = cpqfcTSheartbeat; // handles timeouts, housekeeping
-
-      add_timer( cpqfcTStimer);  // give it to Linux
-
-
-      // now initialize our hardware...
-      if (cpqfcHBAdata->fcChip.InitializeTachyon( cpqfcHBAdata, 1,1)) {
-	printk(KERN_WARNING "cpqfc: initialization of HBA hardware failed.\n");
-	// FIXME: might want to do something better than nothing here.
-      }
-
-      cpqfcHBAdata->fcStatsTime = jiffies;  // (for FC Statistics delta)
-      
-      // give our HBA time to initialize and login current devices...
-      {
-	// The Brocade switch (e.g. 2400, 2010, etc.) as of March 2000,
-	// has the following algorithm for FL_Port startup:
-	// Time(sec) Action
-	// 0:        Device Plugin and LIP(F7,F7) transmission
-	// 1.0       LIP incoming
-        // 1.027     LISA incoming, no CLS! (link not up)
-	// 1.028     NOS incoming (switch test for N_Port)
-        // 1.577     ED_TOV expired, transmit LIPs again	
-	// 3.0       LIP(F8,F7) incoming (switch passes Tach Prim.Sig)
-	// 3.028     LILP received, link up, FLOGI starts
-	// slowest(worst) case, measured on 1Gb Finisar GT analyzer
-	
-	unsigned long stop_time;
-
-        spin_unlock_irq(&io_request_lock);
-	stop_time = jiffies + 4*HZ;
-        while ( time_before(jiffies, stop_time) ) 
-	  	schedule();  // (our worker task needs to run)
+	if (pci_present() == 0)	// no PCI busses?
+	{
+		printk("  no PCI bus?@#!\n");
+		return NumberOfAdapters;
+	}
 
-	spin_lock_irq(&io_request_lock);
-      }
-      
-      NumberOfAdapters++; 
-    } // end of while()
-  }
-
-  LEAVE("cpqfcTS_detect");
- 
-  return NumberOfAdapters;
-}
-
-static void my_ioctl_done (Scsi_Cmnd * SCpnt)
-{
-    struct request * req;
-    
-    req = &SCpnt->request;
-    req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */
-  
-    if (req->CPQFC_WAITING != NULL)
-	CPQFC_COMPLETE(req->CPQFC_WAITING);
-}   
-
-
-
-int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg)
-{
-  int result = 0;
-  struct Scsi_Host *HostAdapter = ScsiDev->host;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  PFC_LOGGEDIN_PORT pLoggedInPort;
-  Scsi_Cmnd DumCmnd;
-  int i, j;
-  VENDOR_IOCTL_REQ ioc;
-  cpqfc_passthru_t *vendor_cmd;
-  Scsi_Device *SDpnt;
-  Scsi_Cmnd *ScsiPassThruCmnd;
-
-  ENTER("cpqfcTS_ioctl ");
-  
-  // can we find an FC device mapping to this SCSI target?
-  DumCmnd.channel = ScsiDev->channel;		// For searching
-  DumCmnd.target  = ScsiDev->id;
-  pLoggedInPort = fcFindLoggedInPort( fcChip,
-    &DumCmnd, // search Scsi Nexus
-    0,        // DON'T search linked list for FC port id
-    NULL,     // DON'T search linked list for FC WWN
-    NULL);    // DON'T care about end of list
- 
-  if( pLoggedInPort == NULL )      // not found!
-  {
-    result = -ENXIO;
-  }
- 
-  else  // we know what FC device to operate on...
-  {
-	// printk("ioctl CMND %d", Cmnd);
-    switch (Cmnd) 
-    {
-      // Passthrough provides a mechanism to bypass the RAID
-      // or other controller and talk directly to the devices
-      // (e.g. physical disk drive)
-      // Passthrough commands, unfortunately, tend to be vendor
-      // specific; this is tailored to COMPAQ's RAID (RA4x00)
-      case CPQFCTS_SCSI_PASSTHRU:
-      {
-	void *buf = NULL; // for kernel space buffer for user data
-	
-	if( !arg)
-	  return -EINVAL;
-
-	// must be super user to send stuff directly to the
-	// controller and/or physical drives...
-	if( !suser() )
-	  return -EPERM;
-
-	// copy the caller's struct to our space.
-        if( copy_from_user( &ioc, arg, sizeof( VENDOR_IOCTL_REQ)))
-		return( -EFAULT);
+	for (i = 0; i < HBA_TYPES; i++) {
+		// look for all HBAs of each type
 
-	vendor_cmd = ioc.argp;  // i.e., CPQ specific command struct
+		while ((PciDev = pci_find_device(cpqfc_boards[i].vendor_id, cpqfc_boards[i].device_id, PciDev))) {
 
-	// If necessary, grab a kernel/DMA buffer
-	if( vendor_cmd->len)
-	{
-  	  buf = kmalloc( vendor_cmd->len, GFP_KERNEL);
-	  if( !buf)
-	    return -ENOMEM;
-	}
-
-        // Now build a SCSI_CMND to pass down...
-	// This function allocates and sets Scsi_Cmnd ptrs such as
-	//  ->channel, ->target, ->host
-        ScsiPassThruCmnd = scsi_allocate_device(ScsiDev, 1, 1);
-
-        // Need data from user?
-	// make sure caller's buffer is in kernel space.
-	if( (vendor_cmd->rw_flag == VENDOR_WRITE_OPCODE) &&
-	    vendor_cmd->len)
-        if(  copy_from_user( buf, vendor_cmd->bufp, vendor_cmd->len))
-		return( -EFAULT);
-	    
-	// copy the CDB (if/when MAX_COMMAND_SIZE is 16, remove copy below)
-        memcpy( &ScsiPassThruCmnd->cmnd[0], 
-		&vendor_cmd->cdb[0], 
-		MAX_COMMAND_SIZE);  
-        // we want to copy all 16 bytes into the FCP-SCSI CDB,
-	// although the actual passthru only uses up to the
-	// first 12.
-	
-	ScsiPassThruCmnd->cmd_len = 16; // sizeof FCP-SCSI CDB
-
-	// Unfortunately, the SCSI command cmnd[] field has only
-	// 12 bytes.  Ideally the MAX_COMMAND_SIZE should be increased
-	// to 16 for newer Fibre Channel and SCSI-3 larger CDBs.
-	// However, to avoid a mandatory kernel rebuild, we use the SCp
-	// spare field to store the extra 4 bytes ( ugly :-(
+			if (pci_enable_device(PciDev) != 0) {
+				printk(KERN_WARNING "cpqfc: pci_enable_devive failed, skipping.\n");
+				continue;
+			}
+			if (pci_set_dma_mask(PciDev, CPQFCTS_DMA_MASK) != 0) {
+				printk(KERN_WARNING "cpqfc: HBA cannot support required DMA mask, skipping.\n");
+				continue;
+			}
+			// NOTE: (kernel 2.2.12-32) limits allocation to 128k bytes...
+			printk(" scsi_register allocating %d bytes for FC HBA\n", (u32) sizeof(CPQFCHBA));
+
+			HostAdapter = scsi_register(ScsiHostTemplate, sizeof(CPQFCHBA));
+
+			if (HostAdapter == NULL)
+				continue;
+			DEBUG_PCI(printk("  HBA found!\n"));
+			DEBUG_PCI(printk("  HostAdapter->PciDev->irq = %u\n", PciDev->irq));
+			DEBUG_PCI(printk("  PciDev->baseaddress[0]= %lx\n", PciDev->resource[0].start));
+			DEBUG_PCI(printk("  PciDev->baseaddress[1]= %lx\n", PciDev->resource[1].start));
+			DEBUG_PCI(printk("  PciDev->baseaddress[2]= %lx\n", PciDev->resource[2].start));
+			DEBUG_PCI(printk("  PciDev->baseaddress[3]= %lx\n", PciDev->resource[3].start));
+
+			scsi_set_pci_device(HostAdapter, PciDev);
+			HostAdapter->irq = PciDev->irq;	// copy for Scsi layers
+
+			// HP Tachlite uses two (255-byte) ranges of Port I/O (lower & upper),
+			// for a total I/O port address space of 512 bytes.
+			// mask out the I/O port address (lower) & record
+			HostAdapter->io_port = (unsigned int)
+			    PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
+			HostAdapter->n_io_port = 0xff;
+
+			// i.e., expect 128 targets (arbitrary number), while the
+			//  RA-4000 supports 32 LUNs
+			HostAdapter->max_id = 0;	// incremented as devices log in    
+			HostAdapter->max_lun = CPQFCTS_MAX_LUN;	// LUNs per FC device
+			HostAdapter->max_channel = CPQFCTS_MAX_CHANNEL;	// multiple busses?
+
+			// get the pointer to our HBA specific data... (one for
+			// each HBA on the PCI bus(ses)).
+			cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
+
+			// make certain our data struct is clear
+			memset(cpqfcHBAdata, 0, sizeof(CPQFCHBA));
+
+
+			// initialize our HBA info
+			cpqfcHBAdata->HBAnum = NumberOfAdapters;
+
+			cpqfcHBAdata->HostAdapter = HostAdapter;	// back ptr
+			Cpqfc_initHBAdata(cpqfcHBAdata, PciDev);	// fill MOST fields
+
+			cpqfcHBAdata->HBAnum = NumberOfAdapters;
+			cpqfcHBAdata->hba_spinlock = SPIN_LOCK_UNLOCKED;
+
+			// request necessary resources and check for conflicts
+			if (request_irq(HostAdapter->irq, cpqfcTS_intr_handler, SA_INTERRUPT | SA_SHIRQ, DEV_NAME, HostAdapter)) {
+				printk(" IRQ %u already used\n", HostAdapter->irq);
+				scsi_unregister(HostAdapter);
+				continue;
+			}
+			// Since we have two 256-byte I/O port ranges (upper
+			// and lower), check them both
+			if (check_region(cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff)) {
+				printk("  cpqfcTS address in use: %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseU);
+				free_irq(HostAdapter->irq, HostAdapter);
+				scsi_unregister(HostAdapter);
+				continue;
+			}
+
+			if (check_region(cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff)) {
+				printk("  cpqfcTS address in use: %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseL);
+				free_irq(HostAdapter->irq, HostAdapter);
+				scsi_unregister(HostAdapter);
+				continue;
+			}
+			// OK, we should be able to grab everything we need now.
+			request_region(cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff, DEV_NAME);
+			request_region(cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff, DEV_NAME);
+			DEBUG_PCI(printk("  Requesting 255 I/O addresses @ %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseL));
+			DEBUG_PCI(printk("  Requesting 255 I/O addresses @ %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseU));
+
+
+			// start our kernel worker thread
+
+			launch_FCworker_thread(HostAdapter);
+
+
+			// start our TimerTask...
+
+			cpqfcTStimer = &cpqfcHBAdata->cpqfcTStimer;
+
+			init_timer(cpqfcTStimer);	// Linux clears next/prev values
+			cpqfcTStimer->expires = jiffies + HZ;	// one second
+			cpqfcTStimer->data = (unsigned long) cpqfcHBAdata;	// this adapter
+			cpqfcTStimer->function = cpqfcTSheartbeat;	// handles timeouts, housekeeping
+
+			add_timer(cpqfcTStimer);	// give it to Linux
+
+
+			// now initialize our hardware...
+			if (cpqfcHBAdata->fcChip.InitializeTachyon(cpqfcHBAdata, 1, 1)) {
+				printk(KERN_WARNING "cpqfc: initialization of HBA hardware failed.\n");
+				// FIXME: might want to do something better than nothing here.
+			}
+
+			cpqfcHBAdata->fcStatsTime = jiffies;	// (for FC Statistics delta)
+
+			// give our HBA time to initialize and login current devices...
+			{
+				// The Brocade switch (e.g. 2400, 2010, etc.) as of March 2000,
+				// has the following algorithm for FL_Port startup:
+				// Time(sec) Action
+				// 0:        Device Plugin and LIP(F7,F7) transmission
+				// 1.0       LIP incoming
+				// 1.027     LISA incoming, no CLS! (link not up)
+				// 1.028     NOS incoming (switch test for N_Port)
+				// 1.577     ED_TOV expired, transmit LIPs again        
+				// 3.0       LIP(F8,F7) incoming (switch passes Tach Prim.Sig)
+				// 3.028     LILP received, link up, FLOGI starts
+				// slowest(worst) case, measured on 1Gb Finisar GT analyzer
+
+				unsigned long stop_time;
+
+				spin_unlock_irq(&io_request_lock);
+				stop_time = jiffies + 4 * HZ;
+				while (time_before(jiffies, stop_time))
+					schedule();	// (our worker task needs to run)
 
-	if( MAX_COMMAND_SIZE < 16)
+				spin_lock_irq(&io_request_lock);
+			}
+
+			NumberOfAdapters++;
+		}		// end of while()
+	}
+
+	LEAVE("cpqfcTS_detect");
+
+	return NumberOfAdapters;
+}
+
+static void my_ioctl_done(Scsi_Cmnd * SCpnt)
+{
+	struct request *req;
+
+	req = &SCpnt->request;
+	req->rq_status = RQ_SCSI_DONE;	/* Busy, but indicate request done */
+
+	if (req->CPQFC_WAITING != NULL)
+		CPQFC_COMPLETE(req->CPQFC_WAITING);
+}
+
+
+
+int cpqfcTS_ioctl(Scsi_Device * ScsiDev, int Cmnd, void *arg)
+{
+	int result = 0;
+	struct Scsi_Host *HostAdapter = ScsiDev->host;
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	PFC_LOGGEDIN_PORT pLoggedInPort;
+	Scsi_Cmnd DumCmnd;
+	int i, j;
+	VENDOR_IOCTL_REQ ioc;
+	cpqfc_passthru_t *vendor_cmd;
+	Scsi_Device *SDpnt;
+	Scsi_Cmnd *ScsiPassThruCmnd;
+
+	ENTER("cpqfcTS_ioctl ");
+
+	// can we find an FC device mapping to this SCSI target?
+	DumCmnd.channel = ScsiDev->channel;	// For searching
+	DumCmnd.target = ScsiDev->id;
+	DumCmnd.lun = ScsiDev->lun;
+	pLoggedInPort = fcFindLoggedInPort(fcChip, &DumCmnd,	// search Scsi Nexus
+					   0,	// DON'T search linked list for FC port id
+					   NULL,	// DON'T search linked list for FC WWN
+					   NULL);	// DON'T care about end of list
+
+	if (pLoggedInPort == NULL)	// not found!
 	{
-          memcpy( &ScsiPassThruCmnd->SCp.buffers_residual,
-		  &vendor_cmd->cdb[12], 4);
-	}	  
-                  
-	
-        ScsiPassThruCmnd->SCp.sent_command = 1; // PASSTHRU!
-	                                        // suppress LUN masking
-	                                        // and VSA logic
-
-	// Use spare fields to copy FCP-SCSI LUN address info...
-        ScsiPassThruCmnd->SCp.phase = vendor_cmd->bus;
-	ScsiPassThruCmnd->SCp.have_data_in = vendor_cmd->pdrive;
-
-        // We copy the scheme used by scsi.c to submit commands
-	// to our own HBA.  We do this in order to stall the
-	// thread calling the IOCTL until it completes, and use
-	// the same "_quecommand" function for synchronizing
-	// FC Link events with our "worker thread".
-
-        {
-          CPQFC_DECLARE_COMPLETION(wait);
-          ScsiPassThruCmnd->request.CPQFC_WAITING = &wait;
-          // eventually gets us to our own _quecommand routine
-          scsi_do_cmd( ScsiPassThruCmnd, &vendor_cmd->cdb[0], 
-	       buf, 
-	       vendor_cmd->len, 
-	       my_ioctl_done, 
-	       10*HZ, 1);// timeout,retries
-          // Other I/Os can now resume; we wait for our ioctl
-	  // command to complete
-	  CPQFC_WAIT_FOR_COMPLETION(&wait);
-          ScsiPassThruCmnd->request.CPQFC_WAITING = NULL;
-        }
-	
-        result = ScsiPassThruCmnd->result;
+		result = -ENXIO;
+	}
 
-        // copy any sense data back to caller
-        if( result != 0 )
+	else			// we know what FC device to operate on...
 	{
-	  memcpy( vendor_cmd->sense_data, // see struct def - size=40
-		  ScsiPassThruCmnd->sense_buffer, 
-		  sizeof(ScsiPassThruCmnd->sense_buffer)); 
-	}
-        SDpnt = ScsiPassThruCmnd->device;
-        scsi_release_command(ScsiPassThruCmnd); // "de-allocate"
-        ScsiPassThruCmnd = NULL;
-
-        // if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
-        //  (*SDpnt->scsi_request_fn)();
-
-        wake_up(&SDpnt->scpnt_wait);
-
-	// need to pass data back to user (space)?
-	if( (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) &&
-	     vendor_cmd->len )
-        if(  copy_to_user( vendor_cmd->bufp, buf, vendor_cmd->len))
-		return( -EFAULT);
-
-        if( buf) 
-	  kfree( buf);
-
-        return result;
-      }
-      
-      case CPQFCTS_GETPCIINFO:
-      {
-	cpqfc_pci_info_struct pciinfo;
-	
-	if( !arg)
-	  return -EINVAL;
-
-         	
-	
-        pciinfo.bus = cpqfcHBAdata->PciDev->bus->number;
-        pciinfo.dev_fn = cpqfcHBAdata->PciDev->devfn;  
-	pciinfo.board_id = cpqfcHBAdata->PciDev->device |
-			  (cpqfcHBAdata->PciDev->vendor <<16); 
-	      
-        if(copy_to_user( arg, &pciinfo, sizeof(cpqfc_pci_info_struct)))
-		return( -EFAULT);
-        return 0;
-      }
-
-      case CPQFCTS_GETDRIVVER:
-      {
-	DriverVer_type DriverVer = 
-		CPQFCTS_DRIVER_VER( VER_MAJOR,VER_MINOR,VER_SUBMINOR);
-	
-	if( !arg)
-	  return -EINVAL;
-
-        if(copy_to_user( arg, &DriverVer, sizeof(DriverVer)))
-		return( -EFAULT);
-        return 0;
-      }
-
-
-
-      case CPQFC_IOCTL_FC_TARGET_ADDRESS:
-      result = 
-        verify_area(VERIFY_WRITE, arg, sizeof(Scsi_FCTargAddress));
-      if (result) 
-	break;
- 
-      put_user(pLoggedInPort->port_id,
-		&((Scsi_FCTargAddress *) arg)->host_port_id);
- 
-      for( i=3,j=0; i>=0; i--)   	// copy the LOGIN port's WWN
-        put_user(pLoggedInPort->u.ucWWN[i], 
-		&((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
-      for( i=7; i>3; i--)		// copy the LOGIN port's WWN
-        put_user(pLoggedInPort->u.ucWWN[i], 
-		&((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
-        break;
-
-
-      case CPQFC_IOCTL_FC_TDR:
-          
-        result = cpqfcTS_TargetDeviceReset( ScsiDev, 0);
-
-        break;
-
-
-
-
-    default:
-      result = -EINVAL;
-      break;
-    }
-  }
+		// printk("ioctl CMND %d", Cmnd);
+		switch (Cmnd) {
+			// Passthrough provides a mechanism to bypass the RAID
+			// or other controller and talk directly to the devices
+			// (e.g. physical disk drive)
+			// Passthrough commands, unfortunately, tend to be vendor
+			// specific; this is tailored to COMPAQ's RAID (RA4x00)
+		case CPQFCTS_SCSI_PASSTHRU:
+			{
+				void *buf = NULL;	// for kernel space buffer for user data
+
+				if (!arg)
+					return -EINVAL;
+
+				// must be super user to send stuff directly to the
+				// controller and/or physical drives...
+				if (!suser())
+					return -EPERM;
+
+				// copy the caller's struct to our space.
+				if (copy_from_user(&ioc, arg, sizeof(VENDOR_IOCTL_REQ)))
+					return (-EFAULT);
+
+				vendor_cmd = ioc.argp;	// i.e., CPQ specific command struct
+
+				// If necessary, grab a kernel/DMA buffer
+				if (vendor_cmd->len) {
+					buf = kmalloc(vendor_cmd->len, GFP_KERNEL);
+					if (!buf)
+						return -ENOMEM;
+				}
+				// Now build a SCSI_CMND to pass down...
+				// This function allocates and sets Scsi_Cmnd ptrs such as
+				//  ->channel, ->target, ->host
+				ScsiPassThruCmnd = scsi_allocate_device(ScsiDev, 1, 1);
+
+				// Need data from user?
+				// make sure caller's buffer is in kernel space.
+				if ((vendor_cmd->rw_flag == VENDOR_WRITE_OPCODE) && vendor_cmd->len)
+					if (copy_from_user(buf, vendor_cmd->bufp, vendor_cmd->len))
+						return (-EFAULT);
+
+				// copy the CDB (if/when MAX_COMMAND_SIZE is 16, remove copy below)
+				memcpy(&ScsiPassThruCmnd->cmnd[0], &vendor_cmd->cdb[0], MAX_COMMAND_SIZE);
+				// we want to copy all 16 bytes into the FCP-SCSI CDB,
+				// although the actual passthru only uses up to the
+				// first 12.
+
+				ScsiPassThruCmnd->cmd_len = 16;	// sizeof FCP-SCSI CDB
+
+				// Unfortunately, the SCSI command cmnd[] field has only
+				// 12 bytes.  Ideally the MAX_COMMAND_SIZE should be increased
+				// to 16 for newer Fibre Channel and SCSI-3 larger CDBs.
+				// However, to avoid a mandatory kernel rebuild, we use the SCp
+				// spare field to store the extra 4 bytes ( ugly :-(
+
+				if (MAX_COMMAND_SIZE < 16) {
+					memcpy(&ScsiPassThruCmnd->SCp.buffers_residual, &vendor_cmd->cdb[12], 4);
+				}
+
+
+				ScsiPassThruCmnd->SCp.sent_command = 1;	// PASSTHRU!
+				// suppress LUN masking
+				// and VSA logic
+
+				// Use spare fields to copy FCP-SCSI LUN address info...
+				ScsiPassThruCmnd->SCp.phase = vendor_cmd->bus;
+				ScsiPassThruCmnd->SCp.have_data_in = vendor_cmd->pdrive;
+
+				// We copy the scheme used by scsi.c to submit commands
+				// to our own HBA.  We do this in order to stall the
+				// thread calling the IOCTL until it completes, and use
+				// the same "_quecommand" function for synchronizing
+				// FC Link events with our "worker thread".
+
+				{
+					CPQFC_DECLARE_COMPLETION(wait);
+					ScsiPassThruCmnd->request.CPQFC_WAITING = &wait;
+					// eventually gets us to our own _quecommand routine
+					scsi_do_cmd(ScsiPassThruCmnd, &vendor_cmd->cdb[0], buf, vendor_cmd->len, my_ioctl_done, 10 * HZ, 1);	// timeout,retries
+					// Other I/Os can now resume; we wait for our ioctl
+					// command to complete
+					CPQFC_WAIT_FOR_COMPLETION(&wait);
+					ScsiPassThruCmnd->request.CPQFC_WAITING = NULL;
+				}
+
+				result = ScsiPassThruCmnd->result;
+
+				// copy any sense data back to caller
+				if (result != 0) {
+					memcpy(vendor_cmd->sense_data,	// see struct def - size=40
+					       ScsiPassThruCmnd->sense_buffer, sizeof(ScsiPassThruCmnd->sense_buffer));
+				}
+				SDpnt = ScsiPassThruCmnd->device;
+				scsi_release_command(ScsiPassThruCmnd);	// "de-allocate"
+				ScsiPassThruCmnd = NULL;
+
+				// if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
+				//  (*SDpnt->scsi_request_fn)();
 
-  LEAVE("cpqfcTS_ioctl");
-  return result;
+				wake_up(&SDpnt->scpnt_wait);
+
+				// need to pass data back to user (space)?
+				if ((vendor_cmd->rw_flag == VENDOR_READ_OPCODE) && vendor_cmd->len)
+					if (copy_to_user(vendor_cmd->bufp, buf, vendor_cmd->len))
+						return (-EFAULT);
+
+				if (buf)
+					kfree(buf);
+
+				return result;
+			}
+
+		case CPQFCTS_GETPCIINFO:
+			{
+				cpqfc_pci_info_struct pciinfo;
+
+				if (!arg)
+					return -EINVAL;
+
+
+
+				pciinfo.bus = cpqfcHBAdata->PciDev->bus->number;
+				pciinfo.dev_fn = cpqfcHBAdata->PciDev->devfn;
+				pciinfo.board_id = cpqfcHBAdata->PciDev->device | (cpqfcHBAdata->PciDev->vendor << 16);
+
+				if (copy_to_user(arg, &pciinfo, sizeof(cpqfc_pci_info_struct)))
+					return (-EFAULT);
+				return 0;
+			}
+
+		case CPQFCTS_GETDRIVVER:
+			{
+				DriverVer_type DriverVer = CPQFCTS_DRIVER_VER(VER_MAJOR, VER_MINOR, VER_SUBMINOR);
+
+				if (!arg)
+					return -EINVAL;
+
+				if (copy_to_user(arg, &DriverVer, sizeof(DriverVer)))
+					return (-EFAULT);
+				return 0;
+			}
+
+
+
+		case CPQFC_IOCTL_FC_TARGET_ADDRESS:
+			result = verify_area(VERIFY_WRITE, arg, sizeof(Scsi_FCTargAddress));
+			if (result)
+				break;
+
+			put_user(pLoggedInPort->port_id, &((Scsi_FCTargAddress *) arg)->host_port_id);
+
+			for (i = 3, j = 0; i >= 0; i--)	// copy the LOGIN port's WWN
+				put_user(pLoggedInPort->u.ucWWN[i], &((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
+			for (i = 7; i > 3; i--)	// copy the LOGIN port's WWN
+				put_user(pLoggedInPort->u.ucWWN[i], &((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
+			break;
+
+
+		case CPQFC_IOCTL_FC_TDR:
+
+			result = cpqfcTS_TargetDeviceReset(ScsiDev, 0);
+
+			break;
+
+
+
+
+		default:
+			result = -EINVAL;
+			break;
+		}
+	}
+
+	LEAVE("cpqfcTS_ioctl");
+	return result;
 }
 
 
@@ -718,84 +613,73 @@
 
 int cpqfcTS_release(struct Scsi_Host *HostAdapter)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; 
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
 
 
-  ENTER("cpqfcTS_release");
-	
-  DEBUG_PCI( printk(" cpqfcTS: delete timer...\n"));
-  del_timer( &cpqfcHBAdata->cpqfcTStimer);  
-    
-  // disable the hardware...
-  DEBUG_PCI( printk(" disable hardware, destroy queues, free mem\n"));
-  cpqfcHBAdata->fcChip.ResetTachyon( cpqfcHBAdata, CLEAR_FCPORTS);
-
-  // kill kernel thread
-  if( cpqfcHBAdata->worker_thread ) // (only if exists)
-  {
-    DECLARE_MUTEX_LOCKED(sem);  // synchronize thread kill
-
-    cpqfcHBAdata->notify_wt = &sem;
-    DEBUG_PCI( printk(" killing kernel thread\n"));
-    send_sig( SIGKILL, cpqfcHBAdata->worker_thread, 1);
-    down( &sem);
-    cpqfcHBAdata->notify_wt = NULL;
-    
-  }
-
-  // free Linux resources
-  DEBUG_PCI( printk(" cpqfcTS: freeing resources...\n"));
-  free_irq( HostAdapter->irq, HostAdapter);
-  scsi_unregister( HostAdapter);
-  release_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff);
-  release_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff);
- /* we get "vfree: bad address" executing this - need to investigate... 
-  if( (void*)((unsigned long)cpqfcHBAdata->fcChip.Registers.MemBase) !=
-      cpqfcHBAdata->fcChip.Registers.ReMapMemBase)
-    vfree( cpqfcHBAdata->fcChip.Registers.ReMapMemBase);
-*/
+	ENTER("cpqfcTS_release");
+
+	DEBUG_PCI(printk(" cpqfcTS: delete timer...\n"));
+	del_timer(&cpqfcHBAdata->cpqfcTStimer);
 
-  LEAVE("cpqfcTS_release");
-  return 0;
+	// disable the hardware...
+	DEBUG_PCI(printk(" disable hardware, destroy queues, free mem\n"));
+	cpqfcHBAdata->fcChip.ResetTachyon(cpqfcHBAdata, CLEAR_FCPORTS);
+
+	// kill kernel thread
+	if (cpqfcHBAdata->worker_thread)	// (only if exists)
+	{
+		DECLARE_MUTEX_LOCKED(sem);	// synchronize thread kill
+
+		cpqfcHBAdata->notify_wt = &sem;
+		DEBUG_PCI(printk(" killing kernel thread\n"));
+		send_sig(SIGKILL, cpqfcHBAdata->worker_thread, 1);
+		down(&sem);
+		cpqfcHBAdata->notify_wt = NULL;
+
+	}
+	// free Linux resources
+	DEBUG_PCI(printk(" cpqfcTS: freeing resources...\n"));
+	free_irq(HostAdapter->irq, HostAdapter);
+	scsi_unregister(HostAdapter);
+	release_region(cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff);
+	release_region(cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff);
+	/* we get "vfree: bad address" executing this - need to investigate... 
+	   if( (void*)((unsigned long)cpqfcHBAdata->fcChip.Registers.MemBase) !=
+	   cpqfcHBAdata->fcChip.Registers.ReMapMemBase)
+	   vfree( cpqfcHBAdata->fcChip.Registers.ReMapMemBase);
+	 */
+
+	LEAVE("cpqfcTS_release");
+	return 0;
 }
 
 
-const char * cpqfcTS_info(struct Scsi_Host *HostAdapter)
+const char *cpqfcTS_info(struct Scsi_Host *HostAdapter)
 {
-  static char buf[300];
-  CPQFCHBA *cpqfcHBA;
-  int BusSpeed, BusWidth;
-  
-  // get the pointer to our Scsi layer HBA buffer  
-  cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata;
-
-  BusWidth = (cpqfcHBA->fcChip.Registers.PCIMCTR &0x4) > 0 ?
-               64 : 32;
-
-  if( cpqfcHBA->fcChip.Registers.TYconfig.value & 0x80000000)
-    BusSpeed = 66;
-  else
-    BusSpeed = 33;
-
-  sprintf(buf, 
-"%s: WWN %08X%08X\n on PCI bus %d device 0x%02x irq %d IObaseL 0x%x, MEMBASE 0x%x\nPCI bus width %d bits, bus speed %d MHz\nFCP-SCSI Driver v%d.%d.%d",
-      cpqfcHBA->fcChip.Name, 
-      cpqfcHBA->fcChip.Registers.wwn_hi,
-      cpqfcHBA->fcChip.Registers.wwn_lo,
-      cpqfcHBA->PciDev->bus->number,
-      cpqfcHBA->PciDev->device,  
-      HostAdapter->irq,
-      cpqfcHBA->fcChip.Registers.IOBaseL,
-      cpqfcHBA->fcChip.Registers.MemBase,
-      BusWidth,
-      BusSpeed,
-      VER_MAJOR, VER_MINOR, VER_SUBMINOR
-);
-
-  
-  cpqfcTSDecodeGBICtype( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
-  cpqfcTSGetLPSM( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
-  return buf;
+	static char buf[300];
+	CPQFCHBA *cpqfcHBA;
+	int BusSpeed, BusWidth;
+
+	// get the pointer to our Scsi layer HBA buffer  
+	cpqfcHBA = (CPQFCHBA *) HostAdapter->hostdata;
+
+	BusWidth = (cpqfcHBA->fcChip.Registers.PCIMCTR & 0x4) > 0 ? 64 : 32;
+
+	if (cpqfcHBA->fcChip.Registers.TYconfig.value & 0x80000000)
+		BusSpeed = 66;
+	else
+		BusSpeed = 33;
+
+	sprintf(buf,
+		"%s: WWN %08X%08X\n on PCI bus %d device 0x%02x irq %d IObaseL 0x%x, MEMBASE 0x%x\nPCI bus width %d bits, bus speed %d MHz\nFCP-SCSI Driver v%d.%d.%d",
+		cpqfcHBA->fcChip.Name,
+		cpqfcHBA->fcChip.Registers.wwn_hi,
+		cpqfcHBA->fcChip.Registers.wwn_lo, cpqfcHBA->PciDev->bus->number, cpqfcHBA->PciDev->device, HostAdapter->irq, cpqfcHBA->fcChip.Registers.IOBaseL, cpqfcHBA->fcChip.Registers.MemBase, BusWidth, BusSpeed, VER_MAJOR, VER_MINOR, VER_SUBMINOR);
+
+
+	cpqfcTSDecodeGBICtype(&cpqfcHBA->fcChip, &buf[strlen(buf)]);
+	cpqfcTSGetLPSM(&cpqfcHBA->fcChip, &buf[strlen(buf)]);
+	return buf;
 }
 
 //
@@ -806,178 +690,167 @@
 // programming to use it to make programming a little simpler. This piece
 // of coding is borrowed from ncr53c8xx.c with some modifications 
 //
-struct info_str
-{
-        char *buffer;			// Pointer to output buffer
-        int buflength;			// It's length
-        int bufoffset;			// File offset corresponding with buf[0]
-	int buffillen;			// Current filled length 
-        int filpos;			// Current file offset
+struct info_str {
+	char *buffer;		// Pointer to output buffer
+	int buflength;		// It's length
+	int bufoffset;		// File offset corresponding with buf[0]
+	int buffillen;		// Current filled length 
+	int filpos;		// Current file offset
 };
 
 static void copy_mem_info(struct info_str *info, char *data, int datalen)
 {
 
-  if (info->filpos < info->bufoffset) {	// Current offset before buffer offset
-    if (info->filpos + datalen <= info->bufoffset) {
-      info->filpos += datalen; 		// Discard if completely before buffer
-      return;
-    } else {				// Partial copy, set to begin
-      data += (info->bufoffset - info->filpos);
-      datalen  -= (info->bufoffset - info->filpos);
-      info->filpos = info->bufoffset;
-    }
-  }
-
-  info->filpos += datalen;		// Update current offset
+	if (info->filpos < info->bufoffset) {	// Current offset before buffer offset
+		if (info->filpos + datalen <= info->bufoffset) {
+			info->filpos += datalen;	// Discard if completely before buffer
+			return;
+		} else {	// Partial copy, set to begin
+			data += (info->bufoffset - info->filpos);
+			datalen -= (info->bufoffset - info->filpos);
+			info->filpos = info->bufoffset;
+		}
+	}
+
+	info->filpos += datalen;	// Update current offset
 
-  if (info->buffillen == info->buflength) // Buffer full, discard
-    return;
+	if (info->buffillen == info->buflength)	// Buffer full, discard
+		return;
 
-  if (info->buflength - info->buffillen < datalen)  // Overflows buffer ?
-    datalen = info->buflength - info->buffillen;
+	if (info->buflength - info->buffillen < datalen)	// Overflows buffer ?
+		datalen = info->buflength - info->buffillen;
 
-  memcpy(info->buffer + info->buffillen, data, datalen);
-  info->buffillen += datalen;
+	memcpy(info->buffer + info->buffillen, data, datalen);
+	info->buffillen += datalen;
 }
 
 static int copy_info(struct info_str *info, char *fmt, ...)
 {
-        va_list args;
-        char buf[400];
-        int len;
-
-        va_start(args, fmt);
-        len = vsprintf(buf, fmt, args);
-        va_end(args);
+	va_list args;
+	char buf[400];
+	int len;
+
+	va_start(args, fmt);
+	len = vsprintf(buf, fmt, args);
+	va_end(args);
 
-        copy_mem_info(info, buf, len);
-        return len;
+	copy_mem_info(info, buf, len);
+	return len;
 }
 
 
 // Routine to get data for /proc RAM filesystem
 //
-int cpqfcTS_proc_info (char *buffer, char **start, off_t offset, int length, 
-		       int hostno, int inout)
+int cpqfcTS_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
 {
-  struct Scsi_Host *host;
-  Scsi_Cmnd DumCmnd;
-  int Chan, Targ, i;
-  struct info_str info;
-  CPQFCHBA *cpqfcHBA;
-  PTACHYON fcChip;
-  PFC_LOGGEDIN_PORT pLoggedInPort;
-  char buf[81];
-
-  // Search the Scsi host list for our controller
-  for (host=scsi_hostlist; host; host=host->next)
-    if (host->host_no == hostno)
-      break;
-
-  if (!host) return -ESRCH;
-
-  if (inout) return -EINVAL;
-
-  // get the pointer to our Scsi layer HBA buffer  
-  cpqfcHBA = (CPQFCHBA *)host->hostdata;
-  fcChip = &cpqfcHBA->fcChip;
-  
-  *start 	  = buffer;
-
-  info.buffer     = buffer;
-  info.buflength  = length;
-  info.bufoffset  = offset;
-  info.filpos     = 0;
-  info.buffillen  = 0;
-  copy_info(&info, "Driver version = %d.%d.%d", VER_MAJOR, VER_MINOR, VER_SUBMINOR); 
-  cpqfcTSDecodeGBICtype( &cpqfcHBA->fcChip, &buf[0]);
-  cpqfcTSGetLPSM( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
-  copy_info(&info, "%s\n", buf); 
+	struct Scsi_Host *host;
+	Scsi_Cmnd DumCmnd;
+	int Chan, Targ, i;
+	struct info_str info;
+	CPQFCHBA *cpqfcHBA;
+	PTACHYON fcChip;
+	PFC_LOGGEDIN_PORT pLoggedInPort;
+	char buf[81];
+
+	// Search the Scsi host list for our controller
+	for (host = scsi_hostlist; host; host = host->next)
+		if (host->host_no == hostno)
+			break;
+
+	if (!host)
+		return -ESRCH;
+
+	if (inout)
+		return -EINVAL;
+
+	// get the pointer to our Scsi layer HBA buffer  
+	cpqfcHBA = (CPQFCHBA *) host->hostdata;
+	fcChip = &cpqfcHBA->fcChip;
+
+	*start = buffer;
+
+	info.buffer = buffer;
+	info.buflength = length;
+	info.bufoffset = offset;
+	info.filpos = 0;
+	info.buffillen = 0;
+	copy_info(&info, "Driver version = %d.%d.%d", VER_MAJOR, VER_MINOR, VER_SUBMINOR);
+	cpqfcTSDecodeGBICtype(&cpqfcHBA->fcChip, &buf[0]);
+	cpqfcTSGetLPSM(&cpqfcHBA->fcChip, &buf[strlen(buf)]);
+	copy_info(&info, "%s\n", buf);
 
 #define DISPLAY_WWN_INFO
 #ifdef DISPLAY_WWN_INFO
-  copy_info(&info, "WWN database: (\"port_id: 000000\" means disconnected)\n");
-  for ( Chan=0; Chan <= host->max_channel; Chan++) {
-    DumCmnd.channel = Chan;
-    for (Targ=0; Targ <= host->max_id; Targ++) {
-      DumCmnd.target = Targ;
-      if ((pLoggedInPort = fcFindLoggedInPort( fcChip,
-	    			&DumCmnd, // search Scsi Nexus
-    				0,        // DON'T search list for FC port id
-    				NULL,     // DON'T search list for FC WWN
-    				NULL))){   // DON'T care about end of list
-	copy_info(&info, "Host: scsi%d Channel: %02d TargetId: %02d -> WWN: ",
-			   hostno, Chan, Targ);
-        for( i=3; i>=0; i--)        // copy the LOGIN port's WWN
-          copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
-        for( i=7; i>3; i--)             // copy the LOGIN port's WWN
-          copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
-	copy_info(&info, " port_id: %06X\n", pLoggedInPort->port_id); 
-      }
-    }
-  }
+	copy_info(&info, "WWN database: (\"port_id: 000000\" means disconnected)\n");
+	for (Chan = 0; Chan <= host->max_channel; Chan++) {
+		DumCmnd.channel = Chan;
+		for (Targ = 0; Targ <= host->max_id; Targ++) {
+			DumCmnd.target = Targ;
+			if ((pLoggedInPort = fcFindLoggedInPort(fcChip, &DumCmnd,	// search Scsi Nexus
+								0,	// DON'T search list for FC port id
+								NULL,	// DON'T search list for FC WWN
+								NULL))) {	// DON'T care about end of list
+				copy_info(&info, "Host: scsi%d Channel: %02d TargetId: %02d -> WWN: ", hostno, Chan, Targ);
+				for (i = 3; i >= 0; i--)	// copy the LOGIN port's WWN
+					copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
+				for (i = 7; i > 3; i--)	// copy the LOGIN port's WWN
+					copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
+				copy_info(&info, " port_id: %06X\n", pLoggedInPort->port_id);
+			}
+		}
+	}
 #endif
 
 
 
-  
-  
+
+
 // Unfortunately, the proc_info buffer isn't big enough
 // for everything we would like...
 // For FC stats, compile this and turn off WWN stuff above  
 //#define DISPLAY_FC_STATS
 #ifdef DISPLAY_FC_STATS
 // get the Fibre Channel statistics
-  {
-    int DeltaSecs = (jiffies - cpqfcHBA->fcStatsTime) / HZ;
-    int days,hours,minutes,secs;
-    
-    days = DeltaSecs / (3600*24); // days
-    hours = (DeltaSecs% (3600*24)) / 3600; // hours
-    minutes = (DeltaSecs%3600 /60); // minutes
-    secs =  DeltaSecs%60;  // secs
-copy_info( &info, "Fibre Channel Stats (time dd:hh:mm:ss %02u:%02u:%02u:%02u\n",
-      days, hours, minutes, secs);
-  }
-    
-  cpqfcHBA->fcStatsTime = jiffies;  // (for next delta)
-
-  copy_info( &info, "  LinkUp           %9u     LinkDown      %u\n",
-        fcChip->fcStats.linkUp, fcChip->fcStats.linkDown);
-        
-  copy_info( &info, "  Loss of Signal   %9u     Loss of Sync  %u\n",
-    fcChip->fcStats.LossofSignal, fcChip->fcStats.LossofSync);
-		  
-  copy_info( &info, "  Discarded Frames %9u     Bad CRC Frame %u\n",
-    fcChip->fcStats.Dis_Frm, fcChip->fcStats.Bad_CRC);
-
-  copy_info( &info, "  TACH LinkFailTX  %9u     TACH LinkFailRX     %u\n",
-    fcChip->fcStats.linkFailTX, fcChip->fcStats.linkFailRX);
-  
-  copy_info( &info, "  TACH RxEOFa      %9u     TACH Elastic Store  %u\n",
-    fcChip->fcStats.Rx_EOFa, fcChip->fcStats.e_stores);
-
-  copy_info( &info, "  BufferCreditWait %9uus   TACH FM Inits %u\n",
-    fcChip->fcStats.BB0_Timer*10, fcChip->fcStats.FMinits );
-	
-  copy_info( &info, "  FC-2 Timeouts    %9u     FC-2 Logouts  %u\n",
-    fcChip->fcStats.timeouts, fcChip->fcStats.logouts); 
-        
-  copy_info( &info, "  FC-2 Aborts      %9u     FC-4 Aborts   %u\n",
-    fcChip->fcStats.FC2aborted, fcChip->fcStats.FC4aborted);
-   
-  // clear the counters
-  cpqfcTSClearLinkStatusCounters( fcChip);
+	{
+		int DeltaSecs = (jiffies - cpqfcHBA->fcStatsTime) / HZ;
+		int days, hours, minutes, secs;
+
+		days = DeltaSecs / (3600 * 24);	// days
+		hours = (DeltaSecs % (3600 * 24)) / 3600;	// hours
+		minutes = (DeltaSecs % 3600 / 60);	// minutes
+		secs = DeltaSecs % 60;	// secs
+		copy_info(&info, "Fibre Channel Stats (time dd:hh:mm:ss %02u:%02u:%02u:%02u\n", days, hours, minutes, secs);
+	}
+
+	cpqfcHBA->fcStatsTime = jiffies;	// (for next delta)
+
+	copy_info(&info, "  LinkUp           %9u     LinkDown      %u\n", fcChip->fcStats.linkUp, fcChip->fcStats.linkDown);
+
+	copy_info(&info, "  Loss of Signal   %9u     Loss of Sync  %u\n", fcChip->fcStats.LossofSignal, fcChip->fcStats.LossofSync);
+
+	copy_info(&info, "  Discarded Frames %9u     Bad CRC Frame %u\n", fcChip->fcStats.Dis_Frm, fcChip->fcStats.Bad_CRC);
+
+	copy_info(&info, "  TACH LinkFailTX  %9u     TACH LinkFailRX     %u\n", fcChip->fcStats.linkFailTX, fcChip->fcStats.linkFailRX);
+
+	copy_info(&info, "  TACH RxEOFa      %9u     TACH Elastic Store  %u\n", fcChip->fcStats.Rx_EOFa, fcChip->fcStats.e_stores);
+
+	copy_info(&info, "  BufferCreditWait %9uus   TACH FM Inits %u\n", fcChip->fcStats.BB0_Timer * 10, fcChip->fcStats.FMinits);
+
+	copy_info(&info, "  FC-2 Timeouts    %9u     FC-2 Logouts  %u\n", fcChip->fcStats.timeouts, fcChip->fcStats.logouts);
+
+	copy_info(&info, "  FC-2 Aborts      %9u     FC-4 Aborts   %u\n", fcChip->fcStats.FC2aborted, fcChip->fcStats.FC4aborted);
+
+	// clear the counters
+	cpqfcTSClearLinkStatusCounters(fcChip);
 #endif
-	
-  return info.buffillen;
+
+	return info.buffillen;
 }
 
 
 #if DEBUG_CMND
 
-UCHAR *ScsiToAscii( UCHAR ScsiCommand)
+u8 *ScsiToAscii(u8 ScsiCommand)
 {
 
 /*++
@@ -1000,152 +873,148 @@
 --*/
 
 
-   switch (ScsiCommand)
-   {
-      case 0x00:
-         return( "Test Unit Ready" );
+	switch (ScsiCommand) {
+	case 0x00:
+		return ("Test Unit Ready");
 
-      case 0x01:
-         return( "Rezero Unit or Rewind" );
+	case 0x01:
+		return ("Rezero Unit or Rewind");
 
-      case 0x02:
-         return( "Request Block Address" );
+	case 0x02:
+		return ("Request Block Address");
 
-      case 0x03:
-         return( "Requese Sense" );
+	case 0x03:
+		return ("Requese Sense");
 
-      case 0x04:
-         return( "Format Unit" );
+	case 0x04:
+		return ("Format Unit");
 
-      case 0x05:
-         return( "Read Block Limits" );
+	case 0x05:
+		return ("Read Block Limits");
 
-      case 0x07:
-         return( "Reassign Blocks" );
+	case 0x07:
+		return ("Reassign Blocks");
 
-      case 0x08:
-         return( "Read (6)" );
+	case 0x08:
+		return ("Read (6)");
 
-      case 0x0a:
-         return( "Write (6)" );
+	case 0x0a:
+		return ("Write (6)");
 
-      case 0x0b:
-         return( "Seek (6)" );
+	case 0x0b:
+		return ("Seek (6)");
 
-      case 0x12:
-         return( "Inquiry" );
+	case 0x12:
+		return ("Inquiry");
 
-      case 0x15:
-         return( "Mode Select (6)" );
+	case 0x15:
+		return ("Mode Select (6)");
 
-      case 0x16:
-         return( "Reserve" );
+	case 0x16:
+		return ("Reserve");
 
-      case 0x17:
-         return( "Release" );
+	case 0x17:
+		return ("Release");
 
-      case 0x1a:
-         return( "ModeSen(6)" );
+	case 0x1a:
+		return ("ModeSen(6)");
 
-      case 0x1b:
-         return( "Start/Stop Unit" );
+	case 0x1b:
+		return ("Start/Stop Unit");
 
-      case 0x1c:
-         return( "Receive Diagnostic Results" );
+	case 0x1c:
+		return ("Receive Diagnostic Results");
 
-      case 0x1d:
-         return( "Send Diagnostic" );
+	case 0x1d:
+		return ("Send Diagnostic");
 
-      case 0x25:
-         return( "Read Capacity" );
+	case 0x25:
+		return ("Read Capacity");
 
-      case 0x28:
-         return( "Read (10)" );
+	case 0x28:
+		return ("Read (10)");
 
-      case 0x2a:
-         return( "Write (10)" );
+	case 0x2a:
+		return ("Write (10)");
 
-      case 0x2b:
-         return( "Seek (10)" );
+	case 0x2b:
+		return ("Seek (10)");
 
-      case 0x2e:
-         return( "Write and Verify" );
+	case 0x2e:
+		return ("Write and Verify");
 
-      case 0x2f:
-         return( "Verify" );
+	case 0x2f:
+		return ("Verify");
 
-      case 0x34:
-         return( "Pre-Fetch" );
+	case 0x34:
+		return ("Pre-Fetch");
 
-      case 0x35:
-         return( "Synchronize Cache" );
+	case 0x35:
+		return ("Synchronize Cache");
 
-      case 0x37:
-         return( "Read Defect Data (10)" );
+	case 0x37:
+		return ("Read Defect Data (10)");
 
-      case 0x3b:
-         return( "Write Buffer" );
+	case 0x3b:
+		return ("Write Buffer");
 
-      case 0x3c:
-         return( "Read Buffer" );
+	case 0x3c:
+		return ("Read Buffer");
 
-      case 0x3e:
-         return( "Read Long" );
+	case 0x3e:
+		return ("Read Long");
 
-      case 0x3f:
-         return( "Write Long" );
+	case 0x3f:
+		return ("Write Long");
 
-      case 0x41:
-         return( "Write Same" );
+	case 0x41:
+		return ("Write Same");
 
-      case 0x4c:
-         return( "Log Select" );
+	case 0x4c:
+		return ("Log Select");
 
-      case 0x4d:
-         return( "Log Sense" );
+	case 0x4d:
+		return ("Log Sense");
 
-      case 0x56:
-         return( "Reserve (10)" );
+	case 0x56:
+		return ("Reserve (10)");
 
-      case 0x57:
-         return( "Release (10)" );
+	case 0x57:
+		return ("Release (10)");
 
-      case 0xa0:
-         return( "ReportLuns" );
+	case 0xa0:
+		return ("ReportLuns");
 
-      case 0xb7:
-         return( "Read Defect Data (12)" );
+	case 0xb7:
+		return ("Read Defect Data (12)");
 
-      case 0xca:
-         return( "Peripheral Device Addressing SCSI Passthrough" );
+	case 0xca:
+		return ("Peripheral Device Addressing SCSI Passthrough");
 
-      case 0xcb:
-         return( "Compaq Array Firmware Passthrough" );
+	case 0xcb:
+		return ("Compaq Array Firmware Passthrough");
 
-      default:
-         return( NULL );
-   }
+	default:
+		return (NULL);
+	}
 
-} // end ScsiToAscii()
+}				// end ScsiToAscii()
 
 void cpqfcTS_print_scsi_cmd(Scsi_Cmnd * cmd)
 {
 
-printk("cpqfcTS: (%s) chnl 0x%02x, trgt = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", 
-    ScsiToAscii( cmd->cmnd[0]), cmd->channel, cmd->target, cmd->lun, cmd->cmd_len);
+	printk("cpqfcTS: (%s) chnl 0x%02x, trgt = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", ScsiToAscii(cmd->cmnd[0]), cmd->channel, cmd->target, cmd->lun, cmd->cmd_len);
 
-if( cmd->cmnd[0] == 0)   // Test Unit Ready?
-{
-  int i;
+	if (cmd->cmnd[0] == 0)	// Test Unit Ready?
+	{
+		int i;
 
-  printk("Cmnd->request_bufflen = 0x%X, ->use_sg = %d, ->bufflen = %d\n",
-    cmd->request_bufflen, cmd->use_sg, cmd->bufflen);
-  printk("Cmnd->request_buffer = %p, ->sglist_len = %d, ->buffer = %p\n",
-    cmd->request_buffer, cmd->sglist_len, cmd->buffer);
-  for (i = 0; i < cmd->cmd_len; i++)
-    printk("0x%02x ", cmd->cmnd[i]);
-  printk("\n");
-}
+		printk("Cmnd->request_bufflen = 0x%X, ->use_sg = %d, ->bufflen = %d\n", cmd->request_bufflen, cmd->use_sg, cmd->bufflen);
+		printk("Cmnd->request_buffer = %p, ->sglist_len = %d, ->buffer = %p\n", cmd->request_buffer, cmd->sglist_len, cmd->buffer);
+		for (i = 0; i < cmd->cmd_len; i++)
+			printk("0x%02x ", cmd->cmnd[i]);
+		printk("\n");
+	}
 
 }
 
@@ -1154,51 +1023,48 @@
 
 
 
-static void QueCmndOnBoardLock( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
+static void QueCmndOnBoardLock(CPQFCHBA * cpqfcHBAdata, Scsi_Cmnd * Cmnd)
 {
-  int i;
+	int i;
 
-  for( i=0; i< CPQFCTS_REQ_QUEUE_LEN; i++)
-  {    // find spare slot
-    if( cpqfcHBAdata->BoardLockCmnd[i] == NULL )
-    {
-      cpqfcHBAdata->BoardLockCmnd[i] = Cmnd;
+	for (i = 0; i < CPQFCTS_REQ_QUEUE_LEN; i++) {	// find spare slot
+		if (cpqfcHBAdata->BoardLockCmnd[i] == NULL) {
+			cpqfcHBAdata->BoardLockCmnd[i] = Cmnd;
 //      printk(" BoardLockCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n",
 //        i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
-      break;
-    }
-  }
-  if( i >= CPQFCTS_REQ_QUEUE_LEN)
-  {
-    printk(" cpqfcTS WARNING: Lost Cmnd %p on BoardLock Q full!", Cmnd);
-  }
+			break;
+		}
+	}
+	if (i >= CPQFCTS_REQ_QUEUE_LEN) {
+		printk(" cpqfcTS WARNING: Lost Cmnd %p on BoardLock Q full!", Cmnd);
+	}
 
 }
 
 
-static void QueLinkDownCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
+static void QueLinkDownCmnd(CPQFCHBA * cpqfcHBAdata, Scsi_Cmnd * Cmnd)
 {
-  int indx;
+	int indx;
 
-  // Remember the command ptr so we can return; we'll complete when
-  // the device comes back, causing immediate retry
-  for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++)//, SCptr++)
-  {
-    if( cpqfcHBAdata->LinkDnCmnd[indx] == NULL ) // available?
-    {
+	// Remember the command ptr so we can return; we'll complete when
+	// the device comes back, causing immediate retry
+	for (indx = 0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++)	//, SCptr++)
+	{
+		if (cpqfcHBAdata->LinkDnCmnd[indx] == NULL)	// available?
+		{
 #ifdef DUMMYCMND_DBG
-      printk(" @add Cmnd %p to LnkDnCmnd[%d]@ ", Cmnd,indx);
+			printk(" @add Cmnd %p to LnkDnCmnd[%d]@ ", Cmnd, indx);
 #endif
-      cpqfcHBAdata->LinkDnCmnd[indx] = Cmnd;
-      break;
-    }
-  }
-
-  if( indx >= CPQFCTS_REQ_QUEUE_LEN ) // no space for Cmnd??
-  {
-    // this will result in an _abort call later (with possible trouble)
-    printk("no buffer for LinkDnCmnd!! %p\n", Cmnd);
-  }
+			cpqfcHBAdata->LinkDnCmnd[indx] = Cmnd;
+			break;
+		}
+	}
+
+	if (indx >= CPQFCTS_REQ_QUEUE_LEN)	// no space for Cmnd??
+	{
+		// this will result in an _abort call later (with possible trouble)
+		printk("no buffer for LinkDnCmnd!! %p\n", Cmnd);
+	}
 }
 
 
@@ -1211,185 +1077,162 @@
 // for cases that don't go to the hardware like scsi cmds destined
 // for LUNs we know don't exist, so this code might be simplified...)
 
-static void QueBadTargetCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
+static void QueBadTargetCmnd(CPQFCHBA * cpqfcHBAdata, Scsi_Cmnd * Cmnd)
 {
-  int i;
-    //    printk(" can't find target %d\n", Cmnd->target);
+	int i;
+	//    printk(" can't find target %d\n", Cmnd->target);
 
-  for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
-  {    // find spare slot
-    if( cpqfcHBAdata->BadTargetCmnd[i] == NULL )
-    {
-      cpqfcHBAdata->BadTargetCmnd[i] = Cmnd;
+	for (i = 0; i < CPQFCTS_MAX_TARGET_ID; i++) {	// find spare slot
+		if (cpqfcHBAdata->BadTargetCmnd[i] == NULL) {
+			cpqfcHBAdata->BadTargetCmnd[i] = Cmnd;
 //      printk(" BadTargetCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n",
 //          i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
-      break;
-    }
-  }
+			break;
+		}
+	}
 }
 
 
 // This is the "main" entry point for Linux Scsi commands --
 // it all starts here.
 
-int cpqfcTS_queuecommand(Scsi_Cmnd *Cmnd, void (* done)(Scsi_Cmnd *))
+int cpqfcTS_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
 {
-  struct Scsi_Host *HostAdapter = Cmnd->host;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  TachFCHDR_GCMND fchs;  // only use for FC destination id field  
-  PFC_LOGGEDIN_PORT pLoggedInPort;
-  ULONG ulStatus, SESTtype;
-  LONG ExchangeID;
+	struct Scsi_Host *HostAdapter = Cmnd->host;
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	TachFCHDR_GCMND fchs;	// only use for FC destination id field  
+	PFC_LOGGEDIN_PORT pLoggedInPort;
+	u32 ulStatus, SESTtype;
+	s32 ExchangeID;
+
+
 
 
+	ENTER("cpqfcTS_queuecommand");
 
+	PCI_TRACEO((u32) Cmnd, 0x98)
 
-  ENTER("cpqfcTS_queuecommand");
-      
-  PCI_TRACEO( (ULONG)Cmnd, 0x98)
-      
-  
-  Cmnd->scsi_done = done;
-#ifdef DEBUG_CMND  
-  cpqfcTS_print_scsi_cmd( Cmnd);
+
+	    Cmnd->scsi_done = done;
+#ifdef DEBUG_CMND
+	cpqfcTS_print_scsi_cmd(Cmnd);
 #endif
 
-  // prevent board contention with kernel thread...  
-  
-   if( cpqfcHBAdata->BoardLock )
-  {
+	// prevent board contention with kernel thread...  
+
+	if (cpqfcHBAdata->BoardLock) {
 //    printk(" @BrdLck Hld@ ");
-    QueCmndOnBoardLock( cpqfcHBAdata, Cmnd);
-  }
-  
-  else
-  {
-
-    // in the current system (2.2.12), this routine is called
-    // after spin_lock_irqsave(), so INTs are disabled. However,
-    // we might have something pending in the LinkQ, which
-    // might cause the WorkerTask to run.  In case that
-    // happens, make sure we lock it out.
-    
-    
-    
-    PCI_TRACE( 0x98) 
-    CPQ_SPINLOCK_HBA( cpqfcHBAdata)
-    PCI_TRACE( 0x98) 
-	    
-  // can we find an FC device mapping to this SCSI target?
-    pLoggedInPort = fcFindLoggedInPort( fcChip,
-      Cmnd,     // search Scsi Nexus
-      0,        // DON'T search linked list for FC port id
-      NULL,     // DON'T search linked list for FC WWN
-      NULL);    // DON'T care about end of list
- 
-    if( pLoggedInPort == NULL )      // not found!
-    {
+		QueCmndOnBoardLock(cpqfcHBAdata, Cmnd);
+	}
+
+	else {
+
+		// in the current system (2.2.12), this routine is called
+		// after spin_lock_irqsave(), so INTs are disabled. However,
+		// we might have something pending in the LinkQ, which
+		// might cause the WorkerTask to run.  In case that
+		// happens, make sure we lock it out.
+
+
+
+		PCI_TRACE(0x98)
+		    CPQ_SPINLOCK_HBA(cpqfcHBAdata)
+		    PCI_TRACE(0x98)
+		    // can we find an FC device mapping to this SCSI target?
+		    pLoggedInPort = fcFindLoggedInPort(fcChip, Cmnd,	// search Scsi Nexus
+						       0,	// DON'T search linked list for FC port id
+						       NULL,	// DON'T search linked list for FC WWN
+						       NULL);	// DON'T care about end of list
+
+		if (pLoggedInPort == NULL)	// not found!
+		{
 //    printk(" @Q bad targ cmnd %p@ ", Cmnd);
-      QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
-    }
-    else if (Cmnd->lun >= CPQFCTS_MAX_LUN)
-    {
-      printk(KERN_WARNING "cpqfc: Invalid LUN: %d\n", Cmnd->lun);
-      QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
-    } 
-
-    else  // we know what FC device to send to...
-    {
-
-      // does this device support FCP target functions?
-      // (determined by PRLI field)
-
-      if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) )
-      {
-        printk(" Doesn't support TARGET functions port_id %Xh\n",
-          pLoggedInPort->port_id );
-        QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
-      }
-
-    // In this case (previous login OK), the device is temporarily
-    // unavailable waiting for re-login, in which case we expect it
-    // to be back in between 25 - 500ms.  
-    // If the FC port doesn't log back in within several seconds
-    // (i.e. implicit "logout"), or we get an explicit logout,
-    // we set "device_blocked" in Scsi_Device struct; in this
-    // case 30 seconds will elapse before Linux/Scsi sends another
-    // command to the device.
-      else if( pLoggedInPort->prli != TRUE )
-      {
+			QueBadTargetCmnd(cpqfcHBAdata, Cmnd);
+		} else if (Cmnd->lun >= CPQFCTS_MAX_LUN) {
+			printk(KERN_WARNING "cpqfc: Invalid LUN: %d\n", Cmnd->lun);
+			QueBadTargetCmnd(cpqfcHBAdata, Cmnd);
+		}
+
+		else		// we know what FC device to send to...
+		{
+
+			// does this device support FCP target functions?
+			// (determined by PRLI field)
+
+			if (!(pLoggedInPort->fcp_info & TARGET_FUNCTION)) {
+				printk(" Doesn't support TARGET functions port_id %Xh\n", pLoggedInPort->port_id);
+				QueBadTargetCmnd(cpqfcHBAdata, Cmnd);
+			}
+			// In this case (previous login OK), the device is temporarily
+			// unavailable waiting for re-login, in which case we expect it
+			// to be back in between 25 - 500ms.  
+			// If the FC port doesn't log back in within several seconds
+			// (i.e. implicit "logout"), or we get an explicit logout,
+			// we set "device_blocked" in Scsi_Device struct; in this
+			// case 30 seconds will elapse before Linux/Scsi sends another
+			// command to the device.
+			else if (pLoggedInPort->prli != TRUE) {
 //      printk("Device (Chnl/Target %d/%d) invalid PRLI, port_id %06lXh\n",
 //        Cmnd->channel, Cmnd->target, pLoggedInPort->port_id);
-        QueLinkDownCmnd( cpqfcHBAdata, Cmnd);
-//    Need to use "blocked" flag??   	
-//	Cmnd->device->device_blocked = TRUE; // just let it timeout
-      }
-      else  // device supports TARGET functions, and is logged in...
-      {
-      // (context of fchs is to "reply" to...)
-        fchs.s_id = pLoggedInPort->port_id; // destination FC address
-
-      // what is the data direction?  For data TO the device,
-      // we need IWE (Intiator Write Entry).  Otherwise, IRE.
-
-        if( Cmnd->cmnd[0] == WRITE_10 ||
-  	  Cmnd->cmnd[0] == WRITE_6 ||
-	  Cmnd->cmnd[0] == WRITE_BUFFER ||      
-	  Cmnd->cmnd[0] == VENDOR_WRITE_OPCODE ||  // CPQ specific 
-	  Cmnd->cmnd[0] == MODE_SELECT )
-        {
-          SESTtype = SCSI_IWE; // data from HBA to Device
-        }
-        else
-          SESTtype = SCSI_IRE; // data from Device to HBA
-    	  
-        ulStatus = cpqfcTSBuildExchange(
-          cpqfcHBAdata,
-          SESTtype,     // e.g. Initiator Read Entry (IRE)
-          &fchs,        // we are originator; only use d_id
-          Cmnd,         // Linux SCSI command (with scatter/gather list)
-          &ExchangeID );// fcController->fcExchanges index, -1 if failed
+				QueLinkDownCmnd(cpqfcHBAdata, Cmnd);
+//    Need to use "blocked" flag??      
+//      Cmnd->device->device_blocked = TRUE; // just let it timeout
+			} else	// device supports TARGET functions, and is logged in...
+			{
+				// (context of fchs is to "reply" to...)
+				fchs.s_id = pLoggedInPort->port_id;	// destination FC address
+
+				// what is the data direction?  For data TO the device,
+				// we need IWE (Intiator Write Entry).  Otherwise, IRE.
+
+				if (Cmnd->cmnd[0] == WRITE_10 || Cmnd->cmnd[0] == WRITE_6 || Cmnd->cmnd[0] == WRITE_BUFFER || Cmnd->cmnd[0] == VENDOR_WRITE_OPCODE ||	// CPQ specific 
+				    Cmnd->cmnd[0] == MODE_SELECT) {
+					SESTtype = SCSI_IWE;	// data from HBA to Device
+				} else
+					SESTtype = SCSI_IRE;	// data from Device to HBA
+
+				ulStatus = cpqfcTSBuildExchange(cpqfcHBAdata, SESTtype,	// e.g. Initiator Read Entry (IRE)
+								&fchs,	// we are originator; only use d_id
+								Cmnd,	// Linux SCSI command (with scatter/gather list)
+								&ExchangeID);	// fcController->fcExchanges index, -1 if failed
+
+				if (!ulStatus)	// Exchange setup?
+
+				{
+					if (cpqfcHBAdata->BoardLock) {
+						TriggerHBA(fcChip->Registers.ReMapMemBase, 0);
+						printk(" @bl! %d, xID %Xh@ ", current->pid, ExchangeID);
+					}
+
+					ulStatus = cpqfcTSStartExchange(cpqfcHBAdata, ExchangeID);
+					if (!ulStatus) {
+						PCI_TRACEO(ExchangeID, 0xB8)
+						    // submitted to Tach's Outbound Que (ERQ PI incremented)
+						    // waited for completion for ELS type (Login frames issued
+						    // synchronously)
+					} else
+						// check reason for Exchange not being started - we might
+						// want to Queue and start later, or fail with error
+					{
+						printk("quecommand: cpqfcTSStartExchange failed: %Xh\n", ulStatus);
+					}
+				}	// end good BuildExchange status
+
+				else	// SEST table probably full  -- why? hardware hang?
+				{
+					printk("quecommand: cpqfcTSBuildExchange faild: %Xh\n", ulStatus);
+				}
+			}	// end can't do FCP-SCSI target functions
+		}		// end can't find target (FC device)
 
-        if( !ulStatus ) // Exchange setup?
-   
-        {
-          if( cpqfcHBAdata->BoardLock )
-          {
-    TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
-	    printk(" @bl! %d, xID %Xh@ ", current->pid, ExchangeID);
-          }
-
-	  ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
-	  if( !ulStatus )
-          {
-            PCI_TRACEO( ExchangeID, 0xB8) 
-          // submitted to Tach's Outbound Que (ERQ PI incremented)
-          // waited for completion for ELS type (Login frames issued
-          // synchronously)
-	  }
-          else
-            // check reason for Exchange not being started - we might
-            // want to Queue and start later, or fail with error
-          {
-            printk("quecommand: cpqfcTSStartExchange failed: %Xh\n", ulStatus );
-          }
-        }            // end good BuildExchange status
-        
-        else  // SEST table probably full  -- why? hardware hang?
-        {
-	  printk("quecommand: cpqfcTSBuildExchange faild: %Xh\n", ulStatus);
-        }
-      }  // end can't do FCP-SCSI target functions
-    } // end can't find target (FC device)
-
-    CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
-  }
-	
-  PCI_TRACEO( (ULONG)Cmnd, 0x9C) 
-  LEAVE("cpqfcTS_queuecommand");
-  return 0;
-}    
+		CPQ_SPINUNLOCK_HBA(cpqfcHBAdata)
+	}
+
+	PCI_TRACEO((u32) Cmnd, 0x9C)
+	    LEAVE("cpqfcTS_queuecommand");
+	return 0;
+}
 
 
 // Entry point for upper Scsi layer intiated abort.  Typically
@@ -1403,148 +1246,140 @@
 // errors, it should be considered a driver error and reported to
 // the author.
 
-int cpqfcTS_abort(Scsi_Cmnd *Cmnd)
+int cpqfcTS_abort(Scsi_Cmnd * Cmnd)
 {
-//	printk(" cpqfcTS_abort called?? \n");
- 	return 0;
+//      printk(" cpqfcTS_abort called?? \n");
+	return 0;
 }
- 
-int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd)
+
+int cpqfcTS_eh_abort(Scsi_Cmnd * Cmnd)
 {
 
-  struct Scsi_Host *HostAdapter = Cmnd->host;
-  // get the pointer to our Scsi layer HBA buffer  
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  int i;
-  ENTER("cpqfcTS_eh_abort");
-
-  Cmnd->result = DID_ABORT <<16;  // assume we'll find it
-
-  printk(" @Linux _abort Scsi_Cmnd %p ", Cmnd);
-  // See if we can find a Cmnd pointer that matches...
-  // The most likely case is we accepted the command
-  // from Linux Scsi (e.g. ceated a SEST entry) and it
-  // got lost somehow.  If we can't find any reference
-  // to the passed pointer, we can only presume it
-  // got completed as far as our driver is concerned.
-  // If we found it, we will try to abort it through
-  // common mechanism.  If FC ABTS is successful (ACC)
-  // or is rejected (RJT) by target, we will call
-  // Scsi "done" quickly.  Otherwise, the ABTS will timeout
-  // and we'll call "done" later.
-
-  // Search the SEST exchanges for a matching Cmnd ptr.
-  for( i=0; i< TACH_SEST_LEN; i++)
-  {
-    if( Exchanges->fcExchange[i].Cmnd == Cmnd )
-    {
-      
-      // found it!
-      printk(" x_ID %Xh, type %Xh\n", i, Exchanges->fcExchange[i].type);
-
-      Exchanges->fcExchange[i].status = INITIATOR_ABORT; // seconds default
-      Exchanges->fcExchange[i].timeOut = 10; // seconds default (changed later)
-
-      // Since we need to immediately return the aborted Cmnd to Scsi 
-      // upper layers, we can't make future reference to any of it's 
-      // fields (e.g the Nexus).
-
-      cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i);
-
-      break;
-    }
-  }
-
-  if( i >= TACH_SEST_LEN ) // didn't find Cmnd ptr in chip's SEST?
-  {
-    // now search our non-SEST buffers (i.e. Cmnd waiting to
-    // start on the HBA or waiting to complete with error for retry).
-    
-    // first check BadTargetCmnd
-    for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
-    { 
-      if( cpqfcHBAdata->BadTargetCmnd[i] == Cmnd )
-      {
-        cpqfcHBAdata->BadTargetCmnd[i] = NULL;
-	printk("in BadTargetCmnd Q\n");
-	goto Done; // exit
-      }
-    }
-
-    // if not found above...
-
-    for( i=0; i < CPQFCTS_REQ_QUEUE_LEN; i++)
-    {
-      if( cpqfcHBAdata->LinkDnCmnd[i] == Cmnd ) 
-      {
-	cpqfcHBAdata->LinkDnCmnd[i] = NULL;
-	printk("in LinkDnCmnd Q\n");
-	goto Done;
-      }
-    }
-
-
-    for( i=0; i< CPQFCTS_REQ_QUEUE_LEN; i++)
-    {    // find spare slot
-      if( cpqfcHBAdata->BoardLockCmnd[i] == Cmnd )
-      {
-        cpqfcHBAdata->BoardLockCmnd[i] = NULL;
-	printk("in BoardLockCmnd Q\n");
-	goto Done;
-      }
-    }
-    
-    Cmnd->result = DID_ERROR <<16;  // Hmmm...
-    printk("Not found! ");
+	struct Scsi_Host *HostAdapter = Cmnd->host;
+	// get the pointer to our Scsi layer HBA buffer  
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	int i;
+	ENTER("cpqfcTS_eh_abort");
+
+	Cmnd->result = DID_ABORT << 16;	// assume we'll find it
+
+	printk(" @Linux _abort Scsi_Cmnd %p ", Cmnd);
+	// See if we can find a Cmnd pointer that matches...
+	// The most likely case is we accepted the command
+	// from Linux Scsi (e.g. ceated a SEST entry) and it
+	// got lost somehow.  If we can't find any reference
+	// to the passed pointer, we can only presume it
+	// got completed as far as our driver is concerned.
+	// If we found it, we will try to abort it through
+	// common mechanism.  If FC ABTS is successful (ACC)
+	// or is rejected (RJT) by target, we will call
+	// Scsi "done" quickly.  Otherwise, the ABTS will timeout
+	// and we'll call "done" later.
+
+	// Search the SEST exchanges for a matching Cmnd ptr.
+	for (i = 0; i < TACH_SEST_LEN; i++) {
+		if (Exchanges->fcExchange[i].Cmnd == Cmnd) {
+
+			// found it!
+			printk(" x_ID %Xh, type %Xh\n", i, Exchanges->fcExchange[i].type);
+
+			Exchanges->fcExchange[i].status = INITIATOR_ABORT;	// seconds default
+			Exchanges->fcExchange[i].timeOut = 10;	// seconds default (changed later)
+
+			// Since we need to immediately return the aborted Cmnd to Scsi 
+			// upper layers, we can't make future reference to any of it's 
+			// fields (e.g the Nexus).
+
+			cpqfcTSPutLinkQue(cpqfcHBAdata, BLS_ABTS, &i);
+
+			break;
+		}
+	}
+
+	if (i >= TACH_SEST_LEN)	// didn't find Cmnd ptr in chip's SEST?
+	{
+		// now search our non-SEST buffers (i.e. Cmnd waiting to
+		// start on the HBA or waiting to complete with error for retry).
+
+		// first check BadTargetCmnd
+		for (i = 0; i < CPQFCTS_MAX_TARGET_ID; i++) {
+			if (cpqfcHBAdata->BadTargetCmnd[i] == Cmnd) {
+				cpqfcHBAdata->BadTargetCmnd[i] = NULL;
+				printk("in BadTargetCmnd Q\n");
+				goto Done;	// exit
+			}
+		}
+
+		// if not found above...
+
+		for (i = 0; i < CPQFCTS_REQ_QUEUE_LEN; i++) {
+			if (cpqfcHBAdata->LinkDnCmnd[i] == Cmnd) {
+				cpqfcHBAdata->LinkDnCmnd[i] = NULL;
+				printk("in LinkDnCmnd Q\n");
+				goto Done;
+			}
+		}
+
+
+		for (i = 0; i < CPQFCTS_REQ_QUEUE_LEN; i++) {	// find spare slot
+			if (cpqfcHBAdata->BoardLockCmnd[i] == Cmnd) {
+				cpqfcHBAdata->BoardLockCmnd[i] = NULL;
+				printk("in BoardLockCmnd Q\n");
+				goto Done;
+			}
+		}
+
+		Cmnd->result = DID_ERROR << 16;	// Hmmm...
+		printk("Not found! ");
 //    panic("_abort");
-  }
-  
-Done:
-  
+	}
+
+      Done:
+
 //    panic("_abort");
-  LEAVE("cpqfcTS_eh_abort");
-  return 0;  // (see scsi.h)
-}    
+	LEAVE("cpqfcTS_eh_abort");
+	return 0;		// (see scsi.h)
+}
 
 
 // FCP-SCSI Target Device Reset
 // See dpANS Fibre Channel Protocol for SCSI
 // X3.269-199X revision 12, pg 25
 
-int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, 
-                               unsigned int reset_flags)
+int cpqfcTS_TargetDeviceReset(Scsi_Device * ScsiDev, unsigned int reset_flags)
 {
-  int timeout = 10*HZ;
-  int retries = 1;
-  char scsi_cdb[12];
-  int result;
-  Scsi_Cmnd * SCpnt;
-  Scsi_Device * SDpnt;
-
-
-  // printk("   ENTERING cpqfcTS_TargetDeviceReset() - flag=%d \n",reset_flags);
-
-  if (ScsiDev->host->eh_active) return FAILED;
-
-  memset( scsi_cdb, 0, sizeof( scsi_cdb));
-
-  scsi_cdb[0] = RELEASE;
-
-  // allocate with wait = true, interruptible = false 
-  SCpnt = scsi_allocate_device(ScsiDev, 1, 0);
-  {
-    CPQFC_DECLARE_COMPLETION(wait);
-        
-    SCpnt->SCp.buffers_residual = FCP_TARGET_RESET;
-
-	SCpnt->request.CPQFC_WAITING = &wait;
-	scsi_do_cmd(SCpnt,  scsi_cdb, NULL,  0, my_ioctl_done,  timeout, retries);
-	CPQFC_WAIT_FOR_COMPLETION(&wait);
-	SCpnt->request.CPQFC_WAITING = NULL;
-  }
-    
+	int timeout = 10 * HZ;
+	int retries = 1;
+	char scsi_cdb[12];
+	int result;
+	Scsi_Cmnd *SCpnt;
+	Scsi_Device *SDpnt;
+
+
+	// printk("   ENTERING cpqfcTS_TargetDeviceReset() - flag=%d \n",reset_flags);
+
+	if (ScsiDev->host->eh_active)
+		return FAILED;
+
+	memset(scsi_cdb, 0, sizeof(scsi_cdb));
+
+	scsi_cdb[0] = RELEASE;
+
+	// allocate with wait = true, interruptible = false 
+	SCpnt = scsi_allocate_device(ScsiDev, 1, 0);
+	{
+		CPQFC_DECLARE_COMPLETION(wait);
+
+		SCpnt->SCp.buffers_residual = FCP_TARGET_RESET;
+
+		SCpnt->request.CPQFC_WAITING = &wait;
+		scsi_do_cmd(SCpnt, scsi_cdb, NULL, 0, my_ioctl_done, timeout, retries);
+		CPQFC_WAIT_FOR_COMPLETION(&wait);
+		SCpnt->request.CPQFC_WAITING = NULL;
+	}
+
 /*
       if(driver_byte(SCpnt->result) != 0)
 	  switch(SCpnt->sense_buffer[2] & 0xf) {
@@ -1577,41 +1412,41 @@
 		   SCpnt->sense_buffer[2] & 0xf);
 	    
       };
-*/    
-  result = SCpnt->result;
+*/
+	result = SCpnt->result;
 
-  SDpnt = SCpnt->device;
-  scsi_release_command(SCpnt);
-  SCpnt = NULL;
+	SDpnt = SCpnt->device;
+	scsi_release_command(SCpnt);
+	SCpnt = NULL;
 
-  // if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
-  // 	(*SDpnt->scsi_request_fn)();
+	// if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
+	//    (*SDpnt->scsi_request_fn)();
 
-  wake_up(&SDpnt->scpnt_wait);
-  // printk("   LEAVING cpqfcTS_TargetDeviceReset() - return SUCCESS \n");
-  return SUCCESS;
+	wake_up(&SDpnt->scpnt_wait);
+	// printk("   LEAVING cpqfcTS_TargetDeviceReset() - return SUCCESS \n");
+	return SUCCESS;
 }
 
 
-int cpqfcTS_eh_device_reset(Scsi_Cmnd *Cmnd)
+int cpqfcTS_eh_device_reset(Scsi_Cmnd * Cmnd)
 {
-  int retval;
-  Scsi_Device *SDpnt = Cmnd->device;
-  // printk("   ENTERING cpqfcTS_eh_device_reset() \n");
-  spin_unlock_irq(&io_request_lock);
-  retval = cpqfcTS_TargetDeviceReset( SDpnt, 0);
-  spin_lock_irq(&io_request_lock);
-  return retval;
+	int retval;
+	Scsi_Device *SDpnt = Cmnd->device;
+	// printk("   ENTERING cpqfcTS_eh_device_reset() \n");
+	spin_unlock_irq(&io_request_lock);
+	retval = cpqfcTS_TargetDeviceReset(SDpnt, 0);
+	spin_lock_irq(&io_request_lock);
+	return retval;
 }
 
-	
-int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags)
+
+int cpqfcTS_reset(Scsi_Cmnd * Cmnd, unsigned int reset_flags)
 {
 
-  ENTER("cpqfcTS_reset");
+	ENTER("cpqfcTS_reset");
 
-  LEAVE("cpqfcTS_reset");
-  return SCSI_RESET_ERROR;      /* Bus Reset Not supported */
+	LEAVE("cpqfcTS_reset");
+	return SCSI_RESET_ERROR;	/* Bus Reset Not supported */
 }
 
 /* This function determines the bios parameters for a given
@@ -1621,228 +1456,210 @@
    (from hosts.h)
 */
 
-int cpqfcTS_biosparam(Disk *disk, kdev_t n, int ip[])
+int cpqfcTS_biosparam(Disk * disk, kdev_t n, int ip[])
 {
-  int size = disk->capacity;
-  
-  ENTER("cpqfcTS_biosparam");
-  ip[0] = 64;
-  ip[1] = 32;
-  ip[2] = size >> 11;
-  
-  if( ip[2] > 1024 )
-  {
-    ip[0] = 255;
-    ip[1] = 63;
-    ip[2] = size / (ip[0] * ip[1]);
-  }
-
-  LEAVE("cpqfcTS_biosparam");
-  return 0;
-}    
+	int size = disk->capacity;
 
+	ENTER("cpqfcTS_biosparam");
+	ip[0] = 64;
+	ip[1] = 32;
+	ip[2] = size >> 11;
+
+	if (ip[2] > 1024) {
+		ip[0] = 255;
+		ip[1] = 63;
+		ip[2] = size / (ip[0] * ip[1]);
+	}
 
+	LEAVE("cpqfcTS_biosparam");
+	return 0;
+}
 
-void cpqfcTS_intr_handler( int irq, 
-		void *dev_id, 
-		struct pt_regs *regs)
-{
-
-  unsigned long flags, InfLoopBrk=0;
-  struct Scsi_Host *HostAdapter = dev_id;
-  CPQFCHBA *cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata;
-  int MoreMessages = 1; // assume we have something to do
-  UCHAR IntPending;
-  
-  ENTER("intr_handler");
-
-  spin_lock_irqsave( &io_request_lock, flags);
-  // is this our INT?
-  IntPending = readb( cpqfcHBA->fcChip.Registers.INTPEND.address);
 
-  // broken boards can generate messages forever, so
-  // prevent the infinite loop
+
+void cpqfcTS_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+
+	unsigned long flags, InfLoopBrk = 0;
+	struct Scsi_Host *HostAdapter = dev_id;
+	CPQFCHBA *cpqfcHBA = (CPQFCHBA *) HostAdapter->hostdata;
+	int MoreMessages = 1;	// assume we have something to do
+	u8 IntPending;
+
+	ENTER("intr_handler");
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	// is this our INT?
+	IntPending = readb(cpqfcHBA->fcChip.Registers.INTPEND.address);
+
+	// broken boards can generate messages forever, so
+	// prevent the infinite loop
 #define INFINITE_IMQ_BREAK 10000
-  if( IntPending )
-  {
-    
-    // mask our HBA interrupts until we handle it...
-    writeb( 0, cpqfcHBA->fcChip.Registers.INTEN.address);
-
-    if( IntPending & 0x4) // "INT" - Tach wrote to IMQ
-    {
-      while( (++InfLoopBrk < INFINITE_IMQ_BREAK) && (MoreMessages ==1) ) 
-      {
-        MoreMessages = CpqTsProcessIMQEntry( HostAdapter); // ret 0 when done
-      }
-      if( InfLoopBrk >= INFINITE_IMQ_BREAK )
-      {
-        printk("WARNING: Compaq FC adapter generating excessive INTs -REPLACE\n");
-        printk("or investigate alternate causes (e.g. physical FC layer)\n");
-      }
-
-      else  // working normally - re-enable INTs and continue
-        writeb( 0x1F, cpqfcHBA->fcChip.Registers.INTEN.address);
-    
-    }  // (...ProcessIMQEntry() clears INT by writing IMQ consumer)
-    else  // indications of errors or problems...
-          // these usually indicate critical system hardware problems.
-    {
-      if( IntPending & 0x10 )
-  	printk(" cpqfcTS adapter external memory parity error detected\n");
-      if( IntPending & 0x8 )
-  	printk(" cpqfcTS adapter PCI master address crossed 45-bit boundary\n");
-      if( IntPending & 0x2 )
-	printk(" cpqfcTS adapter DMA error detected\n");
-      if( IntPending & 0x1 ) {
-  	UCHAR IntStat;
-  	printk(" cpqfcTS adapter PCI error detected\n");
-  	IntStat = readb( cpqfcHBA->fcChip.Registers.INTSTAT.address);
-	if (IntStat & 0x4) printk("(INT)\n");
-	if (IntStat & 0x8) 
-		printk("CRS: PCI master address crossed 46 bit bouandary\n");
-	if (IntStat & 0x10) printk("MRE: external memory parity error.\n");
-      }
-    }      
-  }
-  spin_unlock_irqrestore( &io_request_lock, flags);
-  LEAVE("intr_handler");
+	if (IntPending) {
+
+		// mask our HBA interrupts until we handle it...
+		writeb(0, cpqfcHBA->fcChip.Registers.INTEN.address);
+
+		if (IntPending & 0x4)	// "INT" - Tach wrote to IMQ
+		{
+			while ((++InfLoopBrk < INFINITE_IMQ_BREAK) && (MoreMessages == 1)) {
+				MoreMessages = CpqTsProcessIMQEntry(HostAdapter);	// ret 0 when done
+			}
+			if (InfLoopBrk >= INFINITE_IMQ_BREAK) {
+				printk("WARNING: Compaq FC adapter generating excessive INTs -REPLACE\n");
+				printk("or investigate alternate causes (e.g. physical FC layer)\n");
+			}
+
+			else	// working normally - re-enable INTs and continue
+				writeb(0x1F, cpqfcHBA->fcChip.Registers.INTEN.address);
+
+		}		// (...ProcessIMQEntry() clears INT by writing IMQ consumer)
+		else		// indications of errors or problems...
+			// these usually indicate critical system hardware problems.
+		{
+			if (IntPending & 0x10)
+				printk(" cpqfcTS adapter external memory parity error detected\n");
+			if (IntPending & 0x8)
+				printk(" cpqfcTS adapter PCI master address crossed 45-bit boundary\n");
+			if (IntPending & 0x2)
+				printk(" cpqfcTS adapter DMA error detected\n");
+			if (IntPending & 0x1) {
+				u8 IntStat;
+				printk(" cpqfcTS adapter PCI error detected\n");
+				IntStat = readb(cpqfcHBA->fcChip.Registers.INTSTAT.address);
+				if (IntStat & 0x4)
+					printk("(INT)\n");
+				if (IntStat & 0x8)
+					printk("CRS: PCI master address crossed 46 bit bouandary\n");
+				if (IntStat & 0x10)
+					printk("MRE: external memory parity error.\n");
+			}
+		}
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	LEAVE("intr_handler");
 }
 
 
 
 
-int cpqfcTSDecodeGBICtype( PTACHYON fcChip, char cErrorString[])
-{
-        // Verify GBIC type (if any) and correct Tachyon Port State Machine
-        // (GBIC) module definition is:
-        // GPIO1, GPIO0, GPIO4 for MD2, MD1, MD0.  The input states appear
-        // to be inverted -- i.e., a setting of 111 is read when there is NO
-        // GBIC present.  The Module Def (MD) spec says 000 is "no GBIC"
-        // Hard code the bit states to detect Copper, 
-        // Long wave (single mode), Short wave (multi-mode), and absent GBIC
-
-  ULONG ulBuff;
-
-  sprintf( cErrorString, "\nGBIC detected: ");
-
-  ulBuff = fcChip->Registers.TYstatus.value & 0x13; 
-  switch( ulBuff )
-  {
-  case 0x13:  // GPIO4, GPIO1, GPIO0 = 111; no GBIC!
-    sprintf( &cErrorString[ strlen( cErrorString)],
-            "NONE! ");
-    return FALSE;          
-          
-       
-  case 0x11:   // Copper GBIC detected
-    sprintf( &cErrorString[ strlen( cErrorString)],
-            "Copper. ");
-    break;
-
-  case 0x10:   // Long-wave (single mode) GBIC detected
-    sprintf( &cErrorString[ strlen( cErrorString)],
-        "Long-wave. ");
-    break;
-  case 0x1:    // Short-wave (multi mode) GBIC detected
-    sprintf( &cErrorString[ strlen( cErrorString)],
-        "Short-wave. ");
-    break;
-  default:     // unknown GBIC - presumably it will work (?)
-    sprintf( &cErrorString[ strlen( cErrorString)],
-            "Unknown. ");
-          
-    break;
-  }  // end switch GBIC detection
-
-  return TRUE;
-}
+int cpqfcTSDecodeGBICtype(PTACHYON fcChip, char cErrorString[])
+{
+	// Verify GBIC type (if any) and correct Tachyon Port State Machine
+	// (GBIC) module definition is:
+	// GPIO1, GPIO0, GPIO4 for MD2, MD1, MD0.  The input states appear
+	// to be inverted -- i.e., a setting of 111 is read when there is NO
+	// GBIC present.  The Module Def (MD) spec says 000 is "no GBIC"
+	// Hard code the bit states to detect Copper, 
+	// Long wave (single mode), Short wave (multi-mode), and absent GBIC
 
+	u32 ulBuff;
 
+	sprintf(cErrorString, "\nGBIC detected: ");
 
+	ulBuff = fcChip->Registers.TYstatus.value & 0x13;
+	switch (ulBuff) {
+	case 0x13:		// GPIO4, GPIO1, GPIO0 = 111; no GBIC!
+		sprintf(&cErrorString[strlen(cErrorString)], "NONE! ");
+		return FALSE;
 
 
+	case 0x11:		// Copper GBIC detected
+		sprintf(&cErrorString[strlen(cErrorString)], "Copper. ");
+		break;
+
+	case 0x10:		// Long-wave (single mode) GBIC detected
+		sprintf(&cErrorString[strlen(cErrorString)], "Long-wave. ");
+		break;
+	case 0x1:		// Short-wave (multi mode) GBIC detected
+		sprintf(&cErrorString[strlen(cErrorString)], "Short-wave. ");
+		break;
+	default:		// unknown GBIC - presumably it will work (?)
+		sprintf(&cErrorString[strlen(cErrorString)], "Unknown. ");
 
-int cpqfcTSGetLPSM( PTACHYON fcChip, char cErrorString[])
-{
-  // Tachyon's Frame Manager LPSM in LinkDown state?
-  // (For non-loop port, check PSM instead.)
-  // return string with state and FALSE is Link Down
-
-  int LinkUp;
-
-  if( fcChip->Registers.FMstatus.value & 0x80 ) 
-    LinkUp = FALSE;
-  else
-    LinkUp = TRUE;
-
-  sprintf( &cErrorString[ strlen( cErrorString)],
-    " LPSM %Xh ", 
-     (fcChip->Registers.FMstatus.value >>4) & 0xf );
-
-
-  switch( fcChip->Registers.FMstatus.value & 0xF0)
-  {
-                    // bits set in LPSM
-    case 0x10:
-      sprintf( &cErrorString[ strlen( cErrorString)], "ARB");
-      break;
-    case 0x20:
-      sprintf( &cErrorString[ strlen( cErrorString)], "ARBwon");
-      break;
-    case 0x30:
-      sprintf( &cErrorString[ strlen( cErrorString)], "OPEN");
-      break;
-    case 0x40:
-      sprintf( &cErrorString[ strlen( cErrorString)], "OPENed");
-      break;
-    case 0x50:
-      sprintf( &cErrorString[ strlen( cErrorString)], "XmitCLS");
-      break;
-    case 0x60:
-      sprintf( &cErrorString[ strlen( cErrorString)], "RxCLS");
-      break;
-    case 0x70:
-      sprintf( &cErrorString[ strlen( cErrorString)], "Xfer");
-      break;
-    case 0x80:
-      sprintf( &cErrorString[ strlen( cErrorString)], "Init");
-      break;
-    case 0x90:
-      sprintf( &cErrorString[ strlen( cErrorString)], "O-IInitFin");
-      break;
-    case 0xa0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "O-IProtocol");
-      break;
-    case 0xb0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "O-ILipRcvd");
-      break;
-    case 0xc0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "HostControl");
-      break;
-    case 0xd0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "LoopFail");
-      break;
-    case 0xe0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "Offline");
-      break;
-    case 0xf0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "OldPort");
-      break;
-    case 0:
-    default:
-      sprintf( &cErrorString[ strlen( cErrorString)], "Monitor");
-      break;
-
-  }
+		break;
+	}			// end switch GBIC detection
 
-  return LinkUp;
+	return TRUE;
 }
 
 
 
 
-#include "linux/slab.h"
+
+
+int cpqfcTSGetLPSM(PTACHYON fcChip, char cErrorString[])
+{
+	// Tachyon's Frame Manager LPSM in LinkDown state?
+	// (For non-loop port, check PSM instead.)
+	// return string with state and FALSE is Link Down
+
+	int LinkUp;
+
+	if (fcChip->Registers.FMstatus.value & 0x80)
+		LinkUp = FALSE;
+	else
+		LinkUp = TRUE;
+
+	sprintf(&cErrorString[strlen(cErrorString)], " LPSM %Xh ", (fcChip->Registers.FMstatus.value >> 4) & 0xf);
+
+
+	switch (fcChip->Registers.FMstatus.value & 0xF0) {
+		// bits set in LPSM
+	case 0x10:
+		sprintf(&cErrorString[strlen(cErrorString)], "ARB");
+		break;
+	case 0x20:
+		sprintf(&cErrorString[strlen(cErrorString)], "ARBwon");
+		break;
+	case 0x30:
+		sprintf(&cErrorString[strlen(cErrorString)], "OPEN");
+		break;
+	case 0x40:
+		sprintf(&cErrorString[strlen(cErrorString)], "OPENed");
+		break;
+	case 0x50:
+		sprintf(&cErrorString[strlen(cErrorString)], "XmitCLS");
+		break;
+	case 0x60:
+		sprintf(&cErrorString[strlen(cErrorString)], "RxCLS");
+		break;
+	case 0x70:
+		sprintf(&cErrorString[strlen(cErrorString)], "Xfer");
+		break;
+	case 0x80:
+		sprintf(&cErrorString[strlen(cErrorString)], "Init");
+		break;
+	case 0x90:
+		sprintf(&cErrorString[strlen(cErrorString)], "O-IInitFin");
+		break;
+	case 0xa0:
+		sprintf(&cErrorString[strlen(cErrorString)], "O-IProtocol");
+		break;
+	case 0xb0:
+		sprintf(&cErrorString[strlen(cErrorString)], "O-ILipRcvd");
+		break;
+	case 0xc0:
+		sprintf(&cErrorString[strlen(cErrorString)], "HostControl");
+		break;
+	case 0xd0:
+		sprintf(&cErrorString[strlen(cErrorString)], "LoopFail");
+		break;
+	case 0xe0:
+		sprintf(&cErrorString[strlen(cErrorString)], "Offline");
+		break;
+	case 0xf0:
+		sprintf(&cErrorString[strlen(cErrorString)], "OldPort");
+		break;
+	case 0:
+	default:
+		sprintf(&cErrorString[strlen(cErrorString)], "Monitor");
+		break;
+
+	}
+
+	return LinkUp;
+}
 
 // Dynamic memory allocation alignment routines
 // HP's Tachyon Fibre Channel Controller chips require
@@ -1885,96 +1702,86 @@
 // we need about 8 allocations per HBA.  Figuring at most 10 HBAs per server
 // size the dynamic_mem array at 80.
 
-void* fcMemManager( struct pci_dev *pdev, ALIGNED_MEM *dynamic_mem, 
-		   ULONG n_alloc, ULONG ab, ULONG u32_AlignedAddress,
-			dma_addr_t *dma_handle)
-{
-  USHORT allocBoundary=1;   // compiler specific - worst case 1
-                                  // best case - replace malloc() call
-                                  // with function that allocates exactly
-                                  // at desired boundary
-
-  unsigned long ulAddress;
-  ULONG t_alloc, i;
-  void *alloc_address = 0;  // def. error code / address not found
-  LONG mask;                // must be 32-bits wide!
-
-  ENTER("fcMemManager");
-  if( u32_AlignedAddress )          // are we freeing existing memory?
-  {
+void *fcMemManager(struct pci_dev *pdev, ALIGNED_MEM * dynamic_mem, u32 n_alloc, u32 ab, u32 u32_AlignedAddress, dma_addr_t * dma_handle)
+{
+	u16 allocBoundary = 1;	// compiler specific - worst case 1
+	// best case - replace malloc() call
+	// with function that allocates exactly
+	// at desired boundary
+
+	unsigned long ulAddress;
+	u32 t_alloc, i;
+	void *alloc_address = 0;	// def. error code / address not found
+	s32 mask;		// must be 32-bits wide!
+
+	ENTER("fcMemManager");
+	if (u32_AlignedAddress)	// are we freeing existing memory?
+	{
 //    printk(" freeing AlignedAddress %Xh\n", u32_AlignedAddress);
-    for( i=0; i<DYNAMIC_ALLOCATIONS; i++) // look for the base address
-    {
+		for (i = 0; i < DYNAMIC_ALLOCATIONS; i++)	// look for the base address
+		{
 //    printk("dynamic_mem[%u].AlignedAddress %lX\n", i, dynamic_mem[i].AlignedAddress);
-      if( dynamic_mem[i].AlignedAddress == u32_AlignedAddress )
-      {
-        alloc_address = dynamic_mem[i].BaseAllocated; // 'success' status
-	pci_free_consistent(pdev,dynamic_mem[i].size, 
-				alloc_address, 
-				dynamic_mem[i].dma_handle);
-        dynamic_mem[i].BaseAllocated = 0;   // clear for next use
-        dynamic_mem[i].AlignedAddress = 0;
-        dynamic_mem[i].size = 0;
-        break;                        // quit for loop; done
-      }
-    }
-  }
-  else if( n_alloc )                   // want new memory?
-  {
-    dma_addr_t handle;
-    t_alloc = n_alloc + (ab - allocBoundary); // pad bytes for alignment
+			if (dynamic_mem[i].AlignedAddress == u32_AlignedAddress) {
+				alloc_address = dynamic_mem[i].BaseAllocated;	// 'success' status
+				pci_free_consistent(pdev, dynamic_mem[i].size, alloc_address, dynamic_mem[i].dma_handle);
+				dynamic_mem[i].BaseAllocated = 0;	// clear for next use
+				dynamic_mem[i].AlignedAddress = 0;
+				dynamic_mem[i].size = 0;
+				break;	// quit for loop; done
+			}
+		}
+	} else if (n_alloc)	// want new memory?
+	{
+		dma_addr_t handle;
+		t_alloc = n_alloc + (ab - allocBoundary);	// pad bytes for alignment
 //    printk("pci_alloc_consistent() for Tach alignment: %ld bytes\n", t_alloc);
 
 // (would like to) allow thread block to free pages 
-    alloc_address =                  // total bytes (NumberOfBytes)
-      pci_alloc_consistent(pdev, t_alloc, &handle); 
+		alloc_address =	// total bytes (NumberOfBytes)
+		    pci_alloc_consistent(pdev, t_alloc, &handle);
 
-                                  // now mask off least sig. bits of address
-    if( alloc_address )           // (only if non-NULL)
-    {
-                                  // find place to store ptr, so we
-                                  // can free it later...
-
-      mask = (LONG)(ab - 1);            // mask all low-order bits
-      mask = ~mask;                            // invert bits
-      for( i=0; i<DYNAMIC_ALLOCATIONS; i++) // look for free slot
-      {
-        if( dynamic_mem[i].BaseAllocated == 0) // take 1st available
-        {
-          dynamic_mem[i].BaseAllocated = alloc_address;// address from O/S
-          dynamic_mem[i].dma_handle = handle;
-	  if (dma_handle != NULL) 
-	  {
+		// now mask off least sig. bits of address
+		if (alloc_address)	// (only if non-NULL)
+		{
+			// find place to store ptr, so we
+			// can free it later...
+
+			mask = (s32) (ab - 1);	// mask all low-order bits
+			mask = ~mask;	// invert bits
+			for (i = 0; i < DYNAMIC_ALLOCATIONS; i++)	// look for free slot
+			{
+				if (dynamic_mem[i].BaseAllocated == 0)	// take 1st available
+				{
+					dynamic_mem[i].BaseAllocated = alloc_address;	// address from O/S
+					dynamic_mem[i].dma_handle = handle;
+					if (dma_handle != NULL) {
 //             printk("handle = %p, ab=%d, boundary = %d, mask=0x%08x\n", 
-//			handle, ab, allocBoundary, mask);
-	    *dma_handle = (dma_addr_t) 
-		((((ULONG)handle) + (ab - allocBoundary)) & mask);
-	  }
-          dynamic_mem[i].size = t_alloc;
-          break;
-        }
-      }
-      ulAddress = (unsigned long)alloc_address;
-      
-      ulAddress += (ab - allocBoundary);    // add the alignment bytes-
-                                            // then truncate address...
-      alloc_address = (void*)(ulAddress & mask);
-      
-      dynamic_mem[i].AlignedAddress = 
-	(ULONG)(ulAddress & mask); // 32bit Tach address
-      memset( alloc_address, 0, n_alloc );  // clear new memory
-    }
-    else  // O/S dynamic mem alloc failed!
-      alloc_address = 0;  // (for debugging breakpt)
+//                      handle, ab, allocBoundary, mask);
+						*dma_handle = (dma_addr_t)
+						    ((((u32) handle) + (ab - allocBoundary)) & mask);
+					}
+					dynamic_mem[i].size = t_alloc;
+					break;
+				}
+			}
+			ulAddress = (unsigned long) alloc_address;
+
+			ulAddress += (ab - allocBoundary);	// add the alignment bytes-
+			// then truncate address...
+			alloc_address = (void *) (ulAddress & mask);
+
+			dynamic_mem[i].AlignedAddress = (u32) (ulAddress & mask);	// 32bit Tach address
+			memset(alloc_address, 0, n_alloc);	// clear new memory
+		} else		// O/S dynamic mem alloc failed!
+			alloc_address = 0;	// (for debugging breakpt)
 
-  }
+	}
 
-  LEAVE("fcMemManager");
-  return alloc_address;  // good (or NULL) address
+	LEAVE("fcMemManager");
+	return alloc_address;	// good (or NULL) address
 }
 
 
 static Scsi_Host_Template driver_template = CPQFCTS;
 
 #include "scsi_module.c"
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfcTSioctl.h linux-2.4.21/drivers/scsi/cpqfcTSioctl.h
--- linux-2.4.20/drivers/scsi/cpqfcTSioctl.h	2001-10-25 20:53:50.000000000 +0000
+++ linux-2.4.21/drivers/scsi/cpqfcTSioctl.h	2002-12-18 18:58:01.000000000 +0000
@@ -4,71 +4,38 @@
 
 #define CCPQFCTS_IOC_MAGIC 'Z'
 
-typedef struct 
-{
-  __u8 bus;
-  __u8 dev_fn;
-  __u32 board_id;
+typedef struct {
+	__u8 bus;
+	__u8 dev_fn;
+	__u32 board_id;
 } cpqfc_pci_info_struct;
 
 typedef __u32 DriverVer_type;
-/*
-typedef union
-{
-  struct  // Peripheral Unit Device
-  { 
-    __u8 Bus:6;
-    __u8 Mode:2;  // b00
-    __u8 Dev;
-  } PeripDev;
-  struct  // Volume Set Address
-  { 
-    __u8 DevMSB:6;
-    __u8 Mode:2;  // b01
-    __u8 DevLSB;
-  } LogDev;
-  struct  // Logical Unit Device (SCSI-3, SCC-2 defined)
-  { 
-    __u8 Targ:6;
-    __u8 Mode:2;  // b10
-    __u8 Dev:5;
-    __u8 Bus:3;
-
-  } LogUnit;
-} SCSI3Addr_struct;
-
-
-typedef struct
-{
-  SCSI3Addr_struct FCP_Nexus;
-  __u8 cdb[16];
-} PassThru_Command_struct;
-*/
 
 /* this is nearly duplicated in idashare.h */
 typedef struct {
-  int	lc;    		/* Controller number */
-  int	node;		/* Node (box) number */
-  int	ld;		/* Logical Drive on this box, if required */
-  __u32 nexus;          /* SCSI Nexus */
-  void	*argp;		/* Argument pointer */
+	int lc;			/* Controller number */
+	int node;		/* Node (box) number */
+	int ld;			/* Logical Drive on this box, if required */
+	__u32 nexus;		/* SCSI Nexus */
+	void *argp;		/* Argument pointer */
 } VENDOR_IOCTL_REQ;
 
 
 typedef struct {
-  char	cdb[16];	/* SCSI CDB for the pass-through */
-  ushort bus;		/* Target bus on the box */
-  ushort pdrive;	/* Physical drive on the box */
-  int len;              /* Length of the data area of the CDB */
-  int sense_len;	/* Length of the sense data */
-  char sense_data[40];  /* Sense data */
-  void *bufp;		/* Data area for the CDB */
-  char rw_flag;		/* Read CDB or Write CDB */
+	char cdb[16];		/* SCSI CDB for the pass-through */
+	ushort bus;		/* Target bus on the box */
+	ushort pdrive;		/* Physical drive on the box */
+	int len;		/* Length of the data area of the CDB */
+	int sense_len;		/* Length of the sense data */
+	char sense_data[40];	/* Sense data */
+	void *bufp;		/* Data area for the CDB */
+	char rw_flag;		/* Read CDB or Write CDB */
 } cpqfc_passthru_t;
 
 /*
-** Defines for the IOCTLS.
-*/
+ * Defines for the IOCTLS.
+ */
 
 #define VENDOR_READ_OPCODE			0x26
 #define VENDOR_WRITE_OPCODE			0x27
@@ -78,17 +45,22 @@
 
 #define CPQFCTS_SCSI_PASSTHRU _IOWR( CCPQFCTS_IOC_MAGIC,11, VENDOR_IOCTL_REQ)
 
-/* We would rather have equivalent generic, low-level driver agnostic 
-ioctls that do what CPQFC_IOCTL_FC_TARGET_ADDRESS and 
-CPQFC_IOCTL_FC_TDR 0x5388 do, but currently, we do not have them, 
-consequently applications would have to know they are talking to cpqfc. */
-   
-/* Used to get Fibre Channel WWN and port_id from device */
-// #define CPQFC_IOCTL_FC_TARGET_ADDRESS 0x5387
+/*
+ *	We would rather have equivalent generic, low-level driver agnostic 
+ *	ioctls that do what CPQFC_IOCTL_FC_TARGET_ADDRESS and 
+ *	CPQFC_IOCTL_FC_TDR 0x5388 do, but currently, we do not have them, 
+ *	consequently applications would have to know they are talking to cpqfc.
+ */
+
+/*
+ *	Used to get Fibre Channel WWN and port_id from device
+ */
+
 #define CPQFC_IOCTL_FC_TARGET_ADDRESS \
 	_IOR( CCPQFCTS_IOC_MAGIC, 13, Scsi_FCTargAddress)
 
-/* Used to invoke Target Defice Reset for Fibre Channel */
-// #define CPQFC_IOCTL_FC_TDR 0x5388
+/*
+ *	Used to invoke Target Defice Reset for Fibre Channel
+ */
+ 
 #define CPQFC_IOCTL_FC_TDR _IO( CCPQFCTS_IOC_MAGIC, 15)
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfcTSstructs.h linux-2.4.21/drivers/scsi/cpqfcTSstructs.h
--- linux-2.4.20/drivers/scsi/cpqfcTSstructs.h	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/scsi/cpqfcTSstructs.h	2002-12-18 18:58:07.000000000 +0000
@@ -17,77 +17,83 @@
  * General Public License for more details.
  * Written by Don Zimmerman
 */
+
 #ifndef CPQFCTSSTRUCTS_H
 #define CPQFCTSSTRUCTS_H
 
-#include <linux/timer.h>  // timer declaration in our host data
-#include <linux/tqueue.h> // task queue sched
+#include <linux/timer.h>	// timer declaration in our host data
+#include <linux/tqueue.h>	// task queue sched
 #include <asm/atomic.h>
 #include "cpqfcTSioctl.h"
 
+/* FIXME - this is crap */
 #define DbgDelay(secs) { int wait_time; printk( " DbgDelay %ds ", secs); \
                          for( wait_time=jiffies + (secs*HZ); \
 		         time_before(jiffies, wait_time) ;) ; }
 
 #define CPQFCTS_DRIVER_VER(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-// don't forget to also change MODULE_DESCRIPTION in cpqfcTSinit.c
+/* don't forget to also change MODULE_DESCRIPTION in cpqfcTSinit.c */
 #define VER_MAJOR 2
 #define VER_MINOR 1
-#define VER_SUBMINOR 1
+#define VER_SUBMINOR 2
 
-// Macros for kernel (esp. SMP) tracing using a PCI analyzer
-// (e.g. x86).
+/*
+ *	Macros for kernel (esp. SMP) tracing using a PCI analyzer
+ *	(e.g. x86).
+ */
+ 
 //#define PCI_KERNEL_TRACE
 #ifdef PCI_KERNEL_TRACE
-#define PCI_TRACE(x) inl( fcChip->Registers.IOBaseL +x);
-#define PCI_TRACEO(x,y) outl( x, (fcChip->Registers.IOBaseL +y));
+#define PCI_TRACE(x)		inl( fcChip->Registers.IOBaseL +x);
+#define PCI_TRACEO(x,y) 	outl( x, (fcChip->Registers.IOBaseL +y));
 #else
 
-#define PCI_TRACE(x) 
+#define PCI_TRACE(x)
 #define PCI_TRACEO(x,y)
 #endif
 
-			 
-//#define DEBUG_CMND 1   // debug output for Linux Scsi CDBs
-//#define DUMMYCMND_DBG 1
+
+//#define DEBUG_CMND		1   // debug output for Linux Scsi CDBs
+//#define DUMMYCMND_DBG		1
 
 //#define DEBUG_CPQFCTS 1
 //#undef DEBUG_CPQFCTS 
 #ifdef DEBUG_CPQFCTS
-#define ENTER(x)	printk("cpqfcts : entering %s()\n", x);
-#define LEAVE(x)	printk("cpqfcts : leaving %s()\n", x);
-#define DEBUG(x)	x
+#define ENTER(x)		printk("cpqfcts : entering %s()\n", x);
+#define LEAVE(x)		printk("cpqfcts : leaving %s()\n", x);
+#define DEBUG(x)		x
 #else
 #define ENTER(x)
 #define LEAVE(x)
 #define DEBUG(x)
 #endif				/* DEBUG_CPQFCTS */
 
-//#define DEBUG_CPQFCTS_PCI 1
+//#define DEBUG_CPQFCTS_PCI	1
 //#undef DEBUG_CPQFCTS_PCI
 #if DEBUG_CPQFCTS_PCI
-#define DEBUG_PCI(x)	x
+#define DEBUG_PCI(x)		x
 #else
 #define DEBUG_PCI(x)
 #endif				/* DEBUG_CPQFCTS_PCI */
 
-#define STACHLITE66_TS12  "Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.2"
-#define STACHLITE66_TS13  "Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.3"
-#define STACHLITE_UNKNOWN "Compaq FibreChannel HBA Tachyon Chip/Board Ver??"
-#define SAGILENT_XL2_21   "Agilent FC HBA, Tachyon XL2 HPFC-5200B/2.1"
+#define STACHLITE66_TS12	"Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.2"
+#define STACHLITE66_TS13	"Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.3"
+#define STACHLITE_UNKNOWN	"Compaq FibreChannel HBA Tachyon Chip/Board Ver??"
+#define SAGILENT_XL2_21		"Agilent FC HBA, Tachyon XL2 HPFC-5200B/2.1"
 
 // PDA is Peripheral Device Address, VSA is Volume Set Addressing
 // Linux SCSI parameters
-#define CPQFCTS_MAX_TARGET_ID 64
+#define CPQFCTS_MAX_TARGET_ID	64
 
 // Note, changing CPQFCTS_MAX_LUN to less than 32 (e.g, 8) will result in
 // strange behavior if a box with more than, e.g. 8, is on the loop.
-#define CPQFCTS_MAX_LUN 32    // The RA-4x00 supports 32 (Linux SCSI supports 8)
-#define CPQFCTS_MAX_CHANNEL 0 // One FC port on cpqfcTS HBA
+#define CPQFCTS_MAX_LUN		32	// The RA-4x00 supports 32 (Linux SCSI supports 8)
+#define CPQFCTS_MAX_CHANNEL 	0	// One FC port on cpqfcTS HBA
 
-#define CPQFCTS_CMD_PER_LUN 15 // power of 2 -1, must be >0 
-#define CPQFCTS_REQ_QUEUE_LEN (TACH_SEST_LEN/2) // must be < TACH_SEST_LEN
+#define CPQFCTS_CMD_PER_LUN	15	// power of 2 -1, must be >0
+#define CPQFCTS_REQ_QUEUE_LEN	(TACH_SEST_LEN/2)	// must be < TACH_SEST_LEN
 
+/* FIMXME - these are crpa too */
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 #ifndef DECLARE_MUTEX_LOCKED
 #define DECLARE_MUTEX_LOCKED(sem) struct semaphore sem = MUTEX_LOCKED
@@ -95,205 +101,194 @@
 
 #define DEV_NAME "cpqfcTS"
 
-struct SupportedPCIcards
-{
-  __u16 vendor_id;
-  __u16 device_id;
+struct SupportedPCIcards {
+	__u16 vendor_id;
+	__u16 device_id;
 };
-			 
-// nn:nn denotes bit field
-                            // TachyonHeader struct def.
-                            // the fields shared with ODB
-                            // need to have same value
-
-
-
-
-#ifndef BYTE
-//typedef UCHAR BYTE;
-typedef __u8 BYTE;
-#endif
-#ifndef UCHAR
-typedef __u8 UCHAR;
-#endif
-#ifndef LONG
-typedef __s32 LONG;
-#endif
-#ifndef ULONG
-typedef __u32 ULONG;
-#endif
-#ifndef PVOID
-typedef void * PVOID;
-#endif
-#ifndef USHORT
-typedef __u16 USHORT;
-#endif
-#ifndef BOOLEAN
-typedef __u8 BOOLEAN;
-#endif
-
-
-// macro for FC-PH reject codes
-// payload format for LS_RJT (FC payloads are big endian):
-//     byte  0         1         2         3  (MSB)
-// DWORD 0   01        00        00        00
-// DWORD 1   resvd     code      expl.     vendor
 
+/*
+ *	nn:nn denotes bit field
+ *	TachyonHeader struct def.
+ *	the fields shared with ODB
+ *	need to have same value
+ */
+ 
+/*
+ * macro for FC-PH reject codes
+ * payload format for LS_RJT (FC payloads are big endian):
+ *     byte  0         1         2         3  (MSB)
+ * DWORD 0   01        00        00        00
+ * DWORD 1   resvd     code      expl.     vendor
+ */
 #define LS_RJT_REASON( code, expl) (( code<<8) | (expl <<16))
 
-
 #define TachLiteSTATUS 0x12
 
-// Fibre Channel EXCHANGE status codes for Tachyon chips/ driver software
-// 32-bit ERROR word defines
-#define INVALID_ARGS 0x1
-#define LNKDWN_OSLS  0x2
-#define LNKDWN_LASER 0x4
-#define OUTQUE_FULL  0x8
-#define DRIVERQ_FULL 0x10
-#define SEST_FULL    0x20
-#define BAD_ALPA     0x40
-#define OVERFLOW     0x80  // inbound CM
-#define COUNT_ERROR     0x100  // inbound CM
-#define LINKFAIL_RX     0x200  // inbound CM
-#define ABORTSEQ_NOTIFY 0x400  // outbound CM
-#define LINKFAIL_TX     0x800  // outbound CM
-#define HOSTPROG_ERR     0x1000  // outbound CM
-#define FRAME_TO         0x2000  // outbound CM
-#define INV_ENTRY        0x4000  // outbound CM
-#define SESTPROG_ERR     0x8000  // outbound CM
-#define OUTBOUND_TIMEOUT 0x10000L // timeout waiting for Tachyon outbound CM
-#define INITIATOR_ABORT  0x20000L // initiator exchange timeout or O/S ABORT
-#define MEMPOOL_FAIL     0x40000L // O/S memory pool allocation failed
-#define FC2_TIMEOUT      0x80000L // driver timeout for lost frames
-#define TARGET_ABORT     0x100000L // ABTS received from FC port
-#define EXCHANGE_QUEUED  0x200000L // e.g. Link State was LDn on fcStart
-#define PORTID_CHANGED   0x400000L // fc Port address changed
-#define DEVICE_REMOVED   0x800000L // fc Port address changed
-// Several error scenarios result in SEST Exchange frames 
-// unexpectedly arriving in the SFQ
-#define SFQ_FRAME        0x1000000L // SFQ frames from open Exchange
-
-// Maximum number of Host Bus Adapters (HBA) / controllers supported
-// only important for mem allocation dimensions - increase as necessary
-
+/*
+ *	Fibre Channel EXCHANGE status codes for Tachyon chips/ driver software
+ *	32-bit ERROR word defines
+ */
+#define INVALID_ARGS 		0x1
+#define LNKDWN_OSLS  		0x2
+#define LNKDWN_LASER 		0x4
+#define OUTQUE_FULL  		0x8
+#define DRIVERQ_FULL 		0x10
+#define SEST_FULL    		0x20
+#define BAD_ALPA     		0x40
+#define OVERFLOW     		0x80		// inbound CM
+#define COUNT_ERROR     	0x100		// inbound CM
+#define LINKFAIL_RX     	0x200		// inbound CM
+#define ABORTSEQ_NOTIFY 	0x400		// outbound CM
+#define LINKFAIL_TX     	0x800		// outbound CM
+#define HOSTPROG_ERR     	0x1000		// outbound CM
+#define FRAME_TO         	0x2000		// outbound CM
+#define INV_ENTRY        	0x4000		// outbound CM
+#define SESTPROG_ERR     	0x8000		// outbound CM
+#define OUTBOUND_TIMEOUT 	0x10000L	// timeout waiting for Tachyon outbound CM
+#define INITIATOR_ABORT  	0x20000L	// initiator exchange timeout or O/S ABORT
+#define MEMPOOL_FAIL     	0x40000L	// O/S memory pool allocation failed
+#define FC2_TIMEOUT      	0x80000L	// driver timeout for lost frames
+#define TARGET_ABORT     	0x100000L	// ABTS received from FC port
+#define EXCHANGE_QUEUED  	0x200000L	// e.g. Link State was LDn on fcStart
+#define PORTID_CHANGED   	0x400000L	// fc Port address changed
+#define DEVICE_REMOVED   	0x800000L	// fc Port address changed
+/*
+ *	Several error scenarios result in SEST Exchange frames 
+ *	unexpectedly arriving in the SFQ
+ */
+#define SFQ_FRAME		0x1000000L	// SFQ frames from open Exchange
+
+/*
+ *	Maximum number of Host Bus Adapters (HBA) / controllers supported
+ *	only important for mem allocation dimensions - increase as necessary
+ */
+ 
 #define MAX_ADAPTERS 8
-#define MAX_RX_PAYLOAD 1024  // hardware dependent max frame payload
-// Tach header struc defines
-#define SOFi3 0x7
-#define SOFf  0x8
-#define SOFn3 0xB
-#define EOFn  0x5
-#define EOFt  0x6
+#define MAX_RX_PAYLOAD 1024			// hardware dependent max frame payload
+
+/*
+ *	Tach header struct defines
+ */
+
+#define SOFi3			0x7
+#define SOFf			0x8
+#define SOFn3			0xB
+#define EOFn			0x5
+#define EOFt			0x6
 
 // FCP R_CTL defines
-#define FCP_CMND 0x6
-#define FCP_XFER_RDY 0x5
-#define FCP_RSP 0x7
-#define FCP_RESPONSE 0x777 // (arbitrary #)
-#define NEED_FCP_RSP 0x77  // (arbitrary #)
-#define FCP_DATA 0x1
-
-#define RESET_TACH 0x100 // Reset Tachyon/TachLite
-#define SCSI_IWE 0x2000  // initiator write entry (for SEST)
-#define SCSI_IRE 0x3000  // initiator read entry (for SEST)
-#define SCSI_TRE 0x400  // target read entry (for SEST)
-#define SCSI_TWE 0x500  // target write entry (for SEST)
-#define TOGGLE_LASER 0x800
-#define LIP 0x900
-#define CLEAR_FCPORTS 99 // (arbitrary #) free mem for Logged in ports
-#define FMINIT 0x707     // (arbitrary) for Frame Manager Init command
-
-// BLS == Basic Link Service
-// ELS == Extended Link Service
-#define BLS_NOP 4
-#define BLS_ABTS 0x10   // FC-PH Basic Link Service Abort Sequence
-#define BLS_ABTS_ACC 0x100  // FC-PH Basic Link Service Abort Sequence Accept
-#define BLS_ABTS_RJT 0x101  // FC-PH Basic Link Service Abort Sequence Reject
-#define ELS_PLOGI 0x03  // FC-PH Port Login (arbitrary assign)
-#define ELS_SCR   0x70  // (arb assign) State Change Registration (Fabric)
-#define FCS_NSR   0x72  // (arb assign) Name Service Request (Fabric)
-#define ELS_FLOGI 0x44  // (arb assign) Fabric Login
-#define ELS_FDISC 0x41  // (arb assign) Fabric Discovery (Login)
-#define ELS_PDISC 0x50  // FC-PH2 Port Discovery
-#define ELS_ABTX  0x06  // FC-PH Abort Exchange 
-#define ELS_LOGO 0x05   // FC-PH Port Logout
-#define ELS_PRLI 0x20   // FCP-SCSI Process Login
-#define ELS_PRLO 0x21   // FCP-SCSI Process Logout
-#define ELS_LOGO_ACC 0x07   // {FC-PH} Port Logout Accept
-#define ELS_PLOGI_ACC 0x08  // {FC-PH} Port Login Accept
-#define ELS_ACC 0x18        // {FC-PH} (generic) ACCept
-#define ELS_PRLI_ACC 0x22  // {FCP-SCSI} Process Login Accept
-#define ELS_RJT 0x1000000
-#define SCSI_REPORT_LUNS 0x0A0
-#define REPORT_LUNS 0xA0 // SCSI-3 command op-code
-#define FCP_TARGET_RESET 0x200
-
-#define ELS_LILP_FRAME 0x00000711 // 1st payload word of LILP frame
-
-#define SFQ_UNASSISTED_FCP  1  // ICM, DWord3, "Type" unassisted FCP
-#define SFQ_UNKNOWN         0x31 // (arbitrary) ICM, DWord3, "Type" unknown
-
-// these "LINK" bits refer to loop or non-loop
-#define LINKACTIVE 0x2    // fcLinkQ type - LINK UP Tachyon FM 'Lup' bit set
-#define LINKDOWN 0xf2     // fcLinkQ type - LINK DOWN Tachyon FM 'Ldn' bit set
+#define FCP_CMND		0x6
+#define FCP_XFER_RDY		0x5
+#define FCP_RSP			0x7
+#define FCP_RESPONSE		0x777		// (arbitrary #)
+#define NEED_FCP_RSP		0x77		// (arbitrary #)
+#define FCP_DATA		0x1
+
+#define RESET_TACH 		0x100		// Reset Tachyon/TachLite
+#define SCSI_IWE 		0x2000		// initiator write entry (for SEST)
+#define SCSI_IRE 		0x3000		// initiator read entry (for SEST)
+#define SCSI_TRE 		0x400		// target read entry (for SEST)
+#define SCSI_TWE 		0x500		// target write entry (for SEST)
+#define TOGGLE_LASER 		0x800
+#define LIP			0x900
+#define CLEAR_FCPORTS		99		// (arbitrary #) free mem for Logged in ports
+#define FMINIT			0x707		// (arbitrary) for Frame Manager Init command
+
+/*
+ *	BLS == Basic Link Service
+ *	ELS == Extended Link Service
+ */
+ 
+#define BLS_NOP 		4
+#define BLS_ABTS		0x10		// FC-PH Basic Link Service Abort Sequence
+#define BLS_ABTS_ACC		0x100		// FC-PH Basic Link Service Abort Sequence Accept
+#define BLS_ABTS_RJT		0x101		// FC-PH Basic Link Service Abort Sequence Reject
+#define ELS_PLOGI		0x03		// FC-PH Port Login (arbitrary assign)
+#define ELS_SCR			0x70		// (arb assign) State Change Registration (Fabric)
+#define FCS_NSR			0x72		// (arb assign) Name Service Request (Fabric)
+#define ELS_FLOGI		0x44		// (arb assign) Fabric Login
+#define ELS_FDISC		0x41		// (arb assign) Fabric Discovery (Login)
+#define ELS_PDISC		0x50		// FC-PH2 Port Discovery
+#define ELS_ABTX		0x06		// FC-PH Abort Exchange
+#define ELS_LOGO		0x05		// FC-PH Port Logout
+#define ELS_PRLI		0x20		// FCP-SCSI Process Login
+#define ELS_PRLO		0x21		// FCP-SCSI Process Logout
+#define ELS_LOGO_ACC		0x07		// {FC-PH} Port Logout Accept
+#define ELS_PLOGI_ACC		0x08		// {FC-PH} Port Login Accept
+#define ELS_ACC			0x18		// {FC-PH} (generic) ACCept
+#define ELS_PRLI_ACC		0x22		// {FCP-SCSI} Process Login Accept
+#define ELS_RJT			0x1000000
+#define SCSI_REPORT_LUNS	0x0A0
+#define REPORT_LUNS		0xA0		// SCSI-3 command op-code
+#define FCP_TARGET_RESET	0x200
+
+#define ELS_LILP_FRAME		0x00000711	// 1st payload word of LILP frame
+
+#define SFQ_UNASSISTED_FCP	1		// ICM, DWord3, "Type" unassisted FCP
+#define SFQ_UNKNOWN      	0x31		// (arbitrary) ICM, DWord3, "Type" unknown
+
+/*
+ * These "LINK" bits refer to loop or non-loop
+ */
+#define LINKACTIVE		0x2		// fcLinkQ type - LINK UP Tachyon FM 'Lup' bit set
+#define LINKDOWN		0xf2		// fcLinkQ type - LINK DOWN Tachyon FM 'Ldn' bit set
 
 //#define VOLUME_SET_ADDRESSING 1 // "channel" or "bus" 1
 
-typedef struct      // 32 bytes hdr ONLY (e.g. FCP_DATA buffer for SEST)
+typedef struct			// 32 bytes hdr ONLY (e.g. FCP_DATA buffer for SEST)
 {
-  ULONG reserved;   // dword 0 (don't use)
-  ULONG sof_eof;
-  ULONG d_id;       // dword 2 - 31:24 R_CTL, 23:0 D_ID
-  ULONG s_id;       // dword 3 - 31:24 CS_CTL, 23:0 S_ID
-  ULONG f_ctl;      // dword 4 - 31:24 Type,  23:0 F_CTL
-  ULONG seq_cnt;    // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
-  ULONG ox_rx_id;   // dword 6 - 31:16 OX_ID,  15:0 RX_ID
-  ULONG ro;         // dword 7 - relative offset
+	__u32 reserved;		// dword 0 (don't use)
+	__u32 sof_eof;
+	__u32 d_id;		// dword 2 - 31:24 R_CTL, 23:0 D_ID
+	__u32 s_id;		// dword 3 - 31:24 CS_CTL, 23:0 S_ID
+	__u32 f_ctl;		// dword 4 - 31:24 Type,  23:0 F_CTL
+	__u32 seq_cnt;		// dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
+	__u32 ox_rx_id;		// dword 6 - 31:16 OX_ID,  15:0 RX_ID
+	__u32 ro;		// dword 7 - relative offset
 } TachFCHDR;
 
-                    // NOTE!! the following struct MUST be 64 bytes.
-typedef struct      // 32 bytes hdr + 32 bytes payload
+				// NOTE!! the following struct MUST be 64 bytes.
+typedef struct			// 32 bytes hdr + 32 bytes payload
 {
-  ULONG reserved;   // dword 0 (don't use - must clear to 0)
-  ULONG sof_eof;    // dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp
-  ULONG d_id;       // dword 2 - 31:24 R_CTL, 23:0 D_ID
-  ULONG s_id;       // dword 3 - 31:24 CS_CTL, 23:0 S_ID
-  ULONG f_ctl;      // dword 4 - 31:24 Type,  23:0 F_CTL
-  ULONG seq_cnt;    // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
-  ULONG ox_rx_id;   // dword 6 - 31:16 OX_ID,  15:0 RX_ID
-  ULONG ro;  // dword 7 - relative offset
+	__u32 reserved;		// dword 0 (don't use - must clear to 0)
+	__u32 sof_eof;		// dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp
+	__u32 d_id;		// dword 2 - 31:24 R_CTL, 23:0 D_ID
+	__u32 s_id;		// dword 3 - 31:24 CS_CTL, 23:0 S_ID
+	__u32 f_ctl;		// dword 4 - 31:24 Type,  23:0 F_CTL
+	__u32 seq_cnt;		// dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
+	__u32 ox_rx_id;		// dword 6 - 31:16 OX_ID,  15:0 RX_ID
+	__u32 ro;		// dword 7 - relative offset
 //---------
-  __u32 pl[8];              // dwords 8-15 frame data payload
+	__u32 pl[8];		// dwords 8-15 frame data payload
 } TachFCHDR_CMND;
 
 
-typedef struct      // 32 bytes hdr + 120 bytes payload
+typedef struct			// 32 bytes hdr + 120 bytes payload
 {
-  ULONG reserved;   // dword 0 (don't use - must clear to 0)
-  ULONG sof_eof;    // dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp
-  ULONG d_id;       // dword 2 - 31:24 R_CTL, 23:0 D_ID
-  ULONG s_id;       // dword 3 - 31:24 CS_CTL, 23:0 S_ID
-  ULONG f_ctl;      // dword 4 - 31:24 Type,  23:0 F_CTL
-  ULONG seq_cnt;    // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
-  ULONG ox_rx_id;   // dword 6 - 31:16 OX_ID,  15:0 RX_ID
-  ULONG ro;  // dword 7 - relative offset
+	__u32 reserved;		// dword 0 (don't use - must clear to 0)
+	__u32 sof_eof;		// dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp
+	__u32 d_id;		// dword 2 - 31:24 R_CTL, 23:0 D_ID
+	__u32 s_id;		// dword 3 - 31:24 CS_CTL, 23:0 S_ID
+	__u32 f_ctl;		// dword 4 - 31:24 Type,  23:0 F_CTL
+	__u32 seq_cnt;		// dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
+	__u32 ox_rx_id;		// dword 6 - 31:16 OX_ID,  15:0 RX_ID
+	__u32 ro;		// dword 7 - relative offset
 //---------
-  __u32 pl[30];              // largest necessary payload (for LOGIN cmnds)
+	__u32 pl[30];		// largest necessary payload (for LOGIN cmnds)
 } TachFCHDR_GCMND;
 
-typedef struct      // 32 bytes hdr + 64 bytes payload
+typedef struct			// 32 bytes hdr + 64 bytes payload
 {
-  ULONG reserved;   // dword 0 (don't use)
-  ULONG sof_eof;
-  ULONG d_id;       // dword 2 - 31:24 R_CTL, 23:0 D_ID
-  ULONG s_id;       // dword 3 - 31:24 CS_CTL, 23:0 S_ID
-  ULONG f_ctl;      // dword 4 - 31:24 Type,  23:0 F_CTL
-  ULONG seq_cnt;    // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
-  ULONG ox_rx_id;   // dword 6 - 31:16 OX_ID,  15:0 RX_ID
-  ULONG ro;  // dword 7 - relative offset
+	__u32 reserved;		// dword 0 (don't use)
+	__u32 sof_eof;
+	__u32 d_id;		// dword 2 - 31:24 R_CTL, 23:0 D_ID
+	__u32 s_id;		// dword 3 - 31:24 CS_CTL, 23:0 S_ID
+	__u32 f_ctl;		// dword 4 - 31:24 Type,  23:0 F_CTL
+	__u32 seq_cnt;		// dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
+	__u32 ox_rx_id;		// dword 6 - 31:16 OX_ID,  15:0 RX_ID
+	__u32 ro;		// dword 7 - relative offset
 //---------
-  __u32 pl[18]; // payload for FCP-RSP (response buffer) RA-4x00 is 72bytes
+	__u32 pl[18];		// payload for FCP-RSP (response buffer) RA-4x00 is 72bytes
 } TachFCHDR_RSP;
 
 
@@ -302,11 +297,11 @@
 
 
 // Inbound Message Queue structures...
-typedef struct              // each entry 8 words (32 bytes)
+typedef struct			// each entry 8 words (32 bytes)
 {
-  ULONG type;               // IMQ completion message types
-  ULONG word[7];            // remainder of structure
-                            // interpreted by IMQ type
+	__u32 type;		// IMQ completion message types
+	__u32 word[7];		// remainder of structure
+				// interpreted by IMQ type
 } TachyonIMQE;
 
 
@@ -314,114 +309,114 @@
 // ERQ       - Exchange Request Queue (for outbound commands)
 // SFQ       - Single Frame Queue (for incoming frames)
 
-                            // Define Tachyon Outbound Command Que
-                            // (Since many Tachyon registers are Read
-                            // only, maintain copies for debugging)
-                            // most Tach ques need power-of-2 sizes,
-                            // where registers are loaded with po2 -1
-#define TACH_SEST_LEN 512   // TachLite SEST
+				// Define Tachyon Outbound Command Que
+				// (Since many Tachyon registers are Read
+				// only, maintain copies for debugging)
+				// most Tach ques need power-of-2 sizes,
+				// where registers are loaded with po2 -1
+#define TACH_SEST_LEN 512	// TachLite SEST
 
-#define ELS_EXCHANGES 64    // e.g. PLOGI, RSCN, ...
+#define ELS_EXCHANGES 64	// e.g. PLOGI, RSCN, ...
 // define the total number of outstanding (simultaneous) exchanges
-#define TACH_MAX_XID (TACH_SEST_LEN + ELS_EXCHANGES)  // ELS exchanges
+#define TACH_MAX_XID (TACH_SEST_LEN + ELS_EXCHANGES)	// ELS exchanges
 
-#define ERQ_LEN 128         // power of 2, max 4096
+#define ERQ_LEN 128		// power of 2, max 4096
 
 // Inbound Message Queue structures...
-#define IMQ_LEN 512              // minimum 4 entries [(power of 2) - 1]
-typedef struct                   // 8 words - 32 bytes
+#define IMQ_LEN 512		// minimum 4 entries [(power of 2) - 1]
+typedef struct			// 8 words - 32 bytes
 {
-  TachyonIMQE QEntry[IMQ_LEN];
-  ULONG producerIndex;   // IMQ Producer Index register
-                                 // @32 byte align
-  ULONG consumerIndex;   // Consumer Index register (in Tachyon)
-  ULONG length;          // Length register
-  ULONG base;
-} TachyonIMQ;                    // @ 32 * IMQ_LEN align
+	TachyonIMQE QEntry[IMQ_LEN];
+	__u32 producerIndex;	// IMQ Producer Index register
+	// @32 byte align
+	__u32 consumerIndex;	// Consumer Index register (in Tachyon)
+	__u32 length;		// Length register
+	__u32 base;
+} TachyonIMQ;			// @ 32 * IMQ_LEN align
 
 
 
-typedef struct           // inbound completion message
+typedef struct			// inbound completion message
 {
-  ULONG Type;
-  ULONG Index;
-  ULONG TransferLength;
+	__u32 Type;
+	__u32 Index;
+	__u32 TransferLength;
 } TachyonInbCM;
 
 
 
 // arbitrary numeric tags for TL structures
-#define TL_FCHS 1  // TachLite Fibre Channel Header Structure
-#define TL_IWE 2  // initiator write entry (for SEST)
-#define TL_TWE 3  // target write entry (for SEST)
-#define TL_IRE 4  // initiator read entry (for SEST)
-#define TL_TRE 5  // target read entry (for SEST)
-#define TL_IRB 6  // I/O request block
-
-                                // for INCOMING frames
-#define SFQ_LEN 32              // minimum 32 entries, max 4096
-
-typedef struct                  // Single Frame Que
-{
-  TachFCHDR_CMND QEntry[SFQ_LEN]; // must be 64 bytes!!
-  ULONG producerIndex;   // IMQ Producer Index register
-                                 // @32 byte align
-  ULONG consumerIndex;   // Consumer Index register (in Tachyon)
-  ULONG length;          // Length register
-  ULONG base;
+#define TL_FCHS 1		// TachLite Fibre Channel Header Structure
+#define TL_IWE 2		// initiator write entry (for SEST)
+#define TL_TWE 3		// target write entry (for SEST)
+#define TL_IRE 4		// initiator read entry (for SEST)
+#define TL_TRE 5		// target read entry (for SEST)
+#define TL_IRB 6		// I/O request block
+
+				// for INCOMING frames
+#define SFQ_LEN 32		// minimum 32 entries, max 4096
+
+typedef struct			// Single Frame Que
+{
+	TachFCHDR_CMND QEntry[SFQ_LEN];	// must be 64 bytes!!
+	__u32 producerIndex;	// IMQ Producer Index register
+	// @32 byte align
+	__u32 consumerIndex;	// Consumer Index register (in Tachyon)
+	__u32 length;		// Length register
+	__u32 base;
 } TachLiteSFQ;
 
 
-typedef struct                 // I/O Request Block flags
+typedef struct			// I/O Request Block flags
 {
-  UCHAR  BRD : 1;
-  UCHAR      : 1; // reserved
-  UCHAR  SFA : 1;
-  UCHAR  DNC : 1;
-  UCHAR  DIN : 1;
-  UCHAR  DCM : 1;
-  UCHAR  CTS : 1;
-  UCHAR  SBV : 1;  // IRB entry valid - IRB'B' only
+	__u8 BRD:1;
+	 __u8:1;		// reserved
+	__u8 SFA:1;
+	__u8 DNC:1;
+	__u8 DIN:1;
+	__u8 DCM:1;
+	__u8 CTS:1;
+	__u8 SBV:1;		// IRB entry valid - IRB'B' only
 } IRBflags;
 
-typedef struct                  // I/O Request Block
-{                          // Request 'A'
-  ULONG Req_A_SFS_Len;     // total frame len (hdr + payload), min 32
-  ULONG Req_A_SFS_Addr;    // 32-bit pointer to FCHS struct (to be sent)
-  ULONG Req_A_SFS_D_ID;    // 24-bit FC destination (i.e. 8 bit al_pa)
-  ULONG Req_A_Trans_ID;    // X_ID (OX_ID or RX_ID) and/or Index in SEST
-                           // Request 'B'
-  ULONG Req_B_SFS_Len;     // total frame len (hdr + payload), min 32
-  ULONG Req_B_SFS_Addr;    // 32-bit pointer to FCHS struct (to be sent)
-  ULONG Req_B_SFS_D_ID;    // 24-bit FC destination (i.e. 8 bit al_pa)
-  ULONG Req_B_Trans_ID;    // X_ID (OX_ID or RX_ID) and/or Index in SEST
+typedef struct			// I/O Request Block
+{				// Request 'A'
+	__u32 Req_A_SFS_Len;	// total frame len (hdr + payload), min 32
+	__u32 Req_A_SFS_Addr;	// 32-bit pointer to FCHS struct (to be sent)
+	__u32 Req_A_SFS_D_ID;	// 24-bit FC destination (i.e. 8 bit al_pa)
+	__u32 Req_A_Trans_ID;	// X_ID (OX_ID or RX_ID) and/or Index in SEST
+	// Request 'B'
+	__u32 Req_B_SFS_Len;	// total frame len (hdr + payload), min 32
+	__u32 Req_B_SFS_Addr;	// 32-bit pointer to FCHS struct (to be sent)
+	__u32 Req_B_SFS_D_ID;	// 24-bit FC destination (i.e. 8 bit al_pa)
+	__u32 Req_B_Trans_ID;	// X_ID (OX_ID or RX_ID) and/or Index in SEST
 } TachLiteIRB;
 
 
-typedef struct           // TachLite placeholder for IRBs
-{                        // aligned @sizeof(ERQ) for TachLite
-                         // MAX commands is sum of SEST len and ERQ
-                         // we know that each SEST entry requires an
-                         // IRB (ERQ) entry; in addition, we provide
-                         // ERQ_LEN
-  TachLiteIRB QEntry[ERQ_LEN]; // Base register; entries 32 bytes ea.
-  ULONG consumerIndex;   // Consumer Index register
-  ULONG producerIndex;   // ERQ Producer Index register
-  ULONG length;          // Length register
-  ULONG base;            // copy of base ptr for debug
-                         // struct is sized for largest expected cmnd (LOGIN)
+typedef struct			// TachLite placeholder for IRBs
+{				// aligned @sizeof(ERQ) for TachLite
+	// MAX commands is sum of SEST len and ERQ
+	// we know that each SEST entry requires an
+	// IRB (ERQ) entry; in addition, we provide
+	// ERQ_LEN
+	TachLiteIRB QEntry[ERQ_LEN];	// Base register; entries 32 bytes ea.
+	__u32 consumerIndex;	// Consumer Index register
+	__u32 producerIndex;	// ERQ Producer Index register
+	__u32 length;		// Length register
+	__u32 base;		// copy of base ptr for debug
+	// struct is sized for largest expected cmnd (LOGIN)
 } TachLiteERQ;
 
 // for now, just 32 bit DMA, eventually 40something, with code changes
 #define CPQFCTS_DMA_MASK ((unsigned long) (0x00000000FFFFFFFF))
 
-#define TL_MAX_SG_ELEM_LEN 0x7ffff  // Max buffer length a single S/G entry
-				// may represent (a hardware limitation).  The
-				// only reason to ever change this is if you
-				// want to exercise very-hard-to-reach code in
-				// cpqfcTSworker.c:build_SEST_sglist().
+#define TL_MAX_SG_ELEM_LEN 0x7ffff	// Max buffer length a single S/G entry
+					// may represent (a hardware limitation).  The
+					// only reason to ever change this is if you
+					// want to exercise very-hard-to-reach code in
+					// cpqfcTSworker.c:build_SEST_sglist().
 
-#define TL_DANGER_SGPAGES 7  // arbitrary high water mark for # of S/G pages
+#define TL_DANGER_SGPAGES 7	// arbitrary high water mark for # of S/G pages
 				// we must exceed to elicit a warning indicative
 				// of EXTREMELY large data transfers or 
 				// EXTREME memory fragmentation.
@@ -429,236 +424,230 @@
 				// Never seen this is real life, only in 
 				// testing with tricked up driver.)
 
-#define TL_EXT_SG_PAGE_COUNT 256  // Number of Extended Scatter/Gather a/l PAIRS
-                                  // Tachyon register (IOBaseU 0x68)
-                                  // power-of-2 value ONLY!  4 min, 256 max
+#define TL_EXT_SG_PAGE_COUNT 256	// Number of Extended Scatter/Gather a/l PAIRS
+					// Tachyon register (IOBaseU 0x68)
+					// power-of-2 value ONLY!  4 min, 256 max
 
-                          // byte len is #Pairs * 2 ULONG/Pair * 4 bytes/ULONG
+			  // byte len is #Pairs * 2 __u32/Pair * 4 bytes/__u32
 #define TL_EXT_SG_PAGE_BYTELEN (TL_EXT_SG_PAGE_COUNT *2 *4)
 
 
 
 // SEST entry types: IWE, IRE, TWE, TRE
-typedef struct 
-{
-  ULONG Hdr_Len;
-  ULONG Hdr_Addr;
-  ULONG RSP_Len;
-  ULONG RSP_Addr;
-  ULONG Buff_Off;
+typedef struct {
+	__u32 Hdr_Len;
+	__u32 Hdr_Addr;
+	__u32 RSP_Len;
+	__u32 RSP_Addr;
+	__u32 Buff_Off;
 #define USES_EXTENDED_SGLIST(this_sest, x_ID) \
 	(!((this_sest)->u[ x_ID ].IWE.Buff_Off & 0x80000000))
-  ULONG Link;
-  ULONG RX_ID;
-  ULONG Data_Len;
-  ULONG Exp_RO;
-  ULONG Exp_Byte_Cnt;
-   // --- extended/local Gather Len/Address pairs
-  ULONG GLen1;
-  ULONG GAddr1;
-  ULONG GLen2;
-  ULONG GAddr2;
-  ULONG GLen3;
-  ULONG GAddr3;
+	__u32 Link;
+	__u32 RX_ID;
+	__u32 Data_Len;
+	__u32 Exp_RO;
+	__u32 Exp_Byte_Cnt;
+	// --- extended/local Gather Len/Address pairs
+	__u32 GLen1;
+	__u32 GAddr1;
+	__u32 GLen2;
+	__u32 GAddr2;
+	__u32 GLen3;
+	__u32 GAddr3;
 } TachLiteIWE;
 
 
-typedef struct 
-{
-  ULONG Seq_Accum;
-  ULONG reserved;       // must clear to 0
-  ULONG RSP_Len;
-  ULONG RSP_Addr;
-  ULONG Buff_Off;
-  ULONG Buff_Index;           // ULONG 5
-  ULONG Exp_RO;
-  ULONG Byte_Count;
-  ULONG reserved_;      // ULONG 8
-  ULONG Exp_Byte_Cnt;
-   // --- extended/local Scatter Len/Address pairs
-  ULONG SLen1;
-  ULONG SAddr1;
-  ULONG SLen2;
-  ULONG SAddr2;
-  ULONG SLen3;
-  ULONG SAddr3;
+typedef struct {
+	__u32 Seq_Accum;
+	__u32 reserved;		// must clear to 0
+	__u32 RSP_Len;
+	__u32 RSP_Addr;
+	__u32 Buff_Off;
+	__u32 Buff_Index;	// __u32 5
+	__u32 Exp_RO;
+	__u32 Byte_Count;
+	__u32 reserved_;	// __u32 8
+	__u32 Exp_Byte_Cnt;
+	// --- extended/local Scatter Len/Address pairs
+	__u32 SLen1;
+	__u32 SAddr1;
+	__u32 SLen2;
+	__u32 SAddr2;
+	__u32 SLen3;
+	__u32 SAddr3;
 } TachLiteIRE;
 
 
-typedef struct          // Target Write Entry
+typedef struct			// Target Write Entry
 {
-  ULONG Seq_Accum;      // dword 0
-  ULONG reserved;       // dword 1  must clear to 0
-  ULONG Remote_Node_ID;
-  ULONG reserved1;      // dword 3  must clear to 0
-  ULONG Buff_Off;
-  ULONG Buff_Index;     // ULONG 5
-  ULONG Exp_RO;
-  ULONG Byte_Count;
-  ULONG reserved_;      // ULONG 8
-  ULONG Exp_Byte_Cnt;
-   // --- extended/local Scatter Len/Address pairs
-  ULONG SLen1;
-  ULONG SAddr1;
-  ULONG SLen2;
-  ULONG SAddr2;
-  ULONG SLen3;
-  ULONG SAddr3;
+	__u32 Seq_Accum;	// dword 0
+	__u32 reserved;		// dword 1  must clear to 0
+	__u32 Remote_Node_ID;
+	__u32 reserved1;	// dword 3  must clear to 0
+	__u32 Buff_Off;
+	__u32 Buff_Index;	// __u32 5
+	__u32 Exp_RO;
+	__u32 Byte_Count;
+	__u32 reserved_;	// __u32 8
+	__u32 Exp_Byte_Cnt;
+	// --- extended/local Scatter Len/Address pairs
+	__u32 SLen1;
+	__u32 SAddr1;
+	__u32 SLen2;
+	__u32 SAddr2;
+	__u32 SLen3;
+	__u32 SAddr3;
 } TachLiteTWE;
 
-typedef struct      
-{
-  ULONG Hdr_Len;
-  ULONG Hdr_Addr;
-  ULONG RSP_Len;        // DWord 2
-  ULONG RSP_Addr;
-  ULONG Buff_Off;
-  ULONG Buff_Index;     // DWord 5
-  ULONG reserved;
-  ULONG Data_Len;
-  ULONG reserved_;
-  ULONG reserved__;
-   // --- extended/local Gather Len/Address pairs
-  ULONG GLen1;          // DWord A
-  ULONG GAddr1;
-  ULONG GLen2;
-  ULONG GAddr2;
-  ULONG GLen3;
-  ULONG GAddr3;
+typedef struct {
+	__u32 Hdr_Len;
+	__u32 Hdr_Addr;
+	__u32 RSP_Len;		// DWord 2
+	__u32 RSP_Addr;
+	__u32 Buff_Off;
+	__u32 Buff_Index;	// DWord 5
+	__u32 reserved;
+	__u32 Data_Len;
+	__u32 reserved_;
+	__u32 reserved__;
+	// --- extended/local Gather Len/Address pairs
+	__u32 GLen1;		// DWord A
+	__u32 GAddr1;
+	__u32 GLen2;
+	__u32 GAddr2;
+	__u32 GLen3;
+	__u32 GAddr3;
 } TachLiteTRE;
 
 typedef struct ext_sg_page_ptr_t *PSGPAGES;
-typedef struct ext_sg_page_ptr_t 
-{
-  unsigned char page[TL_EXT_SG_PAGE_BYTELEN * 2]; // 2x for alignment
-  dma_addr_t busaddr; 	// need the bus addresses and
-  unsigned int maplen;  // lengths for later pci unmapping.
-  PSGPAGES next;
-} SGPAGES; // linked list of S/G pairs, by Exchange
-
-typedef struct                  // SCSI Exchange State Table
-{
-  union                         // Entry can be IWE, IRE, TWE, TRE
-  {                             // 64 bytes per entry
-    TachLiteIWE IWE;
-    TachLiteIRE IRE;
-    TachLiteTWE TWE;
-    TachLiteTRE TRE;
-  } u[TACH_SEST_LEN];
-
-  TachFCHDR DataHDR[TACH_SEST_LEN]; // for SEST FCP_DATA frame hdr (no pl)
-  TachFCHDR_RSP RspHDR[TACH_SEST_LEN]; // space for SEST FCP_RSP frame
-  PSGPAGES sgPages[TACH_SEST_LEN]; // head of linked list of Pool-allocations
-  ULONG length;          // Length register
-  ULONG base;            // copy of base ptr for debug
+typedef struct ext_sg_page_ptr_t {
+	unsigned char page[TL_EXT_SG_PAGE_BYTELEN * 2];	// 2x for alignment
+	dma_addr_t busaddr;	// need the bus addresses and
+	unsigned int maplen;	// lengths for later pci unmapping.
+	PSGPAGES next;
+} SGPAGES;			// linked list of S/G pairs, by Exchange
+
+typedef struct			// SCSI Exchange State Table
+{
+	union			// Entry can be IWE, IRE, TWE, TRE
+	{			// 64 bytes per entry
+		TachLiteIWE IWE;
+		TachLiteIRE IRE;
+		TachLiteTWE TWE;
+		TachLiteTRE TRE;
+	} u[TACH_SEST_LEN];
+
+	TachFCHDR DataHDR[TACH_SEST_LEN];	// for SEST FCP_DATA frame hdr (no pl)
+	TachFCHDR_RSP RspHDR[TACH_SEST_LEN];	// space for SEST FCP_RSP frame
+	PSGPAGES sgPages[TACH_SEST_LEN];	// head of linked list of Pool-allocations
+	__u32 length;		// Length register
+	__u32 base;		// copy of base ptr for debug
 } TachSEST;
 
 
 
-typedef struct                  // each register has it's own address
-                                // and value (used for write-only regs)
+typedef struct			// each register has it's own address
+				// and value (used for write-only regs)
 {
-  void* address;
-  volatile ULONG value;
+	void *address;
+	volatile __u32 value;
 } FCREGISTER;
 
-typedef struct         // Host copy - TachLite Registers
+typedef struct			// Host copy - TachLite Registers
 {
-  ULONG IOBaseL, IOBaseU;  // I/O port lower and upper TL register addresses
-  ULONG MemBase;           // memory mapped register addresses
-  void* ReMapMemBase;      // O/S VM reference for MemBase
-  ULONG wwn_hi;            // WWN is set once at startup
-  ULONG wwn_lo;
-  ULONG my_al_pa;          // al_pa received after LIP()
-  ULONG ROMCTR;            // flags for on-board RAM/ROM
-  ULONG RAMBase;           // on-board RAM (i.e. some Tachlites)
-  ULONG SROMBase;          // on-board EEPROM (some Tachlites)
-  ULONG PCIMCTR;           // PCI Master Control Reg (has bus width)
-
-  FCREGISTER INTEN;        // copy of interrupt enable mask
-  FCREGISTER INTPEND;      // interrupt pending
-  FCREGISTER INTSTAT;      // interrupt status
-  FCREGISTER SFQconsumerIndex; 
-  FCREGISTER ERQproducerIndex; 
-  FCREGISTER TYconfig;   // TachYon (chip level)
-  FCREGISTER TYcontrol;
-  FCREGISTER TYstatus;
-  FCREGISTER FMconfig;   // Frame Manager (FC loop level)
-  FCREGISTER FMcontrol;
-  FCREGISTER FMstatus;
-  FCREGISTER FMLinkStatus1;
-  FCREGISTER FMLinkStatus2;
-  FCREGISTER FMBB_CreditZero;
-  FCREGISTER status;
-  FCREGISTER ed_tov;     // error detect time-out value
-  FCREGISTER rcv_al_pa;  // received arb. loop physical address
-  FCREGISTER primitive;  // e.g. LIP(), OPN(), ...
+	__u32 IOBaseL, IOBaseU;	// I/O port lower and upper TL register addresses
+	__u32 MemBase;		// memory mapped register addresses
+	void *ReMapMemBase;	// O/S VM reference for MemBase
+	__u32 wwn_hi;		// WWN is set once at startup
+	__u32 wwn_lo;
+	__u32 my_al_pa;		// al_pa received after LIP()
+	__u32 ROMCTR;		// flags for on-board RAM/ROM
+	__u32 RAMBase;		// on-board RAM (i.e. some Tachlites)
+	__u32 SROMBase;		// on-board EEPROM (some Tachlites)
+	__u32 PCIMCTR;		// PCI Master Control Reg (has bus width)
+
+	FCREGISTER INTEN;	// copy of interrupt enable mask
+	FCREGISTER INTPEND;	// interrupt pending
+	FCREGISTER INTSTAT;	// interrupt status
+	FCREGISTER SFQconsumerIndex;
+	FCREGISTER ERQproducerIndex;
+	FCREGISTER TYconfig;	// TachYon (chip level)
+	FCREGISTER TYcontrol;
+	FCREGISTER TYstatus;
+	FCREGISTER FMconfig;	// Frame Manager (FC loop level)
+	FCREGISTER FMcontrol;
+	FCREGISTER FMstatus;
+	FCREGISTER FMLinkStatus1;
+	FCREGISTER FMLinkStatus2;
+	FCREGISTER FMBB_CreditZero;
+	FCREGISTER status;
+	FCREGISTER ed_tov;	// error detect time-out value
+	FCREGISTER rcv_al_pa;	// received arb. loop physical address
+	FCREGISTER primitive;	// e.g. LIP(), OPN(), ...
 } TL_REGISTERS;
 
 
 
-typedef struct 
-{
-  ULONG ok;
-  ULONG invalidArgs;
-  ULONG linkDown;
-  ULONG linkUp;
-  ULONG outQueFull;
-  ULONG SESTFull;
-  ULONG hpe;    // host programming err (from Tach)
-  ULONG FC4aborted; // aborts from Application or upper driver layer
-  ULONG FC2aborted; // aborts from our driver's timeouts
-  ULONG timeouts;   // our driver timeout (on individual exchanges)
-  ULONG logouts;    // explicit - sent LOGO; implicit - device removed
-  ULONG retries;
-  ULONG linkFailTX;
-  ULONG linkFailRX;
-  ULONG CntErrors;  // byte count expected != count received (typ. SEST)
-  ULONG e_stores;   // elastic store errs
-  ULONG resets;     // hard or soft controller resets
-  ULONG FMinits;    // TACH Frame Manager Init (e.g. LIPs)
-  ULONG lnkQueFull;  // too many LOGIN, loop commands
-  ULONG ScsiQueFull; // too many FCP-SCSI inbound frames
-  ULONG LossofSignal;   // FM link status 1 regs
-  ULONG BadRXChar;   // FM link status 1 regs
-  ULONG LossofSync;   // FM link status 1 regs
-  ULONG Rx_EOFa;   // FM link status 2 regs (received EOFa)
-  ULONG Dis_Frm;   // FM link status 2 regs (discarded frames)
-  ULONG Bad_CRC;   // FM link status 2 regs
-  ULONG BB0_Timer; //  FM BB_Credit Zero Timer Reg
-  ULONG loopBreaks; // infinite loop exits
-  ULONG lastBB0timer;  // static accum. buffer needed by Tachlite
+typedef struct {
+	__u32 ok;
+	__u32 invalidArgs;
+	__u32 linkDown;
+	__u32 linkUp;
+	__u32 outQueFull;
+	__u32 SESTFull;
+	__u32 hpe;		// host programming err (from Tach)
+	__u32 FC4aborted;	// aborts from Application or upper driver layer
+	__u32 FC2aborted;	// aborts from our driver's timeouts
+	__u32 timeouts;		// our driver timeout (on individual exchanges)
+	__u32 logouts;		// explicit - sent LOGO; implicit - device removed
+	__u32 retries;
+	__u32 linkFailTX;
+	__u32 linkFailRX;
+	__u32 CntErrors;	// byte count expected != count received (typ. SEST)
+	__u32 e_stores;		// elastic store errs
+	__u32 resets;		// hard or soft controller resets
+	__u32 FMinits;		// TACH Frame Manager Init (e.g. LIPs)
+	__u32 lnkQueFull;	// too many LOGIN, loop commands
+	__u32 ScsiQueFull;	// too many FCP-SCSI inbound frames
+	__u32 LossofSignal;	// FM link status 1 regs
+	__u32 BadRXChar;	// FM link status 1 regs
+	__u32 LossofSync;	// FM link status 1 regs
+	__u32 Rx_EOFa;		// FM link status 2 regs (received EOFa)
+	__u32 Dis_Frm;		// FM link status 2 regs (discarded frames)
+	__u32 Bad_CRC;		// FM link status 2 regs
+	__u32 BB0_Timer;	//  FM BB_Credit Zero Timer Reg
+	__u32 loopBreaks;	// infinite loop exits
+	__u32 lastBB0timer;	// static accum. buffer needed by Tachlite
 } FCSTATS;
 
 
-typedef struct               // Config Options
-{                            // LS Bit first
-  USHORT        : 1;           // bit0:
-  USHORT  flogi : 1;           // bit1: We sent FLOGI - wait for Fabric logins
-  USHORT  fabric: 1;           // bit2: Tachyon detected Fabric (FM stat LG)
-  USHORT  LILPin: 1;           // bit3: We can use an FC-AL LILP frame
-  USHORT  target: 1;           // bit4: this Port has SCSI target capability
-  USHORT  initiator:    1;     // bit5: this Port has SCSI initiator capability
-  USHORT  extLoopback:  1;     // bit6: loopback at GBIC
-  USHORT  intLoopback:  1;     // bit7: loopback in HP silicon
-  USHORT        : 1;           // bit8:
-  USHORT        : 1;           // bit9:
-  USHORT        : 1;           // bit10:
-  USHORT        : 1;           // bit11:
-  USHORT        : 1;           // bit12:
-  USHORT        : 1;           // bit13:
-  USHORT        : 1;           // bit14:
-  USHORT        : 1;           // bit15:
+typedef struct			// Config Options
+{				// LS Bit first
+	__u16:1;		// bit0:
+	__u16 flogi:1;		// bit1: We sent FLOGI - wait for Fabric logins
+	__u16 fabric:1;	// bit2: Tachyon detected Fabric (FM stat LG)
+	__u16 LILPin:1;	// bit3: We can use an FC-AL LILP frame
+	__u16 target:1;	// bit4: this Port has SCSI target capability
+	__u16 initiator:1;	// bit5: this Port has SCSI initiator capability
+	__u16 extLoopback:1;	// bit6: loopback at GBIC
+	__u16 intLoopback:1;	// bit7: loopback in HP silicon
+	 __u16:1;		// bit8:
+	 __u16:1;		// bit9:
+	 __u16:1;		// bit10:
+	 __u16:1;		// bit11:
+	 __u16:1;		// bit12:
+	 __u16:1;		// bit13:
+	 __u16:1;		// bit14:
+	 __u16:1;		// bit15:
 } FC_OPTIONS;
 
 
 
-typedef struct dyn_mem_pair
-{
-  void *BaseAllocated;  // address as allocated from O/S;
-  unsigned long AlignedAddress; // aligned address (used by Tachyon DMA)
-  dma_addr_t dma_handle;
-  size_t size;
+typedef struct dyn_mem_pair {
+	void *BaseAllocated;	// address as allocated from O/S;
+	unsigned long AlignedAddress;	// aligned address (used by Tachyon DMA)
+	dma_addr_t dma_handle;
+	size_t size;
 } ALIGNED_MEM;
 
 
@@ -675,66 +664,63 @@
 #define IMPLICIT_LOGOUT 1
 #define EXPLICIT_LOGOUT 2
 
-typedef struct 
-{
-  UCHAR channel; // SCSI "bus"
-  UCHAR target;
-  UCHAR InqDeviceType;  // byte 0 from SCSI Inquiry response
-  UCHAR VolumeSetAddressing;  // FCP-SCSI LUN coding (40h for VSA)
-  UCHAR LunMasking;     // True if selective presentation supported
-  UCHAR lun[CPQFCTS_MAX_LUN];
+typedef struct {
+	__u8 channel;		// SCSI "bus"
+	__u8 target;
+	__u8 InqDeviceType;	// byte 0 from SCSI Inquiry response
+	__u8 VolumeSetAddressing;	// FCP-SCSI LUN coding (40h for VSA)
+	__u8 LunMasking;	// True if selective presentation supported
+	__u8 lun[CPQFCTS_MAX_LUN];
 } SCSI_NEXUS;
 
 
-typedef struct        
-{
-  union 
-  {
-    UCHAR ucWWN[8];  // a FC 64-bit World Wide Name/ PortID of target
-                     // addressing of single target on single loop...
-    u64 liWWN;
-  } u;
-
-  ULONG port_id;     // a FC 24-bit address of port (lower 8 bits = al_pa)
-
-  Scsi_Cmnd ScsiCmnd;   // command buffer for Report Luns
-#define REPORT_LUNS_PL 256  
-  UCHAR ReportLunsPayload[REPORT_LUNS_PL];
-  
-  SCSI_NEXUS ScsiNexus; // LUNs per FC device
-
-  ULONG LOGO_counter; // might try several times before logging out for good
-  ULONG LOGO_timer;   // after LIP, ports expecting PDISC must time-out and
-                      // LOGOut if successful PDISC not completed in 2 secs
-
-  ULONG concurrent_seq;  // must be 1 or greater
-  ULONG rx_data_size;    // e.g. 128, 256, 1024, 2048 per FC-PH spec
-  ULONG BB_credit;
-  ULONG EE_credit;
-
-  ULONG fcp_info;        // from PRLI (i.e. INITIATOR/ TARGET flags)
-                         // flags for login process
-  BOOLEAN Originator;    // Login sequence Originated (if false, we
-                         // responded to another port's login sequence)
-  BOOLEAN plogi;         // PLOGI frame ACCepted (originated or responded)
-  BOOLEAN pdisc;         // PDISC frame was ORIGINATED (self-login logic)
-  BOOLEAN prli;          // PRLI frame ACCepted (originated or responded)
-  BOOLEAN flogi;         // FLOGI frame ACCepted (originated or responded)
-  BOOLEAN logo;          // port permanently logged out (invalid login param)
-  BOOLEAN flogiReq;      // Fabric login required (set in LIP process)
-  UCHAR highest_ver;
-  UCHAR lowest_ver;
-
-  
-  // when the "target" (actually FC Port) is waiting for login
-  // (e.g. after Link reset), set the device_blocked bit;
-  // after Port completes login, un-block target.
-  UCHAR device_blocked; // see Scsi_Device struct
-
-                    // define singly-linked list of logged-in ports
-                    // once a port_id is identified, it is remembered,
-                    // even if the port is removed indefinitely
-  PVOID pNextPort;  // actually, type PFC_LOGGEDIN_PORT; void for Compiler
+typedef struct {
+	union {
+		__u8 ucWWN[8];	// a FC 64-bit World Wide Name/ PortID of target
+		// addressing of single target on single loop...
+		u64 liWWN;
+	} u;
+
+	__u32 port_id;		// a FC 24-bit address of port (lower 8 bits = al_pa)
+
+	Scsi_Cmnd ScsiCmnd;	// command buffer for Report Luns
+#define REPORT_LUNS_PL 256
+	__u8 ReportLunsPayload[REPORT_LUNS_PL];
+
+	SCSI_NEXUS ScsiNexus;	// LUNs per FC device
+
+	__u32 LOGO_counter;	// might try several times before logging out for good
+	__u32 LOGO_timer;	// after LIP, ports expecting PDISC must time-out and
+	// LOGOut if successful PDISC not completed in 2 secs
+
+	__u32 concurrent_seq;	// must be 1 or greater
+	__u32 rx_data_size;	// e.g. 128, 256, 1024, 2048 per FC-PH spec
+	__u32 BB_credit;
+	__u32 EE_credit;
+
+	__u32 fcp_info;		// from PRLI (i.e. INITIATOR/ TARGET flags)
+	// flags for login process
+	__u8 Originator;	// Login sequence Originated (if false, we
+	// responded to another port's login sequence)
+	__u8 plogi;		// PLOGI frame ACCepted (originated or responded)
+	__u8 pdisc;		// PDISC frame was ORIGINATED (self-login logic)
+	__u8 prli;		// PRLI frame ACCepted (originated or responded)
+	__u8 flogi;		// FLOGI frame ACCepted (originated or responded)
+	__u8 logo;		// port permanently logged out (invalid login param)
+	__u8 flogiReq;	// Fabric login required (set in LIP process)
+	__u8 highest_ver;
+	__u8 lowest_ver;
+
+
+	// when the "target" (actually FC Port) is waiting for login
+	// (e.g. after Link reset), set the device_blocked bit;
+	// after Port completes login, un-block target.
+	__u8 device_blocked;	// see Scsi_Device struct
+
+	// define singly-linked list of logged-in ports
+	// once a port_id is identified, it is remembered,
+	// even if the port is removed indefinitely
+	void * pNextPort;	// actually, type PFC_LOGGEDIN_PORT; void for Compiler
 
 } FC_LOGGEDIN_PORT, *PFC_LOGGEDIN_PORT;
 
@@ -742,16 +728,15 @@
 
 // This serves as the ESB (Exchange Status Block),
 // and has timeout counter; used for ABORTs
-typedef struct                
-{                                  // FC-1 X_IDs
-  ULONG type;            // ELS_PLOGI, SCSI_IWE, ... (0 if free)
-  PFC_LOGGEDIN_PORT pLoggedInPort; // FC device on other end of Exchange
-  Scsi_Cmnd *Cmnd;       // Linux SCSI command packet includes S/G list
-  ULONG timeOut;         // units of ??, DEC by driver, Abort when 0
-  ULONG reTries;         // need one or more retries?
-  ULONG status;          // flags indicating errors (0 if none)
-  TachLiteIRB IRB;       // I/O Request Block, gets copied to ERQ
-  TachFCHDR_GCMND fchs;  // location of IRB's Req_A_SFS_Addr
+typedef struct {		// FC-1 X_IDs
+	__u32 type;		// ELS_PLOGI, SCSI_IWE, ... (0 if free)
+	PFC_LOGGEDIN_PORT pLoggedInPort;	// FC device on other end of Exchange
+	Scsi_Cmnd *Cmnd;	// Linux SCSI command packet includes S/G list
+	__u32 timeOut;		// units of ??, DEC by driver, Abort when 0
+	__u32 reTries;		// need one or more retries?
+	__u32 status;		// flags indicating errors (0 if none)
+	TachLiteIRB IRB;	// I/O Request Block, gets copied to ERQ
+	TachFCHDR_GCMND fchs;	// location of IRB's Req_A_SFS_Addr
 } FC_EXCHANGE, *PFC_EXCHANGE;
 
 // Unfortunately, Linux limits our kmalloc() allocations to 128k.
@@ -761,9 +746,9 @@
 // (In other words, this cumbersome indirection is necessary
 // because of kernel memory allocation constraints!)
 
-typedef struct // we will allocate this dynamically
+typedef struct			// we will allocate this dynamically
 {
-  FC_EXCHANGE fcExchange[ TACH_MAX_XID ];
+	FC_EXCHANGE fcExchange[TACH_MAX_XID];
 } FC_EXCHANGES;
 
 
@@ -776,95 +761,89 @@
 
 
 
-typedef struct
-{
-  char Name[64]; // name of controller ("HP Tachlite TL Rev2.0, 33MHz, 64bit bus")
-  //PVOID  pAdapterDevExt; // back pointer to device object/extension
-  ULONG ChipType;        // local numeric key for Tachyon Type / Rev.
-  ULONG status;              // our Driver - logical status
-  
-  TL_REGISTERS Registers;    // reg addresses & host memory copies
-                             // FC-4 mapping of 'transaction' to X_IDs
-  UCHAR LILPmap[32*4];       // Loop Position Map of ALPAs (late FC-AL only)
-  FC_OPTIONS Options;        // e.g. Target, Initiator, loopback...
-  UCHAR highest_FCPH_ver;    // FC-PH version limits
-  UCHAR lowest_FCPH_ver;     // FC-PH version limits
-
-  FC_EXCHANGES *Exchanges;  
-  ULONG fcLsExchangeLRU;       // Least Recently Used counter (Link Service)
-  ULONG fcSestExchangeLRU;       // Least Recently Used counter (FCP-SCSI)
-  FC_LOGGEDIN_PORT fcPorts;  // linked list of every FC port ever seen
-  FCSTATS fcStats;           // FC comm err counters
-
-                             // Host memory QUEUE pointers
-  TachLiteERQ *ERQ;          // Exchange Request Que 
-  TachyonIMQ *IMQ;           // Inbound Message Que 
-  TachLiteSFQ *SFQ;          // Single Frame Queue
-  TachSEST *SEST;            // SCSI Exchange State Table
-
-  dma_addr_t exch_dma_handle;
-
-  // these function pointers are for "generic" functions, which are
-  // replaced with Host Bus Adapter types at
-  // runtime.
-  int (*CreateTachyonQues)( void* , int);
-  int (*DestroyTachyonQues)( void* , int);
-  int (*LaserControl)(void*, int );   // e.g. On/Off
-  int (*ResetTachyon)(void*, int );
-  void (*FreezeTachyon)(void*, int );
-  void (*UnFreezeTachyon)(void*, int );
-  int (*InitializeTachyon)(void*, int, int );
-  int (*InitializeFrameManager)(void*, int );
-  int (*ProcessIMQEntry)(void*);
-  int (*ReadWriteWWN)(void*, int ReadWrite);
-  int (*ReadWriteNVRAM)(void*, void*, int ReadWrite);
+typedef struct {
+	char Name[64];		// name of controller ("HP Tachlite TL Rev2.0, 33MHz, 64bit bus")
+	//void *  pAdapterDevExt; // back pointer to device object/extension
+	__u32 ChipType;		// local numeric key for Tachyon Type / Rev.
+	__u32 status;		// our Driver - logical status
+
+	TL_REGISTERS Registers;	// reg addresses & host memory copies
+	// FC-4 mapping of 'transaction' to X_IDs
+	__u8 LILPmap[32 * 4];	// Loop Position Map of ALPAs (late FC-AL only)
+	FC_OPTIONS Options;	// e.g. Target, Initiator, loopback...
+	__u8 highest_FCPH_ver;	// FC-PH version limits
+	__u8 lowest_FCPH_ver;	// FC-PH version limits
+
+	FC_EXCHANGES *Exchanges;
+	__u32 fcLsExchangeLRU;	// Least Recently Used counter (Link Service)
+	__u32 fcSestExchangeLRU;	// Least Recently Used counter (FCP-SCSI)
+	FC_LOGGEDIN_PORT fcPorts;	// linked list of every FC port ever seen
+	FCSTATS fcStats;	// FC comm err counters
+
+	// Host memory QUEUE pointers
+	TachLiteERQ *ERQ;	// Exchange Request Que 
+	TachyonIMQ *IMQ;	// Inbound Message Que 
+	TachLiteSFQ *SFQ;	// Single Frame Queue
+	TachSEST *SEST;		// SCSI Exchange State Table
+
+	dma_addr_t exch_dma_handle;
+
+	// these function pointers are for "generic" functions, which are
+	// replaced with Host Bus Adapter types at
+	// runtime.
+	int (*CreateTachyonQues) (void *, int);
+	int (*DestroyTachyonQues) (void *, int);
+	int (*LaserControl) (void *, int);	// e.g. On/Off
+	int (*ResetTachyon) (void *, int);
+	void (*FreezeTachyon) (void *, int);
+	void (*UnFreezeTachyon) (void *, int);
+	int (*InitializeTachyon) (void *, int, int);
+	int (*InitializeFrameManager) (void *, int);
+	int (*ProcessIMQEntry) (void *);
+	int (*ReadWriteWWN) (void *, int ReadWrite);
+	int (*ReadWriteNVRAM) (void *, void *, int ReadWrite);
 
 } TACHYON, *PTACHYON;
 
 
 void cpqfcTSClearLinkStatusCounters(TACHYON * fcChip);
 
-int CpqTsCreateTachLiteQues( void* pHBA, int opcode);
-int CpqTsDestroyTachLiteQues( void* , int);
-int CpqTsInitializeTachLite( void *pHBA, int opcode1, int opcode2);
+int CpqTsCreateTachLiteQues(void *pHBA, int opcode);
+int CpqTsDestroyTachLiteQues(void *, int);
+int CpqTsInitializeTachLite(void *pHBA, int opcode1, int opcode2);
 
-int CpqTsProcessIMQEntry(void* pHBA);
+int CpqTsProcessIMQEntry(void *pHBA);
 int CpqTsResetTachLite(void *pHBA, int type);
 void CpqTsFreezeTachlite(void *pHBA, int type);
 void CpqTsUnFreezeTachlite(void *pHBA, int type);
 int CpqTsInitializeFrameManager(void *pHBA, int);
-int CpqTsLaserControl( void* addrBase, int opcode );
-int CpqTsReadWriteWWN(void*, int ReadWrite);
-int CpqTsReadWriteNVRAM(void*, void* data, int ReadWrite);
-
-void cpqfcTS_WorkTask( struct Scsi_Host *HostAdapter);
-void cpqfcTSWorkerThread( void *host);
-
-int cpqfcTS_GetNVRAM_data( UCHAR *wwnbuf, UCHAR *buf );
-ULONG cpqfcTS_ReadNVRAM( void* GPIOin, void* GPIOout , USHORT count,
-	UCHAR *buf );
-
-BOOLEAN tl_write_i2c_nvram( void* GPIOin, void* GPIOout,
-  USHORT startOffset,  // e.g. 0x2f for WWN start
-  USHORT count,
-  UCHAR *buf );
+int CpqTsLaserControl(void *addrBase, int opcode);
+int CpqTsReadWriteWWN(void *, int ReadWrite);
+int CpqTsReadWriteNVRAM(void *, void *data, int ReadWrite);
+
+void cpqfcTS_WorkTask(struct Scsi_Host *HostAdapter);
+void cpqfcTSWorkerThread(void *host);
+
+int cpqfcTS_GetNVRAM_data(__u8 * wwnbuf, __u8 * buf);
+__u32 cpqfcTS_ReadNVRAM(void *GPIOin, void *GPIOout, __u16 count, __u8 * buf);
+
+__u8 tl_write_i2c_nvram(void *GPIOin, void *GPIOout, __u16 startOffset,	// e.g. 0x2f for WWN start
+			   __u16 count, __u8 * buf);
 
 
 // define misc functions 
-int cpqfcTSGetLPSM( PTACHYON fcChip, char cErrorString[]);
-int cpqfcTSDecodeGBICtype( PTACHYON fcChip, char cErrorString[]);
-void* fcMemManager( struct pci_dev *pdev,
-		ALIGNED_MEM *dyn_mem_pair, ULONG n_alloc, ULONG ab,
-                   ULONG ulAlignedAddress, dma_addr_t *dma_handle);
+int cpqfcTSGetLPSM(PTACHYON fcChip, char cErrorString[]);
+int cpqfcTSDecodeGBICtype(PTACHYON fcChip, char cErrorString[]);
+void *fcMemManager(struct pci_dev *pdev, ALIGNED_MEM * dyn_mem_pair, __u32 n_alloc, __u32 ab, __u32 ulAlignedAddress, dma_addr_t * dma_handle);
 
-void BigEndianSwap(  UCHAR *source, UCHAR *dest,  USHORT cnt);
+void BigEndianSwap(__u8 * source, __u8 * dest, __u16 cnt);
+
+//__u32 virt_to_phys( void * virtaddr );
 
-//ULONG virt_to_phys( PVOID virtaddr );
-                  
 
 // Linux interrupt handler
-void cpqfcTS_intr_handler( int irq,void *dev_id,struct pt_regs *regs);
-void cpqfcTSheartbeat( unsigned long ptr );
+void cpqfcTS_intr_handler(int irq, void *dev_id, struct pt_regs *regs);
+void cpqfcTSheartbeat(unsigned long ptr);
 
 
 
@@ -872,19 +851,17 @@
 // need 4 bytes for x_ID, and a Scsi_Cmnd (~284 bytes)
 //#define LINKQ_ITEM_SIZE ((4+sizeof(Scsi_Cmnd)+3)/4)
 #define LINKQ_ITEM_SIZE (3*16)
-typedef struct
-{
-  ULONG Type;              // e.g. LINKUP, SFQENTRY, PDISC, BLS_ABTS, ...
-  ULONG ulBuff[ LINKQ_ITEM_SIZE ];
+typedef struct {
+	__u32 Type;		// e.g. LINKUP, SFQENTRY, PDISC, BLS_ABTS, ...
+	__u32 ulBuff[LINKQ_ITEM_SIZE];
 } LINKQ_ITEM;
 
 #define FC_LINKQ_DEPTH TACH_MAX_XID
-typedef struct
-{
-  ULONG producer;
-  ULONG consumer;  // when producer equals consumer, Q empty
+typedef struct {
+	__u32 producer;
+	__u32 consumer;		// when producer equals consumer, Q empty
 
-  LINKQ_ITEM Qitem[ FC_LINKQ_DEPTH ];
+	LINKQ_ITEM Qitem[FC_LINKQ_DEPTH];
 
 } FC_LINK_QUE, *PFC_LINK_QUE;
 
@@ -893,18 +870,16 @@
      // User thread processes
 #define FC_SCSIQ_DEPTH 32
 
-typedef struct
-{
-  int Type;              // e.g. SCSI
-  ULONG ulBuff[ 3*16 ];
+typedef struct {
+	int Type;		// e.g. SCSI
+	__u32 ulBuff[3 * 16];
 } SCSIQ_ITEM;
 
-typedef struct
-{
-  ULONG producer;
-  ULONG consumer;  // when producer equals consumer, Q empty
+typedef struct {
+	__u32 producer;
+	__u32 consumer;		// when producer equals consumer, Q empty
 
-  SCSIQ_ITEM Qitem[ FC_SCSIQ_DEPTH ];
+	SCSIQ_ITEM Qitem[FC_SCSIQ_DEPTH];
 
 } FC_SCSI_QUE, *PFC_SCSI_QUE;
 
@@ -912,44 +887,43 @@
 
 
 
-#define DYNAMIC_ALLOCATIONS 4  // Tachyon aligned allocations: ERQ,IMQ,SFQ,SEST
+#define DYNAMIC_ALLOCATIONS 4	// Tachyon aligned allocations: ERQ,IMQ,SFQ,SEST
 
 // Linux space allocated per HBA (chip state, etc.)
-typedef struct 
-{
-  struct Scsi_Host *HostAdapter; // back pointer to Linux Scsi struct
+typedef struct {
+	struct Scsi_Host *HostAdapter;	// back pointer to Linux Scsi struct
+
+	TACHYON fcChip;		// All Tachyon registers, Queues, functions
+	ALIGNED_MEM dynamic_mem[DYNAMIC_ALLOCATIONS];
+
+	struct pci_dev *PciDev;
+	dma_addr_t fcLQ_dma_handle;
+
+	Scsi_Cmnd *LinkDnCmnd[CPQFCTS_REQ_QUEUE_LEN];	// collects Cmnds during LDn
+	// (for Acceptable targets)
+	Scsi_Cmnd *BoardLockCmnd[CPQFCTS_REQ_QUEUE_LEN];	// SEST was full
+
+	Scsi_Cmnd *BadTargetCmnd[CPQFCTS_MAX_TARGET_ID];	// missing targets
+
+	u_char HBAnum;		// 0-based host number
+
 
-  TACHYON fcChip;    // All Tachyon registers, Queues, functions
-  ALIGNED_MEM dynamic_mem[DYNAMIC_ALLOCATIONS];
+	struct timer_list cpqfcTStimer;	// FC utility timer for implicit
+	// logouts, FC protocol timeouts, etc.
+	int fcStatsTime;	// Statistics delta reporting time
 
-  struct pci_dev *PciDev;
-  dma_addr_t fcLQ_dma_handle;
+	struct task_struct *worker_thread;	// our kernel thread
+	int PortDiscDone;	// set by SendLogins(), cleared by LDn
 
-  Scsi_Cmnd *LinkDnCmnd[CPQFCTS_REQ_QUEUE_LEN]; // collects Cmnds during LDn
-                                                // (for Acceptable targets)
-  Scsi_Cmnd *BoardLockCmnd[CPQFCTS_REQ_QUEUE_LEN]; // SEST was full
-  
-  Scsi_Cmnd *BadTargetCmnd[CPQFCTS_MAX_TARGET_ID]; // missing targets
-
-  u_char HBAnum;     // 0-based host number
-
-
-  struct timer_list cpqfcTStimer; // FC utility timer for implicit
-                                  // logouts, FC protocol timeouts, etc.
-  int fcStatsTime;  // Statistics delta reporting time
-
-  struct task_struct *worker_thread; // our kernel thread
-  int PortDiscDone;    // set by SendLogins(), cleared by LDn
-  
-  struct semaphore *TachFrozen;
-  struct semaphore *TYOBcomplete;    // handshake for Tach outbound frames
-  struct semaphore *fcQueReady;      // FibreChannel work for our kernel thread
-  struct semaphore *notify_wt;       // synchronizes kernel thread kill
-  struct semaphore *BoardLock;
-  
-  PFC_LINK_QUE fcLQ;             // the WorkerThread operates on this
+	struct semaphore *TachFrozen;
+	struct semaphore *TYOBcomplete;	// handshake for Tach outbound frames
+	struct semaphore *fcQueReady;	// FibreChannel work for our kernel thread
+	struct semaphore *notify_wt;	// synchronizes kernel thread kill
+	struct semaphore *BoardLock;
 
-  spinlock_t hba_spinlock;           // held/released by WorkerThread
+	PFC_LINK_QUE fcLQ;	// the WorkerThread operates on this
+
+	spinlock_t hba_spinlock;	// held/released by WorkerThread
 
 } CPQFCHBA;
 
@@ -958,69 +932,41 @@
 
 
 
-void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata,
-		PFC_LOGGEDIN_PORT pFcPort);
+void cpqfcTSImplicitLogout(CPQFCHBA * cpqfcHBAdata, PFC_LOGGEDIN_PORT pFcPort);
+
+
+void cpqfcTSTerminateExchange(CPQFCHBA *, SCSI_NEXUS * target, int);
+
+PFC_LOGGEDIN_PORT fcPortLoggedIn(CPQFCHBA * cpqfcHBAdata, TachFCHDR_GCMND * fchs, __u8, __u8);
+void fcProcessLoggedIn(CPQFCHBA * cpqfcHBAdata, TachFCHDR_GCMND * fchs);
+
+
+__u32 cpqfcTSBuildExchange(CPQFCHBA * cpqfcHBAdata, __u32 type,	// e.g. PLOGI
+			   TachFCHDR_GCMND * InFCHS,	// incoming FCHS
+			   void *Data,	// the CDB, scatter/gather, etc.  
+			   __s32 * ExchangeID);	// allocated exchange ID
+
+__u32 cpqfcTSStartExchange(CPQFCHBA * cpqfcHBAdata, __s32 ExchangeID);
+
+void cpqfcTSCompleteExchange(struct pci_dev *pcidev, PTACHYON fcChip, __u32 exchange_ID);
+
+
+PFC_LOGGEDIN_PORT fcFindLoggedInPort(PTACHYON fcChip, Scsi_Cmnd * Cmnd,	// (We want the channel/target/lun Nexus from Cmnd)
+				     __u32 port_id,	// search linked list for al_pa, or
+				     __u8 wwn[8],	// search linked list for WWN, or...
+				     PFC_LOGGEDIN_PORT * pLastLoggedInPort);
 
+void cpqfcTSPutLinkQue(CPQFCHBA * cpqfcHBAdata, int Type, void *QueContent);
 
-void cpqfcTSTerminateExchange( CPQFCHBA*, SCSI_NEXUS *target, int );
+void fcPutScsiQue(CPQFCHBA * cpqfcHBAdata, int Type, void *QueContent);
 
-PFC_LOGGEDIN_PORT fcPortLoggedIn( 
-   CPQFCHBA *cpqfcHBAdata, 
-   TachFCHDR_GCMND* fchs, 
-   BOOLEAN, 
-   BOOLEAN);
-void fcProcessLoggedIn( 
-   CPQFCHBA *cpqfcHBAdata, TachFCHDR_GCMND* fchs);
-
-
-ULONG cpqfcTSBuildExchange( 
-  CPQFCHBA *cpqfcHBAdata,
-  ULONG type, // e.g. PLOGI
-  TachFCHDR_GCMND* InFCHS,  // incoming FCHS
-  void *Data,               // the CDB, scatter/gather, etc.  
-  LONG *ExchangeID );       // allocated exchange ID
-
-ULONG cpqfcTSStartExchange( 
-  CPQFCHBA *cpqfcHBAdata,
-  LONG ExchangeID );
-
-void cpqfcTSCompleteExchange( 
-       struct pci_dev *pcidev,
-       PTACHYON fcChip, 
-       ULONG exchange_ID);
-
-
-PFC_LOGGEDIN_PORT  fcFindLoggedInPort( 
-  PTACHYON fcChip, 
-  Scsi_Cmnd *Cmnd,  // (We want the channel/target/lun Nexus from Cmnd)
-  ULONG port_id,  // search linked list for al_pa, or
-  UCHAR wwn[8],    // search linked list for WWN, or...
-  PFC_LOGGEDIN_PORT *pLastLoggedInPort
-);
-
-void cpqfcTSPutLinkQue( 
-  CPQFCHBA *cpqfcHBAdata, 
-  int Type, 
-  void *QueContent);
-
-void fcPutScsiQue( 
-  CPQFCHBA *cpqfcHBAdata, 
-  int Type, 
-  void *QueContent);
-
-void fcLinkQReset(
-   CPQFCHBA *);
-void fcScsiQReset(
-   CPQFCHBA *);
-void fcSestReset(
-   CPQFCHBA *);
-
-void cpqfc_pci_unmap(struct pci_dev *pcidev, 
-	Scsi_Cmnd *cmd, 
-	PTACHYON fcChip, 
-	ULONG x_ID);
+void fcLinkQReset(CPQFCHBA *);
+void fcScsiQReset(CPQFCHBA *);
+void fcSestReset(CPQFCHBA *);
 
-extern const UCHAR valid_al_pa[];
+void cpqfc_pci_unmap(struct pci_dev *pcidev, Scsi_Cmnd * cmd, PTACHYON fcChip, __u32 x_ID);
+
+extern const __u8 valid_al_pa[];
 extern const int number_of_al_pa;
 
 #define FCP_RESID_UNDER   0x80000
@@ -1036,37 +982,35 @@
 #define FCP_TASKFUNCTION_FAIL      0x5000000
 
 // FCP-SCSI response status struct
-typedef struct  // see "TachFCHDR_RSP" definition - 64 bytes
+typedef struct			// see "TachFCHDR_RSP" definition - 64 bytes
 {
-  __u32 reserved;
-  __u32 reserved1;
-  __u32 fcp_status;    // field validity and SCSI status
-  __u32 fcp_resid;
-  __u32 fcp_sns_len;   // length of FCP_SNS_INFO field
-  __u32 fcp_rsp_len;   // length of FCP_RSP_INFO field (expect 8)
-  __u32 fcp_rsp_info;  // 4 bytes of FCP protocol response information
-  __u32 fcp_rsp_info2; // (4 more bytes, since most implementations use 8)
-  __u8  fcp_sns_info[36]; // bytes for SCSI sense (ASC, ASCQ)
+	__u32 reserved;
+	__u32 reserved1;
+	__u32 fcp_status;	// field validity and SCSI status
+	__u32 fcp_resid;
+	__u32 fcp_sns_len;	// length of FCP_SNS_INFO field
+	__u32 fcp_rsp_len;	// length of FCP_RSP_INFO field (expect 8)
+	__u32 fcp_rsp_info;	// 4 bytes of FCP protocol response information
+	__u32 fcp_rsp_info2;	// (4 more bytes, since most implementations use 8)
+	__u8 fcp_sns_info[36];	// bytes for SCSI sense (ASC, ASCQ)
 
 } FCP_STATUS_RESPONSE, *PFCP_STATUS_RESPONSE;
 
 
 // Fabric State Change Registration
-typedef struct scrpl
-{
-  __u32 command;
-  __u32 function;
+typedef struct scrpl {
+	__u32 command;
+	__u32 function;
 } SCR_PL;
 
 // Fabric Name Service Request
-typedef struct nsrpl
-{
-  __u32 CT_Rev;  // (& IN_ID)   WORD 0
-  __u32 FCS_Type;            // WORD 1
-  __u32 Command_code;        // WORD 2
-  __u32 reason_code;         // WORD 3
-  __u32 FCP;                 // WORD 4 (lower byte)
-  
+typedef struct nsrpl {
+	__u32 CT_Rev;		// (& IN_ID)   WORD 0
+	__u32 FCS_Type;		// WORD 1
+	__u32 Command_code;	// WORD 2
+	__u32 reason_code;	// WORD 3
+	__u32 FCP;		// WORD 4 (lower byte)
+
 } NSR_PL;
 
 
@@ -1089,12 +1033,12 @@
 					// PDISC after a LIP.
 #define E_D_TOV			2	// Minimum Time to wait for Sequence
 					// Completion.
-#define R_A_TOV			0	// Minimum Time for Target to wait 
+#define R_A_TOV			0	// Minimum Time for Target to wait
 					// before reclaiming resources.
 //
-//	R_CTL Field
+//      R_CTL Field
 //
-//	Routing Bits (31-28)
+//      Routing Bits (31-28)
 //
 #define FC4_DEVICE_DATA		0x00000000
 #define EXT_LINK_DATA		0x20000000
@@ -1105,7 +1049,7 @@
 #define ROUTING_MASK		0xF0000000
 
 //
-//	Information Bits (27-24)
+//      Information Bits (27-24)
 //
 #define UNCAT_INFORMATION	0x00000000
 #define SOLICITED_DATA		0x01000000
@@ -1117,20 +1061,20 @@
 #define COMMAND_STATUS		0x07000000
 #define INFO_MASK		0x0F000000
 //
-//	(Link Control Codes)
+//      (Link Control Codes)
 //
 #define ACK_1			0x00000000
 #define ACK_0_OR_N		0x01000000
-#define P_RJT			0x02000000 
-#define F_RJT			0x03000000 
+#define P_RJT			0x02000000
+#define F_RJT			0x03000000
 #define P_BSY			0x04000000
 #define FABRIC_BUSY_TO_DF	0x05000000	// Fabric Busy to Data Frame
 #define FABRIC_BUSY_TO_LC	0x06000000	// Fabric Busy to Link Ctl Frame
 #define LINK_CREDIT_RESET	0x07000000
 //
-//	(Link Service Command Codes)
+//      (Link Service Command Codes)
 //
-//#define LS_RJT			0x01000000	// LS Reject
+//#define LS_RJT                        0x01000000      // LS Reject
 
 #define LS_ACC			0x02000000	// LS Accept
 #define LS_PLOGI		0x03000000	// N_PORT Login
@@ -1156,11 +1100,11 @@
 #define LS_FDISC		0x51000000	// Fabric Discovery
 #define LS_ADISC		0x52000000	// Discover Address
 #define LS_RNC			0x53000000	// Report Node Capability
-#define LS_SCR                  0x62000000      // State Change Registration
-#define LS_MASK			0xFF000000	
+#define LS_SCR                  0x62000000	// State Change Registration
+#define LS_MASK			0xFF000000
 
 //
-// 	TYPE Bit Masks
+//      TYPE Bit Masks
 //
 #define BASIC_LINK_SERVICE	0x00000000
 #define EXT_LINK_SERVICE	0x01000000
@@ -1186,35 +1130,35 @@
 #define TYPE_MASK		0xFF000000
 
 typedef struct {
-	UCHAR seq_id_valid;
-	UCHAR seq_id;
-	USHORT reserved;  // 2 bytes reserved
-	ULONG ox_rx_id;
-	USHORT low_seq_cnt;
-	USHORT high_seq_cnt;
+	__u8 seq_id_valid;
+	__u8 seq_id;
+	__u16 reserved;	// 2 bytes reserved
+	__u32 ox_rx_id;
+	__u16 low_seq_cnt;
+	__u16 high_seq_cnt;
 } BA_ACC_PAYLOAD;
 
 typedef struct {
-	UCHAR reserved;
-	UCHAR reason_code;
-	UCHAR reason_explain;
-	UCHAR vendor_unique;
+	__u8 reserved;
+	__u8 reason_code;
+	__u8 reason_explain;
+	__u8 vendor_unique;
 } BA_RJT_PAYLOAD;
 
 
 typedef struct {
-	ULONG 	command_code;
-	ULONG 	sid;
-	USHORT	ox_id;
-	USHORT	rx_id;
+	__u32 command_code;
+	__u32 sid;
+	__u16 ox_id;
+	__u16 rx_id;
 } RRQ_MESSAGE;
 
 typedef struct {
-	ULONG command_code;
-	UCHAR vendor;
-	UCHAR explain;
-	UCHAR reason;
-	UCHAR reserved;
+	__u32 command_code;
+	__u8 vendor;
+	__u8 explain;
+	__u8 reason;
+	__u8 reserved;
 } REJECT_MESSAGE;
 
 
@@ -1244,9 +1188,9 @@
 
 #define X_ID_INTERLOCK		0x2000
 
-#define ERROR_POLICY		0x1800		// Error Policy Supported
-#define ERROR_DISCARD		0x00		// Only Discard Supported
-#define ERROR_DISC_PROCESS	0x02		// Discard and process supported
+#define ERROR_POLICY		0x1800	// Error Policy Supported
+#define ERROR_DISCARD		0x00	// Only Discard Supported
+#define ERROR_DISC_PROCESS	0x02	// Discard and process supported
 
 #define NODE_ID			0x01
 #define IEEE_EXT		0x20
@@ -1255,88 +1199,87 @@
 // Categories Supported Per Sequence
 //
 #define	CATEGORIES_PER_SEQUENCE	0x300
-#define ONE_CATEGORY_SEQUENCE	0x00		// 1 Category per Sequence
-#define TWO_CATEGORY_SEQUENCE	0x01		// 2 Categories per Sequence
-#define MANY_CATEGORY_SEQUENCE	0x03		// > 2 Categories/Sequence
+#define ONE_CATEGORY_SEQUENCE	0x00	// 1 Category per Sequence
+#define TWO_CATEGORY_SEQUENCE	0x01	// 2 Categories per Sequence
+#define MANY_CATEGORY_SEQUENCE	0x03	// > 2 Categories/Sequence
 
 typedef struct {
 
-	USHORT initiator_control;
-	USHORT service_options;
+	__u16 initiator_control;
+	__u16 service_options;
 
-	USHORT rx_data_size;
-	USHORT recipient_control;
+	__u16 rx_data_size;
+	__u16 recipient_control;
 
-	USHORT ee_credit;
-	USHORT concurrent_sequences;
+	__u16 ee_credit;
+	__u16 concurrent_sequences;
 
-	USHORT reserved;
-	USHORT open_sequences;
+	__u16 reserved;
+	__u16 open_sequences;
 
 } CLASS_PARAMETERS;
 
 typedef struct {
-	ULONG	login_cmd;
+	__u32 login_cmd;
 	//
 	// Common Service Parameters
 	//
 	struct {
 
-		USHORT bb_credit;
-		UCHAR lowest_ver;
-		UCHAR highest_ver;
+		__u16 bb_credit;
+		__u8 lowest_ver;
+		__u8 highest_ver;
 
-		USHORT bb_rx_size;
-		USHORT common_features;
+		__u16 bb_rx_size;
+		__u16 common_features;
 
-		USHORT rel_offset;
-		USHORT concurrent_seq;
+		__u16 rel_offset;
+		__u16 concurrent_seq;
 
 
-		ULONG e_d_tov;
+		__u32 e_d_tov;
 	} cmn_services;
 
 	//
 	// Port Name
 	//
-	UCHAR port_name[8];
+	__u8 port_name[8];
 
 	//
 	// Node/Fabric Name
 	//
-	UCHAR node_name[8];
+	__u8 node_name[8];
 
 	//
 	// Class 1, 2 and 3 Service Parameters
 	//
-	CLASS_PARAMETERS	class1;
-	CLASS_PARAMETERS	class2;
-	CLASS_PARAMETERS	class3;
+	CLASS_PARAMETERS class1;
+	CLASS_PARAMETERS class2;
+	CLASS_PARAMETERS class3;
 
-	ULONG reserved[4];
+	__u32 reserved[4];
 
 	//
 	// Vendor Version Level
 	//
-	UCHAR		vendor_id[2];
-	UCHAR		vendor_version[6];
-	ULONG		buffer_size;
-	USHORT		rxid_start;
-	USHORT		total_rxids;
+	__u8 vendor_id[2];
+	__u8 vendor_version[6];
+	__u32 buffer_size;
+	__u16 rxid_start;
+	__u16 total_rxids;
 } LOGIN_PAYLOAD;
 
 
-typedef struct
-{
-  ULONG cmd;  // 4 bytes
-  UCHAR n_port_identifier[3];
-  UCHAR reserved;
-  UCHAR port_name[8];
+typedef struct {
+	__u32 cmd;		// 4 bytes
+	__u8 n_port_identifier[3];
+	__u8 reserved;
+	__u8 port_name[8];
 } LOGOUT_PAYLOAD;
 
 
 //
-//	PRLI Request Service Parameter Defines
+//      PRLI Request Service Parameter Defines
 //
 #define PRLI_ACC			0x01
 #define PRLI_REQ			0x02
@@ -1361,54 +1304,54 @@
 #define NO_MULTI_PAGE		0x700
 
 typedef struct {
-	USHORT	payload_length;
-	UCHAR	page_length;
-	UCHAR	cmd;
+	__u16 payload_length;
+	__u8 page_length;
+	__u8 cmd;
+
 
+	__u32 valid;
 
-	ULONG	valid;
+	__u32 orig_process_associator;
 
-	ULONG	orig_process_associator;
+	__u32 resp_process_associator;
 
-	ULONG	resp_process_associator;
-	
-	ULONG	fcp_info;
+	__u32 fcp_info;
 } PRLI_REQUEST;
 
 typedef struct {
 
-	USHORT	payload_length;
-	UCHAR	page_length;
-	UCHAR	cmd;
+	__u16 payload_length;
+	__u8 page_length;
+	__u8 cmd;
 
-	ULONG	valid;
-	ULONG	orig_process_associator;
+	__u32 valid;
+	__u32 orig_process_associator;
 
-	ULONG	resp_process_associator;
-	ULONG	reserved;
+	__u32 resp_process_associator;
+	__u32 reserved;
 } PRLO_REQUEST;
 
 typedef struct {
-	ULONG	cmd;
+	__u32 cmd;
+
+	__u32 hard_address;
 
-	ULONG	hard_address;
-	
-	UCHAR	port_name[8];
+	__u8 port_name[8];
 
-	UCHAR	node_name[8];
+	__u8 node_name[8];
 
-	ULONG	s_id;
+	__u32 s_id;
 } ADISC_PAYLOAD;
 
 struct ext_sg_entry_t {
 	__u32 len:18;		/* buffer length, bits 0-17 */
 	__u32 uba:13;		/* upper bus address bits 18-31 */
 	__u32 lba;		/* lower bus address bits 0-31 */
-}; 
+};
 
 // J. McCarty's LINK.H
 //
-//	LS_RJT Reason Codes
+//      LS_RJT Reason Codes
 //
 
 #define INVALID_COMMAND_CODE	0x01
@@ -1420,7 +1363,7 @@
 #define LS_VENDOR_UNIQUE	0xFF
 
 //
-// 	LS_RJT Reason Codes Explanations
+//      LS_RJT Reason Codes Explanations
 //
 #define NO_REASON		0x00
 #define OPTIONS_ERROR		0x01
@@ -1439,38 +1382,38 @@
 #define CMD_IN_PROCESS		0x19
 #define INVALID_IDENTIFIER	0x1F	// Invalid N_PORT Identifier
 #define INVALID_SEQ_ID		0x21
-#define ABT_INVALID_XCHNG	0x23 	// Attempt to Abort an invalid Exchange
-#define ABT_INACTIVE_XCHNG	0x25 	// Attempt to Abort an inactive Exchange
+#define ABT_INVALID_XCHNG	0x23	// Attempt to Abort an invalid Exchange
+#define ABT_INACTIVE_XCHNG	0x25	// Attempt to Abort an inactive Exchange
 #define NEED_REC_QUAL		0x27	// Recovery Qualifier required
 #define NO_LOGIN_RESOURCES	0x29	// No resources to support login
 #define NO_DATA			0x2A	// Unable to supply requested data
 #define	REQUEST_NOT_SUPPORTED	0x2C	// Request Not Supported
 
 //
-//	Link Control Codes
+//      Link Control Codes
 //
 
 //
-//	P_BSY Action Codes
+//      P_BSY Action Codes
 //
 #define SEQUENCE_TERMINATED	0x01000000
 #define SEQUENCE_ACTIVE		0x02000000
 
 //
-//	P_BSY Reason Codes
+//      P_BSY Reason Codes
 //
 #define PHYS_NPORT_BUSY		0x010000
 #define NPORT_RESOURCE_BUSY	0x020000
 
 //
-// 	P_RJT, F_RJT Action Codes
+//      P_RJT, F_RJT Action Codes
 //
 
 #define RETRYABLE_ERROR		0x01000000
 #define NON_RETRYABLE_ERROR	0x02000000
 
 //
-// 	P_RJT, F_RJT Reason Codes
+//      P_RJT, F_RJT Reason Codes
 //
 #define INVALID_D_ID		0x010000
 #define INVALID_S_ID		0x020000
@@ -1500,7 +1443,7 @@
 #define P_VENDOR_UNIQUE		0xFF0000
 
 //
-// 	BA_RJT Reason Codes
+//      BA_RJT Reason Codes
 //
 #define BA_INVALID_COMMAND	0x00010000
 #define BA_LOGICAL_ERROR	0x00030000
@@ -1509,7 +1452,7 @@
 #define BA_UNABLE_TO_PERFORM	0x00090000
 
 //
-// 	BA_RJT Reason Explanation Codes
+//      BA_RJT Reason Explanation Codes
 //
 #define BA_NO_REASON		0x00000000
 #define BA_INVALID_OX_RX	0x00000300
@@ -1517,5 +1460,4 @@
 
 
 
-#endif /* CPQFCTSSTRUCTS_H	*/
-
+#endif				/* CPQFCTSSTRUCTS_H      */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfcTStrigger.c linux-2.4.21/drivers/scsi/cpqfcTStrigger.c
--- linux-2.4.20/drivers/scsi/cpqfcTStrigger.c	2001-08-12 17:51:41.000000000 +0000
+++ linux-2.4.21/drivers/scsi/cpqfcTStrigger.c	2002-12-18 18:58:05.000000000 +0000
@@ -12,22 +12,22 @@
 #include <linux/pci.h>
 #include <asm/io.h>
 
-void TriggerHBA( void* IOBaseUpper, int Print)
+void TriggerHBA(void *io_upper, int print)
 {
-  __u32 long value;
+	__u32 long value;
 
-  // get initial value in hopes of not modifying any other GPIO line
-  IOBaseUpper += 0x188;  // TachTL/TS Control reg
-  
-  value = readl( IOBaseUpper);
-  // set HIGH to trigger external analyzer (tested on Dolche Finisar 1Gb GTA)
-  // The Finisar anaylzer triggers on low-to-high TTL transition
-  value |= 0x01; // set bit 0
+	// get initial value in hopes of not modifying any other GPIO line
+	io_upper += 0x188;	// TachTL/TS Control reg
 
-  writel( value, IOBaseUpper);
+	value = readl(io_upper);
+	// set HIGH to trigger external analyzer (tested on Dolche Finisar 1Gb GTA)
+	// The Finisar anaylzer triggers on low-to-high TTL transition
+	value |= 0x01;		// set bit 0
 
-  if( Print)
-    printk( " -GPIO0 set- ");
+	writel(value, io_upper);
+
+	if (print)
+		printk(" -GPIO0 set- ");
 }
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfcTStrigger.h linux-2.4.21/drivers/scsi/cpqfcTStrigger.h
--- linux-2.4.20/drivers/scsi/cpqfcTStrigger.h	2001-08-12 17:51:41.000000000 +0000
+++ linux-2.4.21/drivers/scsi/cpqfcTStrigger.h	2002-12-18 18:58:08.000000000 +0000
@@ -1,8 +1,7 @@
 // don't do this unless you have the right hardware!
 #define TRIGGERABLE_HBA 0
 #if TRIGGERABLE_HBA
-void TriggerHBA( void*, int);
+void TriggerHBA(void *, int);
 #else
 #define TriggerHBA(x, y)
 #endif
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfcTSworker.c linux-2.4.21/drivers/scsi/cpqfcTSworker.c
--- linux-2.4.20/drivers/scsi/cpqfcTSworker.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/scsi/cpqfcTSworker.c	2002-12-18 18:58:05.000000000 +0000
@@ -44,7 +44,7 @@
 
 
 #include "sd.h"
-#include "hosts.h"   // struct Scsi_Host definition for T handler
+#include "hosts.h"		// struct Scsi_Host definition for T handler
 #include "cpqfcTSchip.h"
 #include "cpqfcTSstructs.h"
 #include "cpqfcTStrigger.h"
@@ -116,724 +116,579 @@
 
 // local functions
 
-static void SetLoginFields(
-  PFC_LOGGEDIN_PORT pLoggedInPort,
-  TachFCHDR_GCMND* fchs,
-  BOOLEAN PDisc,
-  BOOLEAN Originator);
+static void SetLoginFields(PFC_LOGGEDIN_PORT pLoggedInPort, TachFCHDR_GCMND * fchs, u8 PDisc, u8 Originator);
 
-static void AnalyzeIncomingFrame( 
-       CPQFCHBA *cpqfcHBAdata,
-       ULONG QNdx );
+static void AnalyzeIncomingFrame(CPQFCHBA * dev, u32 QNdx);
 
-static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds );
+static void SendLogins(CPQFCHBA * dev, __u32 * FabricPortIds);
 
-static int verify_PLOGI( PTACHYON fcChip,
-      TachFCHDR_GCMND* fchs, ULONG* reject_explain);
-static int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain);
+static int verify_PLOGI(PTACHYON fcChip, TachFCHDR_GCMND * fchs, u32 * reject_explain);
+static int verify_PRLI(TachFCHDR_GCMND * fchs, u32 * reject_explain);
 
-static void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type);
-static void BuildLinkServicePayload( 
-              PTACHYON fcChip, ULONG type, void* payload);
+static void LoadWWN(PTACHYON fcChip, u8 * dest, u8 type);
+static void BuildLinkServicePayload(PTACHYON fcChip, u32 type, void *payload);
 
-static void UnblockScsiDevice( struct Scsi_Host *HostAdapter, 
-        PFC_LOGGEDIN_PORT pLoggedInPort);
+static void UnblockScsiDevice(struct Scsi_Host *HostAdapter, PFC_LOGGEDIN_PORT pLoggedInPort);
 
-static void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID);
+static void cpqfcTSCheckandSnoopFCP(PTACHYON fcChip, u32 x_ID);
 
-static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata);
+static void CompleteBoardLockCmnd(CPQFCHBA * dev);
 
-static void RevalidateSEST( struct Scsi_Host *HostAdapter, 
-		        PFC_LOGGEDIN_PORT pLoggedInPort);
+static void RevalidateSEST(struct Scsi_Host *HostAdapter, PFC_LOGGEDIN_PORT pLoggedInPort);
 
-static void IssueReportLunsCommand( 
-              CPQFCHBA* cpqfcHBAdata, 
-	      TachFCHDR_GCMND* fchs);
+static void IssueReportLunsCommand(CPQFCHBA * dev, TachFCHDR_GCMND * fchs);
 
 // (see scsi_error.c comments on kernel task creation)
 
-void cpqfcTSWorkerThread( void *host)
+void cpqfcTSWorkerThread(void *host)
 {
-  struct Scsi_Host *HostAdapter = (struct Scsi_Host*)host;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; 
+	struct Scsi_Host *shpnt = (struct Scsi_Host *) host;
+	CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
 #ifdef PCI_KERNEL_TRACE
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	PTACHYON fcChip = &dev->fcChip;
 #endif
-  struct fs_struct *fs;
-  DECLARE_MUTEX_LOCKED(fcQueReady);
-  DECLARE_MUTEX_LOCKED(fcTYOBcomplete); 
-  DECLARE_MUTEX_LOCKED(TachFrozen);  
-  DECLARE_MUTEX_LOCKED(BoardLock);  
+	struct fs_struct *fs;
+	DECLARE_MUTEX_LOCKED(fcQueReady);
+	DECLARE_MUTEX_LOCKED(fcTYOBcomplete);
+	DECLARE_MUTEX_LOCKED(TachFrozen);
+	DECLARE_MUTEX_LOCKED(BoardLock);
 
-  ENTER("WorkerThread");
+	ENTER("WorkerThread");
 
-  lock_kernel();
+	lock_kernel();
 	/*
 	 * If we were started as result of loading a module, close all of the
 	 * user space pages.  We don't need them, and if we didn't close them
 	 * they would be locked into memory.
+	 *
+	 * FIXME: should use daemonize!
 	 */
-  exit_mm(current);
+	exit_mm(current);
 
-  current->session = 1;
-  current->pgrp = 1;
-	
-  /* Become as one with the init task */
-	
-  exit_fs(current);	/* current->fs->count--; */
-  fs = init_task.fs;
-  // Some kernels compiled for SMP, while actually running
-  // on a uniproc machine, will return NULL for this call
-  if( !fs)
-  {
-    printk(" cpqfcTS FATAL: fs is NULL! Is this an SMP kernel on uniproc machine?\n ");
-  }
- 
-  else
-  { 
-    current->fs = fs;
-    atomic_inc(&fs->count);
-  }
+	current->session = 1;
+	current->pgrp = 1;
 
-  siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
+	/* Become as one with the init task */
 
+	exit_fs(current);	/* current->fs->count--; */
+	fs = init_task.fs;
+	current->fs = fs;
+	atomic_inc(&fs->count);
 
-  /*
-   * Set the name of this process.
-   */
-  sprintf(current->comm, "cpqfcTS_wt_%d", HostAdapter->host_no);
+	siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
 
-  cpqfcHBAdata->fcQueReady = &fcQueReady;  // primary wait point
-  cpqfcHBAdata->TYOBcomplete = &fcTYOBcomplete;
-  cpqfcHBAdata->TachFrozen = &TachFrozen;
-    
- 
-  cpqfcHBAdata->worker_thread = current;
-  
-  unlock_kernel();
 
-  if( cpqfcHBAdata->notify_wt != NULL )
-    up( cpqfcHBAdata->notify_wt); // OK to continue
+	/*
+	 * Set the name of this process.
+	 */
+	sprintf(current->comm, "cpqfcTS_wt_%d", shpnt->host_no);
 
-  while(1)
-  {
-    unsigned long flags;
+	dev->fcQueReady = &fcQueReady;	// primary wait point
+	dev->TYOBcomplete = &fcTYOBcomplete;
+	dev->TachFrozen = &TachFrozen;
 
-    down_interruptible( &fcQueReady);  // wait for something to do
 
-    if (signal_pending(current) )
-      break;
-    
-    PCI_TRACE( 0x90)
-    // first, take the IO lock so the SCSI upper layers can't call
-    // into our _quecommand function (this also disables INTs)
-    spin_lock_irqsave( &io_request_lock, flags); // STOP _que function
-    PCI_TRACE( 0x90)
-         
-    CPQ_SPINLOCK_HBA( cpqfcHBAdata)
-    // next, set this pointer to indicate to the _quecommand function
-    // that the board is in use, so it should que the command and 
-    // immediately return (we don't actually require the semaphore function
-    // in this driver rev)
+	dev->worker_thread = current;
 
-    cpqfcHBAdata->BoardLock = &BoardLock;
+	unlock_kernel();
 
-    PCI_TRACE( 0x90)
+	if (dev->notify_wt != NULL)
+		up(dev->notify_wt);	// OK to continue
 
-    // release the IO lock (and re-enable interrupts)
-    spin_unlock_irqrestore( &io_request_lock, flags);
+	while (1) {
+		unsigned long flags;
 
-    // disable OUR HBA interrupt (keep them off as much as possible
-    // during error recovery)
-    disable_irq( cpqfcHBAdata->HostAdapter->irq);
+		down_interruptible(&fcQueReady);	// wait for something to do
 
-    // OK, let's process the Fibre Channel Link Q and do the work
-    cpqfcTS_WorkTask( HostAdapter);
+		if (signal_pending(current))
+			break;
 
-    // hopefully, no more "work" to do;
-    // re-enable our INTs for "normal" completion processing
-    enable_irq( cpqfcHBAdata->HostAdapter->irq);
- 
+		PCI_TRACE(0x90)
+		// first, take the IO lock so the SCSI upper layers can't call
+		// into our _quecommand function (this also disables INTs)
+		spin_lock_irqsave(&io_request_lock, flags);	// STOP _que function
+		PCI_TRACE(0x90)
 
-    cpqfcHBAdata->BoardLock = NULL; // allow commands to be queued
-    CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
+		CPQ_SPINLOCK_HBA(dev)
+		// next, set this pointer to indicate to the _quecommand function
+		// that the board is in use, so it should que the command and 
+		// immediately return (we don't actually require the semaphore function
+		// in this driver rev)
+		dev->BoardLock = &BoardLock;
 
+		PCI_TRACE(0x90)
+		// release the IO lock (and re-enable interrupts)
+		spin_unlock_irqrestore(&io_request_lock, flags);
 
-    // Now, complete any Cmnd we Q'd up while BoardLock was held
+		// disable OUR HBA interrupt (keep them off as much as possible
+		// during error recovery)
+		disable_irq(dev->HostAdapter->irq);
 
-    CompleteBoardLockCmnd( cpqfcHBAdata);
-  
+		// OK, let's process the Fibre Channel Link Q and do the work
+		cpqfcTS_WorkTask(shpnt);
 
-  }
-  // hopefully, the signal was for our module exit...
-  if( cpqfcHBAdata->notify_wt != NULL )
-    up( cpqfcHBAdata->notify_wt); // yep, we're outta here
+		// hopefully, no more "work" to do;
+		// re-enable our INTs for "normal" completion processing
+		enable_irq(dev->HostAdapter->irq);
+
+
+		dev->BoardLock = NULL;	// allow commands to be queued
+		CPQ_SPINUNLOCK_HBA(dev)
+
+		// Now, complete any Cmnd we Q'd up while BoardLock was held
+		CompleteBoardLockCmnd(dev);
+
+
+	}
+	// hopefully, the signal was for our module exit...
+	if (dev->notify_wt != NULL)
+		up(dev->notify_wt);	// yep, we're outta here
 }
 
 
 // Freeze Tachyon routine.
-// If Tachyon is already frozen, return FALSE
-// If Tachyon is not frozen, call freeze function, return TRUE
+// If Tachyon is already frozen, return 0
+// If Tachyon is not frozen, call freeze function, return 1
 //
-static BOOLEAN FreezeTach( CPQFCHBA *cpqfcHBAdata)
+static u8 FreezeTach(CPQFCHBA * dev)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  BOOLEAN FrozeTach = FALSE;
-  // It's possible that the chip is already frozen; if so,
-  // "Freezing" again will NOT! generate another Freeze
-  // Completion Message.
-
-  if( (fcChip->Registers.TYstatus.value & 0x70000) != 0x70000)
-  {  // (need to freeze...)
-    fcChip->FreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
-
-    // 2. Get Tach freeze confirmation
-    // (synchronize SEST manipulation with Freeze Completion Message)
-    // we need INTs on so semaphore can be set.	
-    enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Semaphore
-    down_interruptible( cpqfcHBAdata->TachFrozen); // wait for INT handler sem.
-    // can we TIMEOUT semaphore wait?? TBD
-    disable_irq( cpqfcHBAdata->HostAdapter->irq); 
-
-    FrozeTach = TRUE;
-  }  // (else, already frozen)
- 
-  return FrozeTach;
-}  
-
-
-
+	PTACHYON fcChip = &dev->fcChip;
+	u8 FrozeTach = 0;
+	// It's possible that the chip is already frozen; if so,
+	// "Freezing" again will NOT! generate another Freeze
+	// Completion Message.
+
+	if ((fcChip->Registers.TYstatus.value & 0x70000) != 0x70000) {	// (need to freeze...)
+		fcChip->FreezeTachyon(fcChip, 2);	// both ERQ and FCP assists
+		// 2. Get Tach freeze confirmation
+		// (synchronize SEST manipulation with Freeze Completion Message)
+		// we need INTs on so semaphore can be set. 
+		enable_irq(dev->HostAdapter->irq);	// only way to get Semaphore
+		down_interruptible(dev->TachFrozen);	// wait for INT handler sem.
+		// can we TIMEOUT semaphore wait?? TBD
+		disable_irq(dev->HostAdapter->irq);
+		FrozeTach = 1;
+	}			// (else, already frozen)
+	return FrozeTach;
+}
 
 // This is the kernel worker thread task, which processes FC
 // tasks which were queued by the Interrupt handler or by
 // other WorkTask functions.
 
 #define DBG 1
+
 //#undef DBG
-void cpqfcTS_WorkTask( struct Scsi_Host *HostAdapter)
+void cpqfcTS_WorkTask(struct Scsi_Host *shpnt)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG QconsumerNdx;
-  LONG ExchangeID;
-  ULONG ulStatus=0;
-  TachFCHDR_GCMND fchs;
-  PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
-
-  ENTER("WorkTask");
-
-  // copy current index to work on
-  QconsumerNdx = fcLQ->consumer;
-
-  PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x90)
-  
-
-  // NOTE: when this switch completes, we will "consume" the Que item
-//  printk("Que type %Xh\n", fcLQ->Qitem[QconsumerNdx].Type);
-  switch( fcLQ->Qitem[QconsumerNdx].Type )
-  {
-      // incoming frame - link service (ACC, UNSOL REQ, etc.)
-      // or FCP-SCSI command
-    case SFQ_UNKNOWN:  
-      AnalyzeIncomingFrame( cpqfcHBAdata, QconsumerNdx );
+	CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 QconsumerNdx;
+	s32 ExchangeID;
+	u32 ulStatus = 0;
+	TachFCHDR_GCMND fchs;
+	PFC_LINK_QUE fcLQ = dev->fcLQ;
+
+	ENTER("WorkTask");
+
+	// copy current index to work on
+	QconsumerNdx = fcLQ->consumer;
+
+	PCI_TRACEO(fcLQ->Qitem[QconsumerNdx].Type, 0x90)
+
+	// NOTE: when this switch completes, we will "consume" the Que item
+	//  printk("Que type %Xh\n", fcLQ->Qitem[QconsumerNdx].Type);
+	switch (fcLQ->Qitem[QconsumerNdx].Type) 
+	{
+		// incoming frame - link service (ACC, UNSOL REQ, etc.)
+		// or FCP-SCSI command
+	case SFQ_UNKNOWN:
+		AnalyzeIncomingFrame(dev, QconsumerNdx);
+		break;
 
-      break;
-  
-    
-    
-    case EXCHANGE_QUEUED:  // an Exchange (i.e. FCP-SCSI) was previously
-                           // Queued because the link was down.  The  
-                           // heartbeat timer detected it and Queued it here.
-                           // We attempt to start it again, and if
-                           // successful we clear the EXCHANGE_Q flag.
-                           // If the link doesn't come up, the Exchange
-                           // will eventually time-out.
-
-      ExchangeID = (LONG)  // x_ID copied from DPC timeout function
-                   fcLQ->Qitem[QconsumerNdx].ulBuff[0];
-
-      // It's possible that a Q'd exchange could have already
-      // been started by other logic (e.g. ABTS process)
-      // Don't start if already started (Q'd flag clear)
-
-      if( Exchanges->fcExchange[ExchangeID].status & EXCHANGE_QUEUED )
-      {
-//        printk(" *Start Q'd x_ID %Xh: type %Xh ", 
-//          ExchangeID, Exchanges->fcExchange[ExchangeID].type);
-      
-        ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID);
-        if( !ulStatus )
-        {
-//          printk("success* ");
-        }	
-        else
-        {
+	case EXCHANGE_QUEUED:	
+		// an Exchange (i.e. FCP-SCSI) was previously
+		// Queued because the link was down.  The  
+		// heartbeat timer detected it and Queued it here.
+		// We attempt to start it again, and if
+		// successful we clear the EXCHANGE_Q flag.
+		// If the link doesn't come up, the Exchange
+		// will eventually time-out.
+
+		ExchangeID = (s32) fcLQ->Qitem[QconsumerNdx].ulBuff[0]; // x_ID copied from DPC timeout function
+
+		// It's possible that a Q'd exchange could have already
+		// been started by other logic (e.g. ABTS process)
+		// Don't start if already started (Q'd flag clear)
+
+		if (Exchanges->fcExchange[ExchangeID].status & EXCHANGE_QUEUED) {
+//      		printk(" *Start Q'd x_ID %Xh: type %Xh ", 
+//				ExchangeID, Exchanges->fcExchange[ExchangeID].type);
+
+			ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
+			if (!ulStatus) {
+//				printk("success* ");
+			} else {
 #ifdef DBG
-      
-          if( ulStatus == EXCHANGE_QUEUED)
-            printk("Queued* ");
-          else
-            printk("failed* ");
-		
+				if (ulStatus == EXCHANGE_QUEUED)
+					printk("Queued* ");
+				else
+					printk("failed* ");
 #endif
-	} 
-      }
-      break;
+			}
+		}
+		break;
 
+	case LINKDOWN:
+		// (lots of things already done in INT handler) future here?
+		break;
 
-    case LINKDOWN:  
-      // (lots of things already done in INT handler) future here?
-      break;
-    
-    
-    case LINKACTIVE:   // Tachyon set the Lup bit in FM status
-                       // NOTE: some misbehaving FC ports (like Tach2.1)
-                       // can re-LIP immediately after a LIP completes.
-      
-      // if "initiator", need to verify LOGs with ports
-//      printk("\n*LNKUP* ");
+	case LINKACTIVE:	// Tachyon set the Lup bit in FM status
+		// NOTE: some misbehaving FC ports (like Tach2.1)
+		// can re-LIP immediately after a LIP completes.
+		// if "initiator", need to verify LOGs with ports
+//		printk("\n*LNKUP* ");
+
+		if (fcChip->Options.initiator)
+			SendLogins(dev, NULL);	// PLOGI or PDISC, based on fcPort data
+		// if SendLogins successfully completes, PortDiscDone
+		// will be set.
+		// If SendLogins was successful, then we expect to get incoming
+		// ACCepts or REJECTs, which are handled below.
+		break;
 
-      if( fcChip->Options.initiator )
-        SendLogins( cpqfcHBAdata, NULL ); // PLOGI or PDISC, based on fcPort data
-                  // if SendLogins successfully completes, PortDiscDone
-                  // will be set.
-      
-      
-      // If SendLogins was successful, then we expect to get incoming
-      // ACCepts or REJECTs, which are handled below.
+		// LinkService and Fabric request/reply processing
+	case ELS_FDISC:	// need to send Fabric Discovery (Login)
+	case ELS_FLOGI:	// need to send Fabric Login
+	case ELS_SCR:		// need to send State Change Registration
+	case FCS_NSR:		// need to send Name Service Request
+	case ELS_PLOGI:	// need to send PLOGI
+	case ELS_ACC:		// send generic ACCept
+	case ELS_PLOGI_ACC:	// need to send ELS ACCept frame to recv'd PLOGI
+	case ELS_PRLI_ACC:	// need to send ELS ACCept frame to recv'd PRLI
+	case ELS_LOGO:		// need to send ELS LOGO (logout)
+	case ELS_LOGO_ACC:	// need to send ELS ACCept frame to recv'd PLOGI
+	case ELS_RJT:		// ReJecT reply
+	case ELS_PRLI:		// need to send ELS PRLI
+
+
+//		printk(" *ELS %Xh* ", fcLQ->Qitem[QconsumerNdx].Type);
+		// if PortDiscDone is not set, it means the SendLogins routine
+		// failed to complete -- assume that LDn occurred, so login frames
+		// are invalid
+		if (!dev->PortDiscDone)	// cleared by LDn
+		{
+			printk("Discard Q'd ELS login frame\n");
+			break;
+		}
 
-      break;
+		ulStatus = cpqfcTSBuildExchange(dev, fcLQ->Qitem[QconsumerNdx].Type,	// e.g. PLOGI
+						(TachFCHDR_GCMND *)
+						fcLQ->Qitem[QconsumerNdx].ulBuff,	// incoming fchs
+						NULL,	// no data (no scatter/gather list)
+						&ExchangeID);	// fcController->fcExchanges index, -1 if failed
+
+		if (!ulStatus)	// Exchange setup?
+		{
+			ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
+			if (!ulStatus) {
+				// submitted to Tach's Outbound Que (ERQ PI incremented)
+				// waited for completion for ELS type (Login frames issued
+				// synchronously)
+			} else
+				// check reason for Exchange not being started - we might
+				// want to Queue and start later, or fail with error
+			{
 
-    // LinkService and Fabric request/reply processing
-    case ELS_FDISC:      // need to send Fabric Discovery (Login)
-    case ELS_FLOGI:      // need to send Fabric Login
-    case ELS_SCR:        // need to send State Change Registration
-    case FCS_NSR:        // need to send Name Service Request
-    case ELS_PLOGI:      // need to send PLOGI
-    case ELS_ACC:        // send generic ACCept
-    case ELS_PLOGI_ACC:  // need to send ELS ACCept frame to recv'd PLOGI
-    case ELS_PRLI_ACC:   // need to send ELS ACCept frame to recv'd PRLI
-    case ELS_LOGO:      // need to send ELS LOGO (logout)
-    case ELS_LOGO_ACC:  // need to send ELS ACCept frame to recv'd PLOGI
-    case ELS_RJT:         // ReJecT reply
-    case ELS_PRLI:       // need to send ELS PRLI
- 
-    
-//      printk(" *ELS %Xh* ", fcLQ->Qitem[QconsumerNdx].Type);
-      // if PortDiscDone is not set, it means the SendLogins routine
-      // failed to complete -- assume that LDn occurred, so login frames
-      // are invalid
-      if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
-      {
-        printk("Discard Q'd ELS login frame\n");
-        break;  
-      }
-
-      ulStatus = cpqfcTSBuildExchange(
-          cpqfcHBAdata,
-          fcLQ->Qitem[QconsumerNdx].Type, // e.g. PLOGI
-          (TachFCHDR_GCMND*)
-            fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
-          NULL,         // no data (no scatter/gather list)
-          &ExchangeID );// fcController->fcExchanges index, -1 if failed
-
-      if( !ulStatus ) // Exchange setup?
-      {
-        ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
-        if( !ulStatus )
-        {
-          // submitted to Tach's Outbound Que (ERQ PI incremented)
-          // waited for completion for ELS type (Login frames issued
-          // synchronously)
-        }
-        else
-          // check reason for Exchange not being started - we might
-          // want to Queue and start later, or fail with error
-        {
-
-        }
-      }
-
-      else   // Xchange setup failed...
-        printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
-
-      break;
-
-    case SCSI_REPORT_LUNS:
-      // pass the incoming frame (actually, it's a PRLI frame)
-      // so we can send REPORT_LUNS, in order to determine VSA/PDU
-      // FCP-SCSI Lun address mode
-      IssueReportLunsCommand( cpqfcHBAdata, (TachFCHDR_GCMND*)
-            fcLQ->Qitem[QconsumerNdx].ulBuff); 
+			}
+		}
 
-      break;
-      
+		else		// Xchange setup failed...
+			printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus);
 
+		break;
 
+	case SCSI_REPORT_LUNS:
+		// pass the incoming frame (actually, it's a PRLI frame)
+		// so we can send REPORT_LUNS, in order to determine VSA/PDU
+		// FCP-SCSI Lun address mode
+		IssueReportLunsCommand(dev, (TachFCHDR_GCMND *)
+				       fcLQ->Qitem[QconsumerNdx].ulBuff);
 
-    case BLS_ABTS:       // need to ABORT one or more exchanges
-    {
-      LONG x_ID = fcLQ->Qitem[QconsumerNdx].ulBuff[0];
-      BOOLEAN FrozeTach = FALSE;   
-     
-      if( x_ID > TACH_SEST_LEN )  // (in)sanity check
-      {
-//	printk( " cpqfcTS ERROR! BOGUS x_ID %Xh", x_ID);
-	break;
-      }
-
-
-      if( Exchanges->fcExchange[ x_ID].Cmnd == NULL ) // should be RARE
-      {
-//	printk(" ABTS %Xh Scsi Cmnd null! ", x_ID);
-	
-       break;  // nothing to abort!
-      }
+		break;
 
+	case BLS_ABTS:		// need to ABORT one or more exchanges
+		{
+			s32 x_ID = fcLQ->Qitem[QconsumerNdx].ulBuff[0];
+			u8 FrozeTach = 0;
+
+			if (x_ID > TACH_SEST_LEN)	// (in)sanity check
+			{
+//				printk( " cpqfcTS ERROR! BOGUS x_ID %Xh", x_ID);
+				break;
+			}
+			if (Exchanges->fcExchange[x_ID].Cmnd == NULL)	// should be RARE
+			{
+//				printk(" ABTS %Xh Scsi Cmnd null! ", x_ID);
+				break;	// nothing to abort!
+			}
 //#define ABTS_DBG
 #ifdef ABTS_DBG
-      printk("INV SEST[%X] ", x_ID); 
-      if( Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT)
-      {
-        printk("FC2TO");
-      }
-      if( Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)
-      {
-        printk("IA");
-      }
-      if( Exchanges->fcExchange[x_ID].status & PORTID_CHANGED)
-      {
-        printk("PORTID");
-      }
-      if( Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)
-      {
-        printk("DEVRM");
-      }
-      if( Exchanges->fcExchange[x_ID].status & LINKFAIL_TX)
-      {
-        printk("LKF");
-      }
-      if( Exchanges->fcExchange[x_ID].status & FRAME_TO)
-      {
-        printk("FRMTO");
-      }
-      if( Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY)
-      {
-        printk("ABSQ");
-      }
-      if( Exchanges->fcExchange[x_ID].status & SFQ_FRAME)
-      {
-        printk("SFQFR");
-      }
-
-      if( Exchanges->fcExchange[ x_ID].type == 0x2000)
-        printk(" WR");
-      else if( Exchanges->fcExchange[ x_ID].type == 0x3000)
-        printk(" RD");
-      else if( Exchanges->fcExchange[ x_ID].type == 0x10)
-        printk(" ABTS");
-      else
-        printk(" %Xh", Exchanges->fcExchange[ x_ID].type); 
-
-      if( !(Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT))
-      {
-	printk(" Cmd %p, ", 
-          Exchanges->fcExchange[ x_ID].Cmnd);
-
-        printk(" brd/chn/trg/lun %d/%d/%d/%d port_id %06X\n", 
-          cpqfcHBAdata->HBAnum,
-          Exchanges->fcExchange[ x_ID].Cmnd->channel,
-          Exchanges->fcExchange[ x_ID].Cmnd->target,
-          Exchanges->fcExchange[ x_ID].Cmnd->lun,
-          Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
-      }
-      else  // assume that Cmnd ptr is invalid on _abort()
-      {
-	printk(" Cmd ptr invalid\n");
-      }
-     
-#endif      
-
-      
-      // Steps to ABORT a SEST exchange:
-      // 1. Freeze TL SCSI assists & ERQ (everything)
-      // 2. Receive FROZEN inbound CM (must succeed!)
-      // 3. Invalidate x_ID SEST entry 
-      // 4. Resume TL SCSI assists & ERQ (everything)
-      // 5. Build/start on exchange - change "type" to BLS_ABTS,
-      //    timeout to X sec (RA_TOV from PLDA is actually 0)
-      // 6. Set Exchange Q'd status if ABTS cannot be started,
-      //    or simply complete Exchange in "Terminate" condition
-
-  PCI_TRACEO( x_ID, 0xB4)
-      
-      // 1 & 2 . Freeze Tach & get confirmation of freeze
-      FrozeTach = FreezeTach( cpqfcHBAdata);
-
-      // 3. OK, Tachyon is frozen, so we can invalidate SEST exchange.
-      // FC2_TIMEOUT means we are originating the abort, while
-      // TARGET_ABORT means we are ACCepting an abort.
-      // LINKFAIL_TX, ABORTSEQ_NOFITY, INV_ENTRY or FRAME_TO are 
-      // all from Tachyon:
-      // Exchange was corrupted by LDn or other FC physical failure
-      // INITIATOR_ABORT means the upper layer driver/application
-      // requested the abort.
-
-
-	  
-      // clear bit 31 (VALid), to invalidate & take control from TL
-      fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
-
-
-      // examine and Tach's "Linked List" for IWEs that 
-      // received (nearly) simultaneous transfer ready (XRDY) 
-      // repair linked list if necessary (TBD!)
-      // (If we ignore the "Linked List", we will time out
-      // WRITE commands where we received the FCP-SCSI XFRDY
-      // frame (because Tachyon didn't processes it).  Linked List
-      // management should be done as an optimization.
-
-//       readl( fcChip->Registers.ReMapMemBase+TL_MEM_SEST_LINKED_LIST ));
-
-
-      
-
-      // 4. Resume all Tachlite functions (for other open Exchanges)
-      // as quickly as possible to allow other exchanges to other ports
-      // to resume.  Freezing Tachyon may cause cascading errors, because
-      // any received SEST frame cannot be processed by the SEST.
-      // Don't "unfreeze" unless Link is operational
-      if( FrozeTach )  // did we just freeze it (above)?
-        fcChip->UnFreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
-      
-
-  PCI_TRACEO( x_ID, 0xB4)
-
-      // Note there is no confirmation that the chip is "unfrozen".  Also,
-      // if the Link is down when unfreeze is called, it has no effect.
-      // Chip will unfreeze when the Link is back up.
-
-      // 5. Now send out Abort commands if possible
-      // Some Aborts can't be "sent" (Port_id changed or gone);
-      // if the device is gone, there is no port_id to send the ABTS to.
-
-      if( !(Exchanges->fcExchange[ x_ID].status & PORTID_CHANGED)
-			  &&
-          !(Exchanges->fcExchange[ x_ID].status & DEVICE_REMOVED) )
-      {
-        Exchanges->fcExchange[ x_ID].type = BLS_ABTS;
-        fchs.s_id = Exchanges->fcExchange[ x_ID].fchs.d_id;
-        ulStatus = cpqfcTSBuildExchange(
-          cpqfcHBAdata,
-          BLS_ABTS,
-          &fchs,        // (uses only s_id)
-          NULL,         // (no scatter/gather list for ABTS)
-          &x_ID );// ABTS on this Exchange ID
-
-        if( !ulStatus ) // Exchange setup build OK?
-        {
-
-            // ABTS may be needed because an Exchange was corrupted
-            // by a Link disruption.  If the Link is UP, we can
-	    // presume that this ABTS can start immediately; otherwise,
-	    // set Que'd status so the Login functions
-            // can restart it when the FC physical Link is restored
-          if( ((fcChip->Registers.FMstatus.value &0xF0) &0x80)) // loop init?
-          {			    
-//                printk(" *set Q status x_ID %Xh on LDn* ", x_ID);
-                Exchanges->fcExchange[ x_ID].status |= EXCHANGE_QUEUED;
-          }
-
-          else  // what FC device (port_id) does the Cmd belong to?
-          {
-            PFC_LOGGEDIN_PORT pLoggedInPort = 
-              Exchanges->fcExchange[ x_ID].pLoggedInPort;
-            
-            // if Port is logged in, we might start the abort.
-	
-            if( (pLoggedInPort != NULL) 
-			      &&
-                (pLoggedInPort->prli == TRUE) ) 
-            {
-              // it's possible that an Exchange has already been Queued
-              // to start after Login completes.  Check and don't
-	      // start it (again) here if Q'd status set
-//	    printk(" ABTS xchg %Xh ", x_ID);            
- 	      if( Exchanges->fcExchange[x_ID].status & EXCHANGE_QUEUED)
-	      {
-//		    printk("already Q'd ");
-	      }
-	      else
-	      {
-//	            printk("starting ");
-		
-                fcChip->fcStats.FC2aborted++; 
-                ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
-                if( !ulStatus )
-                {
-                    // OK
-                    // submitted to Tach's Outbound Que (ERQ PI incremented)
-                }
-                else
-                {
-/*                   printk("ABTS exchange start failed -status %Xh, x_ID %Xh ",
-                        ulStatus, x_ID);
-*/
-                } 
-	      }
-	    }
-	    else
-	    {
-/*         	  printk(" ABTS NOT starting xchg %Xh, %p ",
-			       x_ID, pLoggedInPort);
-	          if( pLoggedInPort )
-	            printk("prli %d ", pLoggedInPort->prli);
-*/
-	    }		
- 	  }
-        }
-        else  // what the #@!
-        {  // how do we fail to build an Exchange for ABTS??
-              printk("ABTS exchange build failed -status %Xh, x_ID %Xh\n",
-                ulStatus, x_ID);
-        }
-      }
-      else   // abort without ABTS -- just complete exchange/Cmnd to Linux
-      {
-//            printk(" *Terminating x_ID %Xh on %Xh* ", 
-//		    x_ID, Exchanges->fcExchange[x_ID].status);
-        cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, x_ID);
-
-      }
-    } // end of ABTS case
-      break;
-
-
-
-    case BLS_ABTS_ACC:   // need to ACCept one ABTS
-                         // (NOTE! this code not updated for Linux yet..)
-      
-
-      printk(" *ABTS_ACC* ");
-      // 1. Freeze TL
-
-      fcChip->FreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
+			printk("INV SEST[%X] ", x_ID);
+			if (Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT) {
+				printk("FC2TO");
+			}
+			if (Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT) {
+				printk("IA");
+			}
+			if (Exchanges->fcExchange[x_ID].status & PORTID_CHANGED) {
+				printk("PORTID");
+			}
+			if (Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) {
+				printk("DEVRM");
+			}
+			if (Exchanges->fcExchange[x_ID].status & LINKFAIL_TX) {
+				printk("LKF");
+			}
+			if (Exchanges->fcExchange[x_ID].status & FRAME_TO) {
+				printk("FRMTO");
+			}
+			if (Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY) {
+				printk("ABSQ");
+			}
+			if (Exchanges->fcExchange[x_ID].status & SFQ_FRAME) {
+				printk("SFQFR");
+			}
 
-      memcpy(  // copy the incoming ABTS frame
-        &fchs,
-        fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
-        sizeof( fchs));
-
-      // 3. OK, Tachyon is frozen so we can invalidate SEST entry 
-      // (if necessary)
-      // Status FC2_TIMEOUT means we are originating the abort, while
-      // TARGET_ABORT means we are ACCepting an abort
-      
-      ExchangeID = fchs.ox_rx_id & 0x7FFF; // RX_ID for exchange
-//      printk("ABTS ACC for Target ExchangeID %Xh\n", ExchangeID);
+			if (Exchanges->fcExchange[x_ID].type == 0x2000)
+				printk(" WR");
+			else if (Exchanges->fcExchange[x_ID].type == 0x3000)
+				printk(" RD");
+			else if (Exchanges->fcExchange[x_ID].type == 0x10)
+				printk(" ABTS");
+			else
+				printk(" %Xh", Exchanges->fcExchange[x_ID].type);
+
+			if (!(Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)) {
+				printk(" Cmd %p, ", Exchanges->fcExchange[x_ID].Cmnd);
+
+				printk(" brd/chn/trg/lun %d/%d/%d/%d port_id %06X\n",
+				       dev->HBAnum, Exchanges->fcExchange[x_ID].Cmnd->channel, Exchanges->fcExchange[x_ID].Cmnd->target, Exchanges->fcExchange[x_ID].Cmnd->lun, Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF);
+			} else	// assume that Cmnd ptr is invalid on _abort()
+			{
+				printk(" Cmd ptr invalid\n");
+			}
+#endif
+			// Steps to ABORT a SEST exchange:
+			// 1. Freeze TL SCSI assists & ERQ (everything)
+			// 2. Receive FROZEN inbound CM (must succeed!)
+			// 3. Invalidate x_ID SEST entry 
+			// 4. Resume TL SCSI assists & ERQ (everything)
+			// 5. Build/start on exchange - change "type" to BLS_ABTS,
+			//    timeout to X sec (RA_TOV from PLDA is actually 0)
+			// 6. Set Exchange Q'd status if ABTS cannot be started,
+			//    or simply complete Exchange in "Terminate" condition
+
+			PCI_TRACEO(x_ID, 0xB4)
+			    // 1 & 2 . Freeze Tach & get confirmation of freeze
+			    FrozeTach = FreezeTach(dev);
+
+			// 3. OK, Tachyon is frozen, so we can invalidate SEST exchange.
+			// FC2_TIMEOUT means we are originating the abort, while
+			// TARGET_ABORT means we are ACCepting an abort.
+			// LINKFAIL_TX, ABORTSEQ_NOFITY, INV_ENTRY or FRAME_TO are 
+			// all from Tachyon:
+			// Exchange was corrupted by LDn or other FC physical failure
+			// INITIATOR_ABORT means the upper layer driver/application
+			// requested the abort.
+
+			// clear bit 31 (VALid), to invalidate & take control from TL
+			fcChip->SEST->u[x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
+
+			// examine and Tach's "Linked List" for IWEs that 
+			// received (nearly) simultaneous transfer ready (XRDY) 
+			// repair linked list if necessary (TBD!)
+			// (If we ignore the "Linked List", we will time out
+			// WRITE commands where we received the FCP-SCSI XFRDY
+			// frame (because Tachyon didn't processes it).  Linked List
+			// management should be done as an optimization.
+
+//			readl( fcChip->Registers.ReMapMemBase+TL_MEM_SEST_LINKED_LIST ));
+
+			// 4. Resume all Tachlite functions (for other open Exchanges)
+			// as quickly as possible to allow other exchanges to other ports
+			// to resume.  Freezing Tachyon may cause cascading errors, because
+			// any received SEST frame cannot be processed by the SEST.
+			// Don't "unfreeze" unless Link is operational
+			if (FrozeTach)	// did we just freeze it (above)?
+				fcChip->UnFreezeTachyon(fcChip, 2);	// both ERQ and FCP assists
+
+			PCI_TRACEO(x_ID, 0xB4)
+			    // Note there is no confirmation that the chip is "unfrozen".  Also,
+			    // if the Link is down when unfreeze is called, it has no effect.
+			    // Chip will unfreeze when the Link is back up.
+			    // 5. Now send out Abort commands if possible
+			    // Some Aborts can't be "sent" (Port_id changed or gone);
+			    // if the device is gone, there is no port_id to send the ABTS to.
+			if (!(Exchanges->fcExchange[x_ID].status & PORTID_CHANGED)
+				&& !(Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)) {
+				Exchanges->fcExchange[x_ID].type = BLS_ABTS;
+				fchs.s_id = Exchanges->fcExchange[x_ID].fchs.d_id;
+				ulStatus = cpqfcTSBuildExchange(dev, BLS_ABTS, &fchs,	// (uses only s_id)
+								NULL,	// (no scatter/gather list for ABTS)
+								&x_ID);	// ABTS on this Exchange ID
+
+				if (!ulStatus)	// Exchange setup build OK?
+				{
+
+					// ABTS may be needed because an Exchange was corrupted
+					// by a Link disruption.  If the Link is UP, we can
+					// presume that this ABTS can start immediately; otherwise,
+					// set Que'd status so the Login functions
+					// can restart it when the FC physical Link is restored
+					if (((fcChip->Registers.FMstatus.value & 0xF0) & 0x80))	// loop init?
+					{
+//						printk(" *set Q status x_ID %Xh on LDn* ", x_ID);
+						Exchanges->fcExchange[x_ID].status |= EXCHANGE_QUEUED;
+					}
+
+					else	// what FC device (port_id) does the Cmd belong to?
+					{
+						PFC_LOGGEDIN_PORT pLoggedInPort = Exchanges->fcExchange[x_ID].pLoggedInPort;
+
+						// if Port is logged in, we might start the abort.
+
+						if ((pLoggedInPort != NULL)
+						    && (pLoggedInPort->prli == 1)) {
+							// it's possible that an Exchange has already been Queued
+							// to start after Login completes.  Check and don't
+							// start it (again) here if Q'd status set
+//							printk(" ABTS xchg %Xh ", x_ID);            
+							if (Exchanges->fcExchange[x_ID].status & EXCHANGE_QUEUED) {
+//								printk("already Q'd ");
+							} else {
+//								printk("starting ");
+								fcChip->fcStats.FC2aborted++;
+								ulStatus = cpqfcTSStartExchange(dev, x_ID);
+								if (!ulStatus) {
+									// OK
+									// submitted to Tach's Outbound Que (ERQ PI incremented)
+								} else {
+//									printk("ABTS exchange start failed -status %Xh, x_ID %Xh ", ulStatus, x_ID);
+								}
+							}
+						}
+					}
+				} else	// what the #@!
+				{	// how do we fail to build an Exchange for ABTS??
+					printk("ABTS exchange build failed -status %Xh, x_ID %Xh\n", ulStatus, x_ID);
+				}
+			} else	// abort without ABTS -- just complete exchange/Cmnd to Linux
+			{
+//				printk(" *Terminating x_ID %Xh on %Xh* ", 
+//					x_ID, Exchanges->fcExchange[x_ID].status);
+				cpqfcTSCompleteExchange(dev->PciDev, fcChip, x_ID);
 
+			}
+		}		// end of ABTS case
+		break;
 
-      // sanity check on received ExchangeID
-      if( Exchanges->fcExchange[ ExchangeID].status == TARGET_ABORT )
-      {
-          // clear bit 31 (VALid), to invalidate & take control from TL
-//          printk("Invalidating SEST exchange %Xh\n", ExchangeID);
-          fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len &= 0x7FFFFFFF;
-      }
-
-
-      // 4. Resume all Tachlite functions (for other open Exchanges)
-      // as quickly as possible to allow other exchanges to other ports
-      // to resume.  Freezing Tachyon for too long may royally screw
-      // up everything!
-      fcChip->UnFreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
-      
-      // Note there is no confirmation that the chip is "unfrozen".  Also,
-      // if the Link is down when unfreeze is called, it has no effect.
-      // Chip will unfreeze when the Link is back up.
+	case BLS_ABTS_ACC:	// need to ACCept one ABTS
+		// (NOTE! this code not updated for Linux yet..)
+		printk(" *ABTS_ACC* ");
+		// 1. Freeze TL
+
+		fcChip->FreezeTachyon(fcChip, 2);	// both ERQ and FCP assists
+		memcpy(		// copy the incoming ABTS frame
+			      &fchs, fcLQ->Qitem[QconsumerNdx].ulBuff,	// incoming fchs
+			      sizeof(fchs));
+
+		// 3. OK, Tachyon is frozen so we can invalidate SEST entry 
+		// (if necessary)
+		// Status FC2_TIMEOUT means we are originating the abort, while
+		// TARGET_ABORT means we are ACCepting an abort
+
+		ExchangeID = fchs.ox_rx_id & 0x7FFF;	// RX_ID for exchange
+//		printk("ABTS ACC for Target ExchangeID %Xh\n", ExchangeID);
+
+		// sanity check on received ExchangeID
+		if (Exchanges->fcExchange[ExchangeID].status == TARGET_ABORT) {
+			// clear bit 31 (VALid), to invalidate & take control from TL
+//			printk("Invalidating SEST exchange %Xh\n", ExchangeID);
+			fcChip->SEST->u[ExchangeID].IWE.Hdr_Len &= 0x7FFFFFFF;
+		}
 
-      // 5. Now send out Abort ACC reply for this exchange
-      Exchanges->fcExchange[ ExchangeID].type = BLS_ABTS_ACC;
-      
-      fchs.s_id = Exchanges->fcExchange[ ExchangeID].fchs.d_id;
-      ulStatus = cpqfcTSBuildExchange(
-            cpqfcHBAdata,
-            BLS_ABTS_ACC,
-            &fchs,
-            NULL,         // no data (no scatter/gather list)
-            &ExchangeID );// fcController->fcExchanges index, -1 if failed
-
-      if( !ulStatus ) // Exchange setup?
-      {
-        ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
-        if( !ulStatus )
-        {
-          // submitted to Tach's Outbound Que (ERQ PI incremented)
-          // waited for completion for ELS type (Login frames issued
-          // synchronously)
-        }
-        else
-          // check reason for Exchange not being started - we might
-          // want to Queue and start later, or fail with error
-        {
-
-        } 
-      }
-      break;
-
-
-    case BLS_ABTS_RJT:   // need to ReJecT one ABTS; reject implies the
-                         // exchange doesn't exist in the TARGET context.
-                         // ExchangeID has to come from LinkService space.
-
-      printk(" *ABTS_RJT* ");
-      ulStatus = cpqfcTSBuildExchange(
-            cpqfcHBAdata,
-            BLS_ABTS_RJT,
-            (TachFCHDR_GCMND*)
-              fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
-            NULL,         // no data (no scatter/gather list)
-            &ExchangeID );// fcController->fcExchanges index, -1 if failed
-
-      if( !ulStatus ) // Exchange setup OK?
-      {
-        ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
-        // If it fails, we aren't required to retry.
-      }
-      if( ulStatus )
-      {
-        printk("Failed to send BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
-      }
-      else
-      {
-        printk("Sent BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
-      
-      }
+		// 4. Resume all Tachlite functions (for other open Exchanges)
+		// as quickly as possible to allow other exchanges to other ports
+		// to resume.  Freezing Tachyon for too long may royally screw
+		// up everything!
+		fcChip->UnFreezeTachyon(fcChip, 2);	// both ERQ and FCP assists
+
+		// Note there is no confirmation that the chip is "unfrozen".  Also,
+		// if the Link is down when unfreeze is called, it has no effect.
+		// Chip will unfreeze when the Link is back up.
+
+		// 5. Now send out Abort ACC reply for this exchange
+		Exchanges->fcExchange[ExchangeID].type = BLS_ABTS_ACC;
+
+		fchs.s_id = Exchanges->fcExchange[ExchangeID].fchs.d_id;
+		ulStatus = cpqfcTSBuildExchange(dev, BLS_ABTS_ACC, &fchs, NULL,	// no data (no scatter/gather list)
+						&ExchangeID);	// fcController->fcExchanges index, -1 if failed
+
+		if (!ulStatus)	// Exchange setup?
+		{
+			ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
+			if (!ulStatus) {
+				// submitted to Tach's Outbound Que (ERQ PI incremented)
+				// waited for completion for ELS type (Login frames issued
+				// synchronously)
+			} else
+				// check reason for Exchange not being started - we might
+				// want to Queue and start later, or fail with error
+			{
 
-      break;
+			}
+		}
+		break;
 
+	case BLS_ABTS_RJT:	// need to ReJecT one ABTS; reject implies the
+		// exchange doesn't exist in the TARGET context.
+		// ExchangeID has to come from LinkService space.
+
+		printk(" *ABTS_RJT* ");
+		ulStatus = cpqfcTSBuildExchange(dev, BLS_ABTS_RJT, (TachFCHDR_GCMND *)
+						fcLQ->Qitem[QconsumerNdx].ulBuff,	// incoming fchs
+						NULL,	// no data (no scatter/gather list)
+						&ExchangeID);	// fcController->fcExchanges index, -1 if failed
+
+		if (!ulStatus)	// Exchange setup OK?
+		{
+			ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
+			// If it fails, we aren't required to retry.
+		}
+		if (ulStatus) {
+			printk("Failed to send BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
+		} else {
+			printk("Sent BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
 
+		}
+		break;
 
-    default:
-      break;
-  }                   // end switch
-//doNothing:
-    // done with this item - now set the NEXT index
+	default:
+		break;
+	}			// end switch
+	// done with this item - now set the NEXT index
 
-  if( QconsumerNdx+1 >= FC_LINKQ_DEPTH ) // rollover test
-  {
-    fcLQ->consumer = 0;
-  }
-  else
-  { 
-    fcLQ->consumer++;
-  }
+	if (QconsumerNdx + 1 >= FC_LINKQ_DEPTH)	// rollover test
+		fcLQ->consumer = 0;
+	else
+		fcLQ->consumer++;
 
-  PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x94)
+	PCI_TRACEO(fcLQ->Qitem[QconsumerNdx].Type, 0x94)
 
-  LEAVE("WorkTask");
-  return;
+	LEAVE("WorkTask");
+	return;
 }
 
 
@@ -845,115 +700,89 @@
 // This circular Q works like Tachyon's que - the producer points to the next
 // (unused) entry.  Called by Interrupt handler, WorkerThread, Timer
 // sputlinkq
-void cpqfcTSPutLinkQue( CPQFCHBA *cpqfcHBAdata,
-  int Type, 
-  void *QueContent)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-//  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
-  ULONG ndx;
-  
-  ENTER("cpqfcTSPutLinkQ");
-
-  ndx = fcLQ->producer;
-  
-  ndx += 1;  // test for Que full
-
-
-  
-  if( ndx >= FC_LINKQ_DEPTH ) // rollover test
-    ndx = 0;
+void cpqfcTSPutLinkQue(CPQFCHBA * dev, int Type, void *QueContent)
+{
+	PTACHYON fcChip = &dev->fcChip;
+//	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	PFC_LINK_QUE fcLQ = dev->fcLQ;
+	u32 ndx;
 
-  if( ndx == fcLQ->consumer )   // QUE full test
-  {
-                       // QUE was full! lost LK command (fatal to logic)
-    fcChip->fcStats.lnkQueFull++;
+	ENTER("cpqfcTSPutLinkQ");
 
-    printk("*LinkQ Full!*");
-    TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
-/*
-    {
-      int i;
-      printk("LinkQ PI %d, CI %d\n", fcLQ->producer,
-        fcLQ->consumer);
-		      
-      for( i=0; i< FC_LINKQ_DEPTH; )
-      {
-	printk(" [%d]%Xh ", i, fcLQ->Qitem[i].Type);
-	if( (++i %8) == 0) printk("\n");
-      }
-  
-    }
-*/    
-    printk( "cpqfcTS: WARNING!! PutLinkQue - FULL!\n"); // we're hung
-  }
-  else                        // QUE next element
-  {
-    // Prevent certain multiple (back-to-back) requests.
-    // This is important in that we don't want to issue multiple
-    // ABTS for the same Exchange, or do multiple FM inits, etc.
-    // We can never be sure of the timing of events reported to
-    // us by Tach's IMQ, which can depend on system/bus speeds,
-    // FC physical link circumstances, etc.
-     
-    if( (fcLQ->producer != fcLQ->consumer)
-	    && 
-        (Type == FMINIT)  )
-    {
-      LONG lastNdx;  // compute previous producer index
-      if( fcLQ->producer)
-        lastNdx = fcLQ->producer- 1;
-      else
-	lastNdx = FC_LINKQ_DEPTH-1;
+	ndx = fcLQ->producer;
 
+	ndx += 1;		// test for Que full
 
-      if( fcLQ->Qitem[lastNdx].Type == FMINIT)
-      {
-//        printk(" *skip FMINIT Q post* ");
-//        goto DoneWithPutQ;
-      }
 
-    }
 
-    // OK, add the Q'd item...
-    
-    fcLQ->Qitem[fcLQ->producer].Type = Type;
-   
-    memcpy(
-        fcLQ->Qitem[fcLQ->producer].ulBuff,
-        QueContent, 
-        sizeof(fcLQ->Qitem[fcLQ->producer].ulBuff));
+	if (ndx >= FC_LINKQ_DEPTH)	// rollover test
+		ndx = 0;
 
-    fcLQ->producer = ndx;  // increment Que producer
+	if (ndx == fcLQ->consumer)	// QUE full test
+	{
+		// QUE was full! lost LK command (fatal to logic)
+		fcChip->fcStats.lnkQueFull++;
 
-    // set semaphore to wake up Kernel (worker) thread
-    // 
-    up( cpqfcHBAdata->fcQueReady );
-  }
+		printk("*LinkQ Full!*");
+		TriggerHBA(fcChip->Registers.ReMapMemBase, 1);
+/*
+		{
+			int i;
+			printk("LinkQ PI %d, CI %d\n", fcLQ->producer, fcLQ->consumer);
+		      
+			for( i=0; i< FC_LINKQ_DEPTH; )
+			{
+				printk(" [%d]%Xh ", i, fcLQ->Qitem[i].Type);
+				if( (++i %8) == 0)
+					printk("\n");
+			}
+		}
+*/
+		printk("cpqfcTS: WARNING!! PutLinkQue - FULL!\n");	// we're hung
+	}
+	else			// QUE next element
+	{
+		// Prevent certain multiple (back-to-back) requests.
+		// This is important in that we don't want to issue multiple
+		// ABTS for the same Exchange, or do multiple FM inits, etc.
+		// We can never be sure of the timing of events reported to
+		// us by Tach's IMQ, which can depend on system/bus speeds,
+		// FC physical link circumstances, etc.
+
+		if ((fcLQ->producer != fcLQ->consumer)
+		    && (Type == FMINIT)) {
+			s32 lastNdx;	// compute previous producer index
+			if (fcLQ->producer)
+				lastNdx = fcLQ->producer - 1;
+			else
+				lastNdx = FC_LINKQ_DEPTH - 1;
+
+
+			if (fcLQ->Qitem[lastNdx].Type == FMINIT) {
+//      			printk(" *skip FMINIT Q post* ");
+//        			goto DoneWithPutQ;
+			}
 
+		}
+		// OK, add the Q'd item...
+		fcLQ->Qitem[fcLQ->producer].Type = Type;
+		memcpy(fcLQ->Qitem[fcLQ->producer].ulBuff, QueContent, sizeof(fcLQ->Qitem[fcLQ->producer].ulBuff));
+		fcLQ->producer = ndx;	// increment Que producer
+		// set semaphore to wake up Kernel (worker) thread
+		up(dev->fcQueReady);
+	}
 //DoneWithPutQ:
-
-  LEAVE("cpqfcTSPutLinkQ");
+	LEAVE("cpqfcTSPutLinkQ");
 }
 
-
-
-
 // reset device ext FC link Q
-void cpqfcTSLinkQReset( CPQFCHBA *cpqfcHBAdata)
-   
+void cpqfcTSLinkQReset(CPQFCHBA * dev)
 {
-  PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
-  fcLQ->producer = 0;
-  fcLQ->consumer = 0;
-
+	PFC_LINK_QUE fcLQ = dev->fcLQ;
+	fcLQ->producer = 0;
+	fcLQ->consumer = 0;
 }
 
-
-
-
-
 // When Tachyon gets an unassisted FCP-SCSI frame, post here so
 // an arbitrary context thread (e.g. IOCTL loopback test function)
 // can process it.
@@ -961,17 +790,15 @@
 // (NOTE: Not revised for Linux)
 // This Q works like Tachyon's que - the producer points to the next
 // (unused) entry.
-void cpqfcTSPutScsiQue( CPQFCHBA *cpqfcHBAdata,
-  int Type, 
-  void *QueContent)
+void cpqfcTSPutScsiQue(CPQFCHBA * dev, int Type, void *QueContent)
 {
-//  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-//  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+//  CPQFCHBA *dev = (CPQFCHBA *)shpnt->hostdata;
+//  PTACHYON fcChip = &dev->fcChip;
 
-//  ULONG ndx;
+//  u32 ndx;
 
-//  ULONG *pExchangeID;
-//  LONG ExchangeID;
+//  u32 *pExchangeID;
+//  s32 ExchangeID;
 
 /*
   KeAcquireSpinLockAtDpcLevel( &pDevExt->fcScsiQueLock);
@@ -999,7 +826,7 @@
       // copied an FCP response frame into a buffer pointed to by the SEST
       // entry.  That buffer is allocated in the SEST structure at ->RspHDR.
       // Copy the RspHDR for use by the Que handler.
-      pExchangeID = (ULONG *)QueContent;
+      pExchangeID = (u32 *)QueContent;
       
       memcpy(
 	      pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
@@ -1020,175 +847,127 @@
 
     KeSetEvent( &pDevExt->TYIBscsi,  // signal any waiting thread
        0,                    // no priority boost
-		   FALSE );              // no waiting later for this event
+		   0 );              // no waiting later for this event
   }
   KeReleaseSpinLockFromDpcLevel( &pDevExt->fcScsiQueLock);
 */
 }
 
+static void ProcessELS_Request(CPQFCHBA *, TachFCHDR_GCMND *);
+static void ProcessELS_Reply(CPQFCHBA *, TachFCHDR_GCMND *);
+static void ProcessFCS_Reply(CPQFCHBA *, TachFCHDR_GCMND *);
 
-
-
-
-
-
-static void ProcessELS_Request( CPQFCHBA*,TachFCHDR_GCMND*);
-
-static void ProcessELS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
-
-static void ProcessFCS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
-
-void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata,
-		PFC_LOGGEDIN_PORT pFcPort)
+void cpqfcTSImplicitLogout(CPQFCHBA * dev, PFC_LOGGEDIN_PORT pFcPort)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	PTACHYON fcChip = &dev->fcChip;
 
-  if( pFcPort->port_id != 0xFFFC01 ) // don't care about Fabric
-  {
-    fcChip->fcStats.logouts++;
-    printk("cpqfcTS: Implicit logout of WWN %08X%08X, port_id %06X\n", 
-        (ULONG)pFcPort->u.liWWN,
-        (ULONG)(pFcPort->u.liWWN >>32),
-	pFcPort->port_id);
-
-  // Terminate I/O with this (Linux) Scsi target
-    cpqfcTSTerminateExchange( cpqfcHBAdata, 
-                            &pFcPort->ScsiNexus,
-	                    DEVICE_REMOVED);
-  }
-			
-  // Do an "implicit logout" - we can't really Logout the device
-  // (i.e. with LOGOut Request) because of port_id confusion
-  // (i.e. the Other port has no port_id).
-  // A new login for that WWN will have to re-write port_id (0 invalid)
-  pFcPort->port_id = 0;  // invalid!
-  pFcPort->pdisc = FALSE;
-  pFcPort->prli = FALSE;
-  pFcPort->plogi = FALSE;
-  pFcPort->flogi = FALSE;
-  pFcPort->LOGO_timer = 0;
-  pFcPort->device_blocked = TRUE; // block Scsi Requests
-  pFcPort->ScsiNexus.VolumeSetAddressing=0;	
+	if (pFcPort->port_id != 0xFFFC01)	// don't care about Fabric
+	{
+		fcChip->fcStats.logouts++;
+		printk("cpqfcTS: Implicit logout of WWN %08X%08X, port_id %06X\n", (u32) pFcPort->u.liWWN, (u32) (pFcPort->u.liWWN >> 32), pFcPort->port_id);
+
+		// Terminate I/O with this (Linux) Scsi target
+		cpqfcTSTerminateExchange(dev, &pFcPort->ScsiNexus, DEVICE_REMOVED);
+	}
+	// Do an "implicit logout" - we can't really Logout the device
+	// (i.e. with LOGOut Request) because of port_id confusion
+	// (i.e. the Other port has no port_id).
+	// A new login for that WWN will have to re-write port_id (0 invalid)
+	pFcPort->port_id = 0;	// invalid!
+	pFcPort->pdisc = 0;
+	pFcPort->prli = 0;
+	pFcPort->plogi = 0;
+	pFcPort->flogi = 0;
+	pFcPort->LOGO_timer = 0;
+	pFcPort->device_blocked = 1;	// block Scsi Requests
+	pFcPort->ScsiNexus.VolumeSetAddressing = 0;
 }
 
-  
+
 // On FC-AL, there is a chance that a previously known device can
 // be quietly removed (e.g. with non-managed hub), 
 // while a NEW device (with different WWN) took the same alpa or
 // even 24-bit port_id.  This chance is unlikely but we must always
 // check for it.
-static void TestDuplicatePortId( CPQFCHBA* cpqfcHBAdata,
-		PFC_LOGGEDIN_PORT pLoggedInPort)
+
+static void TestDuplicatePortId(CPQFCHBA * dev, PFC_LOGGEDIN_PORT pLoggedInPort)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  // set "other port" at beginning of fcPorts list
-  PFC_LOGGEDIN_PORT pOtherPortWithPortId = fcChip->fcPorts.pNextPort;
-  while( pOtherPortWithPortId ) 
-  {
-    if( (pOtherPortWithPortId->port_id == 
-         pLoggedInPort->port_id) 
-		    &&
-         (pOtherPortWithPortId != pLoggedInPort) )
-    {
-      // trouble!  (Implicitly) Log the other guy out
-      printk(" *port_id %Xh is duplicated!* ", 
-        pOtherPortWithPortId->port_id);
-      cpqfcTSImplicitLogout( cpqfcHBAdata, pOtherPortWithPortId); 
-   }
-    pOtherPortWithPortId = pOtherPortWithPortId->pNextPort;
-  }
+	PTACHYON fcChip = &dev->fcChip;
+	// set "other port" at beginning of fcPorts list
+	PFC_LOGGEDIN_PORT pOtherPortWithPortId = fcChip->fcPorts.pNextPort;
+	while (pOtherPortWithPortId) {
+		if ((pOtherPortWithPortId->port_id == pLoggedInPort->port_id)
+		    && (pOtherPortWithPortId != pLoggedInPort)) {
+			// trouble!  (Implicitly) Log the other guy out
+			printk(" *port_id %Xh is duplicated!* ", pOtherPortWithPortId->port_id);
+			cpqfcTSImplicitLogout(dev, pOtherPortWithPortId);
+		}
+		pOtherPortWithPortId = pOtherPortWithPortId->pNextPort;
+	}
 }
 
-
-
-
-
-
 // Dynamic Memory Allocation for newly discovered FC Ports.
 // For simplicity, maintain fcPorts structs for ALL
 // for discovered devices, including those we never do I/O with
 // (e.g. Fabric addresses)
 
-static PFC_LOGGEDIN_PORT CreateFcPort( 
-	  CPQFCHBA* cpqfcHBAdata, 
-	  PFC_LOGGEDIN_PORT pLastLoggedInPort, 
-	  TachFCHDR_GCMND* fchs,
-	  LOGIN_PAYLOAD* plogi)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  PFC_LOGGEDIN_PORT pNextLoggedInPort = NULL;
-  int i;
-
-
-  printk("cpqfcTS: New FC port %06Xh WWN: ", fchs->s_id);
-  for( i=3; i>=0; i--)   // copy the LOGIN port's WWN
-    printk("%02X", plogi->port_name[i]);
-  for( i=7; i>3; i--)   // copy the LOGIN port's WWN
-    printk("%02X", plogi->port_name[i]);
-
-
-  // allocate mem for new port
-  // (these are small and rare allocations...)
-  pNextLoggedInPort = kmalloc( sizeof( FC_LOGGEDIN_PORT), GFP_ATOMIC );
-
-    
-  // allocation succeeded?  Fill out NEW PORT
-  if( pNextLoggedInPort )
-  {    
-                              // clear out any garbage (sometimes exists)
-    memset( pNextLoggedInPort, 0, sizeof( FC_LOGGEDIN_PORT));
-
-
-    // If we login to a Fabric, we don't want to treat it
-    // as a SCSI device...
-    if( (fchs->s_id & 0xFFF000) != 0xFFF000)
-    {
-      int i;
-      
-      // create a unique "virtual" SCSI Nexus (for now, just a
-      // new target ID) -- we will update channel/target on REPORT_LUNS
-      // special case for very first SCSI target...
-      if( cpqfcHBAdata->HostAdapter->max_id == 0)
-      {
-        pNextLoggedInPort->ScsiNexus.target = 0;
-        fcChip->fcPorts.ScsiNexus.target = -1; // don't use "stub"
-      }
-      else
-      {
-        pNextLoggedInPort->ScsiNexus.target =
-          cpqfcHBAdata->HostAdapter->max_id;
-      }
-
-      // initialize the lun[] Nexus struct for lun masking      
-      for( i=0; i< CPQFCTS_MAX_LUN; i++)
-        pNextLoggedInPort->ScsiNexus.lun[i] = 0xFF; // init to NOT USED
-      
-      pNextLoggedInPort->ScsiNexus.channel = 0; // cpqfcTS has 1 FC port
-      
-      printk(" SCSI Chan/Trgt %d/%d", 
-          pNextLoggedInPort->ScsiNexus.channel,
-          pNextLoggedInPort->ScsiNexus.target);
- 
-      // tell Scsi layers about the new target...
-      cpqfcHBAdata->HostAdapter->max_id++; 
-//    printk("HostAdapter->max_id = %d\n",
-//      cpqfcHBAdata->HostAdapter->max_id);		    
-    }                          
-    else
-    {
-      // device is NOT SCSI (in case of Fabric)
-      pNextLoggedInPort->ScsiNexus.target = -1;  // invalid
-    }
+static PFC_LOGGEDIN_PORT CreateFcPort(CPQFCHBA * dev, PFC_LOGGEDIN_PORT pLastLoggedInPort, TachFCHDR_GCMND * fchs, LOGIN_PAYLOAD * plogi)
+{
+	PTACHYON fcChip = &dev->fcChip;
+	PFC_LOGGEDIN_PORT pNextLoggedInPort = NULL;
+	int i;
+
+	printk("cpqfcTS: New FC port %06Xh WWN: ", fchs->s_id);
+	for (i = 3; i >= 0; i--)	// copy the LOGIN port's WWN
+		printk("%02X", plogi->port_name[i]);
+	for (i = 7; i > 3; i--)	// copy the LOGIN port's WWN
+		printk("%02X", plogi->port_name[i]);
+
+	// allocate mem for new port
+	// (these are small and rare allocations...)
+	pNextLoggedInPort = kmalloc(sizeof(FC_LOGGEDIN_PORT), GFP_ATOMIC);
+
+	// allocation succeeded?  Fill out NEW PORT
+	if (pNextLoggedInPort) {
+		// clear out any garbage (sometimes exists)
+		memset(pNextLoggedInPort, 0, sizeof(FC_LOGGEDIN_PORT));
+		// If we login to a Fabric, we don't want to treat it
+		// as a SCSI device...
+		if ((fchs->s_id & 0xFFF000) != 0xFFF000) {
+			int i;
+
+			// create a unique "virtual" SCSI Nexus (for now, just a
+			// new target ID) -- we will update channel/target on REPORT_LUNS
+			// special case for very first SCSI target...
+			if (dev->HostAdapter->max_id == 0) {
+				pNextLoggedInPort->ScsiNexus.target = 0;
+				fcChip->fcPorts.ScsiNexus.target = -1;	// don't use "stub"
+			} else {
+				pNextLoggedInPort->ScsiNexus.target = dev->HostAdapter->max_id;
+			}
 
-	  // create forward link to new port
-    pLastLoggedInPort->pNextPort = pNextLoggedInPort;
-    printk("\n");
-
-  }     
-  return pNextLoggedInPort;  // NULL on allocation failure
-}   // end NEW PORT (WWN) logic
+			// initialize the lun[] Nexus struct for lun masking      
+			for (i = 0; i < CPQFCTS_MAX_LUN; i++)
+				pNextLoggedInPort->ScsiNexus.lun[i] = 0xFF;	// init to NOT USED
+
+			pNextLoggedInPort->ScsiNexus.channel = 0;	// cpqfcTS has 1 FC port
+			printk(" SCSI Chan/Trgt %d/%d", pNextLoggedInPort->ScsiNexus.channel, pNextLoggedInPort->ScsiNexus.target);
+			// tell Scsi layers about the new target...
+			dev->HostAdapter->max_id++;
+//			printk("HostAdapter->max_id = %d\n",
+//				dev->HostAdapter->max_id);                 
+		} else {
+			// device is NOT SCSI (in case of Fabric)
+			pNextLoggedInPort->ScsiNexus.target = -1;	// invalid
+		}
 
+		// create forward link to new port
+		pLastLoggedInPort->pNextPort = pNextLoggedInPort;
+		printk("\n");
 
+	}
+	return pNextLoggedInPort;	// NULL on allocation failure
+}				// end NEW PORT (WWN) logic
 
 // For certain cases, we want to terminate exchanges without
 // sending ABTS to the device.  Examples include when an FC
@@ -1200,870 +979,620 @@
 // Since we must ensure that Tachyon is not operating on the
 // exchange, we have to freeze the chip
 // sterminateex
-void cpqfcTSTerminateExchange( 
-  CPQFCHBA* cpqfcHBAdata, SCSI_NEXUS *ScsiNexus, int TerminateStatus)
+
+void cpqfcTSTerminateExchange(CPQFCHBA * dev, SCSI_NEXUS * ScsiNexus, int TerminateStatus)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG x_ID;
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 x_ID;
+
+	if (ScsiNexus) {
+//		printk("TerminateExchange: ScsiNexus chan/target %d/%d\n",
+//			ScsiNexus->channel, ScsiNexus->target);
+	}
+	for (x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) {
+		if (Exchanges->fcExchange[x_ID].type)	// in use?
+		{
+			if (ScsiNexus == NULL)	// our HBA changed - term. all
+			{
+				Exchanges->fcExchange[x_ID].status = TerminateStatus;
+				cpqfcTSPutLinkQue(dev, BLS_ABTS, &x_ID);
+			} else {
+				// If a device, according to WWN, has been removed, it's
+				// port_id may be used by another working device, so we
+				// have to terminate by SCSI target, NOT port_id.
+				if (Exchanges->fcExchange[x_ID].Cmnd)	// Cmnd in progress?
+				{
+					if ((Exchanges->fcExchange[x_ID].Cmnd->target == ScsiNexus->target)
+					    && (Exchanges->fcExchange[x_ID].Cmnd->channel == ScsiNexus->channel)) {
+						Exchanges->fcExchange[x_ID].status = TerminateStatus;
+						cpqfcTSPutLinkQue(dev, BLS_ABTS, &x_ID);	// timed-out
+					}
+				}
+				// (in case we ever need it...)
+				// all SEST structures have a remote node ID at SEST DWORD 2
+				//          if( (fcChip->SEST->u[ x_ID ].TWE.Remote_Node_ID >> 8)
+				//                ==  port_id)
+			}
+		}
+	}
+}
 
-  if( ScsiNexus )
-  {
-//    printk("TerminateExchange: ScsiNexus chan/target %d/%d\n",
-//		    ScsiNexus->channel, ScsiNexus->target);
+static void ProcessELS_Request(CPQFCHBA * dev, TachFCHDR_GCMND * fchs)
+{
+	PTACHYON fcChip = &dev->fcChip;
+//	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+//	u32 ox_id = (fchs->ox_rx_id >>16);
+	PFC_LOGGEDIN_PORT pLoggedInPort = NULL, pLastLoggedInPort;
+	u8 NeedReject = 0;
+	u32 ls_reject_code = 0;	// default don'n know??
 
-  } 
-  
-  for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
-  {
-    if( Exchanges->fcExchange[x_ID].type )  // in use?
-    {
-      if( ScsiNexus == NULL ) // our HBA changed - term. all
-      {
-	Exchanges->fcExchange[x_ID].status = TerminateStatus;
-        cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); 
-      }
-      else
-      {
-	// If a device, according to WWN, has been removed, it's
-	// port_id may be used by another working device, so we
-	// have to terminate by SCSI target, NOT port_id.
-        if( Exchanges->fcExchange[x_ID].Cmnd) // Cmnd in progress?
-	{	                 
-	  if( (Exchanges->fcExchange[x_ID].Cmnd->target == ScsiNexus->target)
-			&&
-            (Exchanges->fcExchange[x_ID].Cmnd->channel == ScsiNexus->channel)) 
-          {
-            Exchanges->fcExchange[x_ID].status = TerminateStatus;
-            cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); // timed-out
-          }
-	}
-
-	// (in case we ever need it...)
-	// all SEST structures have a remote node ID at SEST DWORD 2
-        //          if( (fcChip->SEST->u[ x_ID ].TWE.Remote_Node_ID >> 8)
-        //                ==  port_id)
-      } 
-    }
-  }
-}
 
+	// Check the incoming frame for a supported ELS type
+	switch (fchs->pl[0] & 0xFFFF) 
+	{
+	case 0x0050:	
+		//  PDISC?
+		// Payload for PLOGI and PDISC is identical (request & reply)
+		if (!verify_PLOGI(fcChip, fchs, &ls_reject_code))	// valid payload?
+		{
+			LOGIN_PAYLOAD logi;	// FC-PH Port Login
+
+			// PDISC payload OK. If critical login fields
+			// (e.g. WWN) matches last login for this port_id,
+			// we may resume any prior exchanges
+			// with the other port
+
+			BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
+
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+							   0,	// don't search linked list for port_id
+							   &logi.port_name[0],	// search linked list for WWN
+							   &pLastLoggedInPort);	// must return non-NULL; when a port_id
+			// is not found, this pointer marks the
+			// end of the singly linked list
+
+			if (pLoggedInPort != NULL)	// WWN found (prior login OK)
+			{
+				if ((fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id) {
+					// Yes.  We were expecting PDISC?
+					if (pLoggedInPort->pdisc) {
+						// Yes; set fields accordingly.     (PDISC, not Originator)
+						SetLoginFields(pLoggedInPort, fchs, 1, 0);
+						// send 'ACC' reply 
+						cpqfcTSPutLinkQue(dev, ELS_PLOGI_ACC,	// (PDISC same as PLOGI ACC)
+								  fchs);
+						// OK to resume I/O...
+					} else {
+						printk("Not expecting PDISC (pdisc=0)\n");
+						NeedReject = 1;
+						// set reject reason code 
+						ls_reject_code = LS_RJT_REASON(PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
+					}
+				} else {
+					if (pLoggedInPort->port_id != 0) {
+						printk("PDISC PortID change: old %Xh, new %Xh\n", pLoggedInPort->port_id, fchs->s_id & 0xFFFFFF);
+					}
+					NeedReject = 1;
+					// set reject reason code 
+					ls_reject_code = LS_RJT_REASON(PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
+				}
+			} else {
+				printk("PDISC Request from unknown WWN\n");
+				NeedReject = 1;
+				// set reject reason code 
+				ls_reject_code = LS_RJT_REASON(LOGICAL_ERROR, INVALID_PORT_NAME);
+			}
 
-static void ProcessELS_Request( 
-              CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-//  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-//  ULONG ox_id = (fchs->ox_rx_id >>16);
-  PFC_LOGGEDIN_PORT pLoggedInPort=NULL, pLastLoggedInPort;
-  BOOLEAN NeedReject = FALSE;
-  ULONG ls_reject_code = 0; // default don'n know??
+		}
+		else		// Payload unacceptable
+		{
+			printk("payload unacceptable\n");
+			NeedReject = 1;	// reject code already set
 
+		}
+		if (NeedReject) {
+			u32 port_id;
+			// The PDISC failed.  Set login struct flags accordingly,
+			// terminate any I/O to this port, and Q a PLOGI
+			if (pLoggedInPort) {
+				pLoggedInPort->pdisc = 0;
+				pLoggedInPort->prli = 0;
+				pLoggedInPort->plogi = 0;
+
+				cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+				port_id = pLoggedInPort->port_id;
+			} else {
+				port_id = fchs->s_id & 0xFFFFFF;
+			}
+			fchs->reserved = ls_reject_code;	// borrow this (unused) field
+			cpqfcTSPutLinkQue(dev, ELS_RJT, fchs);
+		}
+		break;
 
-  // Check the incoming frame for a supported ELS type
-  switch( fchs->pl[0] & 0xFFFF)
-  {
-  case 0x0050: //  PDISC?
+	case 0x0003:
+		//  PLOGI?
+		// Payload for PLOGI and PDISC is identical (request & reply)
+		if (!verify_PLOGI(fcChip, fchs, &ls_reject_code))	// valid payload?
+		{
+			LOGIN_PAYLOAD logi;	// FC-PH Port Login
+			u8 NeedReject = 0;
+
+			// PDISC payload OK. If critical login fields
+			// (e.g. WWN) matches last login for this port_id,
+			// we may resume any prior exchanges
+			// with the other port
+
+			BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+							   0,	// don't search linked list for port_id
+							   &logi.port_name[0],	// search linked list for WWN
+							   &pLastLoggedInPort);	// must return non-NULL; when a port_id
+			// is not found, this pointer marks the
+			// end of the singly linked list
+			if (pLoggedInPort == NULL)	// WWN not found -New Port
+			{
+				pLoggedInPort = CreateFcPort(dev, pLastLoggedInPort, fchs, &logi);
+				if (pLoggedInPort == NULL) {
+					printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
+					// Now Q a LOGOut Request, since we won't be talking to that device
+					NeedReject = 1;
+					// set reject reason code 
+					ls_reject_code = LS_RJT_REASON(LOGICAL_ERROR, NO_LOGIN_RESOURCES);
+				}
+			}
+			if (!NeedReject) {
+				// OK - we have valid fcPort ptr; set fields accordingly.   
+				//                         (not PDISC, not Originator)
+				SetLoginFields(pLoggedInPort, fchs, 0, 0);
+				// send 'ACC' reply 
+				cpqfcTSPutLinkQue(dev, ELS_PLOGI_ACC,	// (PDISC same as PLOGI ACC)
+						  fchs);
+			}
+		}
+		else		// Payload unacceptable
+		{
+			printk("payload unacceptable\n");
+			NeedReject = 1;	// reject code already set
+		}
+		if (NeedReject) {
+			// The PDISC failed.  Set login struct flags accordingly,
+			// terminate any I/O to this port, and Q a PLOGI
+			pLoggedInPort->pdisc = 0;
+			pLoggedInPort->prli = 0;
+			pLoggedInPort->plogi = 0;
 
-    // Payload for PLOGI and PDISC is identical (request & reply)
-    if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
-    {
-      LOGIN_PAYLOAD logi;       // FC-PH Port Login
-      
-      // PDISC payload OK. If critical login fields
-      // (e.g. WWN) matches last login for this port_id,
-      // we may resume any prior exchanges
-      // with the other port
+			fchs->reserved = ls_reject_code;	// borrow this (unused) field
 
-      
-      BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-   
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-	     NULL,     // don't search Scsi Nexus
-	     0,        // don't search linked list for port_id
-             &logi.port_name[0],     // search linked list for WWN
-             &pLastLoggedInPort);  // must return non-NULL; when a port_id
-                                   // is not found, this pointer marks the
-                                   // end of the singly linked list
-    
-      if( pLoggedInPort != NULL)   // WWN found (prior login OK)
-      { 
-           
- 	if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
-	{
-          // Yes.  We were expecting PDISC?
-          if( pLoggedInPort->pdisc )
-	  {
-	    // Yes; set fields accordingly.     (PDISC, not Originator)
-            SetLoginFields( pLoggedInPort, fchs, TRUE, FALSE);
-       
-            // send 'ACC' reply 
-            cpqfcTSPutLinkQue( cpqfcHBAdata, 
-                          ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
-                          fchs );
-
-	    // OK to resume I/O...
-	  }
-	  else
- 	  {
-	    printk("Not expecting PDISC (pdisc=FALSE)\n");
-	    NeedReject = TRUE;
-	    // set reject reason code 
-            ls_reject_code = 
-              LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
-	  }
-	}
-	else
-	{
-	  if( pLoggedInPort->port_id != 0)
-	  {
-  	    printk("PDISC PortID change: old %Xh, new %Xh\n",
-              pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
-	  }
-          NeedReject = TRUE;
-          // set reject reason code 
-          ls_reject_code = 
-	    LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
-		  
-	}
-      }
-      else
-      {
-	printk("PDISC Request from unknown WWN\n");
-        NeedReject = TRUE;
-          
-	// set reject reason code 
-        ls_reject_code = 
-          LS_RJT_REASON( LOGICAL_ERROR, INVALID_PORT_NAME);
-      }
+			// send 'RJT' reply 
+			cpqfcTSPutLinkQue(dev, ELS_RJT, fchs);
+		}
+		// terminate any exchanges with this device...
+		if (pLoggedInPort) {
+			cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+		}
+		break;
 
-    }
-    else // Payload unacceptable
-    {
-      printk("payload unacceptable\n");
-      NeedReject = TRUE;  // reject code already set
-      
-    }
+	case 0x1020:		// PRLI?
+		{
+			u8 NeedReject = 1;
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+							   (fchs->s_id & 0xFFFFFF),	// search linked list for port_id
+							   NULL,	// DON'T search linked list for WWN
+							   NULL);	// don't care
+
+			if (pLoggedInPort == NULL) {
+				// huh?
+				printk(" Unexpected PRLI Request -not logged in!\n");
+				// set reject reason code 
+				ls_reject_code = LS_RJT_REASON(PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
+				// Q a LOGOut here?
+			} else {
+				// verify the PRLI ACC payload
+				if (!verify_PRLI(fchs, &ls_reject_code)) {
+					// PRLI Reply is acceptable; were we expecting it?
+					if (pLoggedInPort->plogi) {
+						// yes, we expected the PRLI ACC  (not PDISC; not Originator)
+						SetLoginFields(pLoggedInPort, fchs, 0, 0);
+						// Q an ACCept Reply
+						cpqfcTSPutLinkQue(dev, ELS_PRLI_ACC, fchs);
+						NeedReject = 0;
+					} else {
+						// huh?
+						printk(" (unexpected) PRLI REQEST with plogi 0\n");
+						// set reject reason code 
+						ls_reject_code = LS_RJT_REASON(PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
+						// Q a LOGOut here?
+					}
+				} else {
+					printk(" PRLI REQUEST payload failed verify\n");
+					// (reject code set by "verify")
+					// Q a LOGOut here?
+				}
+			}
 
-    if( NeedReject)
-    {
-      ULONG port_id;
-      // The PDISC failed.  Set login struct flags accordingly,
-      // terminate any I/O to this port, and Q a PLOGI
-      if( pLoggedInPort )
-      {
-        pLoggedInPort->pdisc = FALSE;
-        pLoggedInPort->prli = FALSE;
-        pLoggedInPort->plogi = FALSE;
-	
-        cpqfcTSTerminateExchange( cpqfcHBAdata, 
-          &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
-	port_id = pLoggedInPort->port_id;
-      }
-      else
-      {
-	port_id = fchs->s_id &0xFFFFFF;
-      }
-      fchs->reserved = ls_reject_code; // borrow this (unused) field
-      cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
-    }
-   
-    break;
+			if (NeedReject) {
+				// Q a ReJecT Reply with reason code
+				fchs->reserved = ls_reject_code;
+				cpqfcTSPutLinkQue(dev, ELS_RJT,	// Q Type
+						  fchs);
+			}
+		}
+		break;
 
+	case 0x0005:		// LOGOut?
+		{
+			// was this LOGOUT because we sent a ELS_PDISC to an FC device
+			// with changed (or new) port_id, or does the port refuse 
+			// to communicate to us?
+			// We maintain a logout counter - if we get 3 consecutive LOGOuts,
+			// give up!
+			LOGOUT_PAYLOAD logo;
+			u8 GiveUpOnDevice = 0;
+			u32 ls_reject_code = 0;
+
+			BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logo, sizeof(logo));
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+							   0,	// don't search linked list for port_id
+							   &logo.port_name[0],	// search linked list for WWN
+							   NULL);	// don't care about end of list
+
+			if (pLoggedInPort)	// found the device?
+			{
+				// Q an ACC reply 
+				cpqfcTSPutLinkQue(dev, ELS_LOGO_ACC,	// Q Type
+						  fchs);	// device to respond to
+				// set login struct fields (LOGO_counter increment)
+				SetLoginFields(pLoggedInPort, fchs, 0, 0);
+				// are we an Initiator?
+				if (fcChip->Options.initiator) {
+					// we're an Initiator, so check if we should 
+					// try (another?) login
+					// Fabrics routinely log out from us after
+					// getting device info - don't try to log them
+					// back in.
+					if ((fchs->s_id & 0xFFF000) == 0xFFF000) {
+						;	// do nothing
+					} else if (pLoggedInPort->LOGO_counter <= 3) {
+						// try (another) login (PLOGI request)
+						cpqfcTSPutLinkQue(dev, ELS_PLOGI,	// Q Type
+								  fchs);
+						// Terminate I/O with "retry" potential
+						cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+					} else {
+						printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n", fchs->s_id && 0xFFFFFF);
+						GiveUpOnDevice = 1;
+					}
+				} else {
+					GiveUpOnDevice = 1;
+				}
+
+				if (GiveUpOnDevice == 1) {
+					cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, DEVICE_REMOVED);
+				}
+			} else	// we don't know this WWN!
+			{
+				// Q a ReJecT Reply with reason code
+				fchs->reserved = ls_reject_code;
+				cpqfcTSPutLinkQue(dev, ELS_RJT,	// Q Type
+						  fchs);
+			}
+		}
+		break;
 
+			// FABRIC only case
+	case 0x0461:	// ELS RSCN (Registered State Change Notification)?
+		{
+			int Ports;
+			int i;
+			__u32 Buff;
+			// Typically, one or more devices have been added to or dropped
+			// from the Fabric.
+			// The format of this frame is defined in FC-FLA (Rev 2.7, Aug 1997)
+			// The first 32-bit word has a 2-byte Payload Length, which
+			// includes the 4 bytes of the first word.  Consequently,
+			// this PL len must never be less than 4, must be a multiple of 4,
+			// and has a specified max value 256.
+			// (Endianess!)
+			Ports = ((fchs->pl[0] >> 24) - 4) / 4;
+			Ports = Ports > 63 ? 63 : Ports;
+
+			printk(" RSCN ports: %d\n", Ports);
+			if (Ports <= 0)	// huh?
+			{
+				// ReJecT the command
+				fchs->reserved = LS_RJT_REASON(UNABLE_TO_PERFORM, 0);
+
+				cpqfcTSPutLinkQue(dev, ELS_RJT,	// Q Type
+						  fchs);
+
+				break;
+			} else	// Accept the command
+			{
+				cpqfcTSPutLinkQue(dev, ELS_ACC,	// Q Type
+						  fchs);
+			}
 
-  case 0x0003: //  PLOGI?
+			// Check the "address format" to determine action.
+			// We have 3 cases:
+			// 0 = Port Address; 24-bit address of affected device
+			// 1 = Area Address; MS 16 bits valid
+			// 2 = Domain Address; MS 8 bits valid
+			for (i = 0; i < Ports; i++) {
+				BigEndianSwap((u8 *) & fchs->pl[i + 1], (u8 *) & Buff, 4);
+				switch (Buff & 0xFF000000) {
+				case 0:	// Port Address?
+				case 0x01000000:	// Area Domain?
+				case 0x02000000:	// Domain Address
+					// For example, "port_id" 0x201300 
+					// OK, let's try a Name Service Request (Query)
+					fchs->s_id = 0xFFFFFC;	// Name Server Address
+					cpqfcTSPutLinkQue(dev, FCS_NSR, fchs);
+					break;
+				default:	// huh? new value on version change?
+					break;
+				}
+			}
+		}
+		break;
+	default:
+		// don't support this request (yet)
+		// set reject reason code 
+		fchs->reserved = LS_RJT_REASON(UNABLE_TO_PERFORM, REQUEST_NOT_SUPPORTED);
+		cpqfcTSPutLinkQue(dev, ELS_RJT,	fchs);	// Q Type
+		break;
+	}
+}
 
-    // Payload for PLOGI and PDISC is identical (request & reply)
-    if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
-    {
-      LOGIN_PAYLOAD logi;       // FC-PH Port Login
-      BOOLEAN NeedReject = FALSE;
-      
-      // PDISC payload OK. If critical login fields
-      // (e.g. WWN) matches last login for this port_id,
-      // we may resume any prior exchanges
-      // with the other port
 
-      
-      BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-   
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-	     NULL,       // don't search Scsi Nexus
-	     0,        // don't search linked list for port_id
-             &logi.port_name[0],     // search linked list for WWN
-             &pLastLoggedInPort);  // must return non-NULL; when a port_id
-                                   // is not found, this pointer marks the
-                                   // end of the singly linked list
-    
-      if( pLoggedInPort == NULL)   // WWN not found -New Port
-      { 
-      	pLoggedInPort = CreateFcPort( 
-			  cpqfcHBAdata, 
-			  pLastLoggedInPort, 
-			  fchs,
-			  &logi);
-        if( pLoggedInPort == NULL )
-        {
-          printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
-          // Now Q a LOGOut Request, since we won't be talking to that device
-	
-          NeedReject = TRUE;  
-	  
-          // set reject reason code 
-          ls_reject_code = 
-            LS_RJT_REASON( LOGICAL_ERROR, NO_LOGIN_RESOURCES);
-	    
+static void ProcessELS_Reply(CPQFCHBA * dev, TachFCHDR_GCMND * fchs)
+{
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 ox_id = (fchs->ox_rx_id >> 16);
+	u32 ls_reject_code;
+	PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
+
+	// If this is a valid reply, then we MUST have sent a request.
+	// Verify that we can find a valid request OX_ID corresponding to
+	// this reply
+
+	if (Exchanges->fcExchange[(fchs->ox_rx_id >> 16)].type == 0) {
+		printk(" *Discarding ACC/RJT frame, xID %04X/%04X* ", ox_id, fchs->ox_rx_id & 0xffff);
+		goto Quit;	// exit this routine
 	}
-      }
-      if( !NeedReject )
-      {
-      
-        // OK - we have valid fcPort ptr; set fields accordingly.   
-	//                         (not PDISC, not Originator)
-        SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE); 
-
-        // send 'ACC' reply 
-        cpqfcTSPutLinkQue( cpqfcHBAdata, 
-                      ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
-                      fchs );
-      }
-    }
-    else // Payload unacceptable
-    {
-      printk("payload unacceptable\n");
-      NeedReject = TRUE;  // reject code already set
-    }
 
-    if( NeedReject)
-    {
-      // The PDISC failed.  Set login struct flags accordingly,
-      // terminate any I/O to this port, and Q a PLOGI
-      pLoggedInPort->pdisc = FALSE;
-      pLoggedInPort->prli = FALSE;
-      pLoggedInPort->plogi = FALSE;
-	
-      fchs->reserved = ls_reject_code; // borrow this (unused) field
+	// Is the reply a RJT (reject)?
+	if ((fchs->pl[0] & 0xFFFFL) == 0x01)	// Reject reply?
+	{
+		//  ******  REJECT REPLY  ********
+		switch (Exchanges->fcExchange[ox_id].type) {
+		case ELS_FDISC:	// we sent out Fabric Discovery
+		case ELS_FLOGI:	// we sent out FLOGI
+			printk("RJT received on Fabric Login from %Xh, reason %Xh\n", fchs->s_id, fchs->pl[1]);
+			break;
+		default:
+			break;
+		}
+		goto Done;
+	}
+	// OK, we have an ACCept...
+	// What's the ACC type? (according to what we sent)
+	switch (Exchanges->fcExchange[ox_id].type) {
+	case ELS_PLOGI:	// we sent out PLOGI
+		if (!verify_PLOGI(fcChip, fchs, &ls_reject_code)) {
+			LOGIN_PAYLOAD logi;	// FC-PH Port Login
+			// login ACC payload acceptable; search for WWN in our list
+			// of fcPorts
+			BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+						   0,	// don't search linked list for port_id
+						   &logi.port_name[0],	// search linked list for WWN
+						   &pLastLoggedInPort);	// must return non-NULL; when a port_id
+			// is not found, this pointer marks the
+			// end of the singly linked list
+			if (pLoggedInPort == NULL)	// WWN not found - new port
+			{
+				pLoggedInPort = CreateFcPort(dev, pLastLoggedInPort, fchs, &logi);
+				if (pLoggedInPort == NULL) {
+					printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
+					// Now Q a LOGOut Request, since we won't be talking to that device
+					goto Done;	// exit with error! dropped login frame
+				}
+			} else	// WWN was already known.  Ensure that any open
+				// exchanges for this WWN are terminated.
+				// NOTE: It's possible that a device can change its 
+				// 24-bit port_id after a Link init or Fabric change 
+				// (e.g. LIP or Fabric RSCN).  In that case, the old
+				// 24-bit port_id may be duplicated, or no longer exist.
+			{
+				cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+			}
 
-      // send 'RJT' reply 
-      cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
-    }
-   
-    // terminate any exchanges with this device...
-    if( pLoggedInPort )
-    {
-      cpqfcTSTerminateExchange( cpqfcHBAdata, 
-        &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
-    }
-    break;
+			// We have an fcPort struct - set fields accordingly
+			// not PDISC, originator 
+			SetLoginFields(pLoggedInPort, fchs, 0, 1);
+			// We just set a "port_id"; is it duplicated?
+			TestDuplicatePortId(dev, pLoggedInPort);
+			// For Fabric operation, we issued PLOGI to 0xFFFFFC
+			// so we can send SCR (State Change Registration) 
+			// Check for this special case...
+			if (fchs->s_id == 0xFFFFFC) {
+				// PLOGI ACC was a Fabric response... issue SCR
+				fchs->s_id = 0xFFFFFD;	// address for SCR
+				cpqfcTSPutLinkQue(dev, ELS_SCR, fchs);
+			}
+			else {
+				// Now we need a PRLI to enable FCP-SCSI operation
+				// set flags and Q up a ELS_PRLI
+				cpqfcTSPutLinkQue(dev, ELS_PRLI, fchs);
+			}
+		} else {
+			// login payload unacceptable - reason in ls_reject_code
+			// Q up a Logout Request
+			printk("Login Payload unacceptable\n");
+		}
+		break;
 
+		// PDISC logic very similar to PLOGI, except we never want
+		// to allocate mem for "new" port, and we set flags differently
+		// (might combine later with PLOGI logic for efficiency)  
+	case ELS_PDISC:	// we sent out PDISC
+		if (!verify_PLOGI(fcChip, fchs, &ls_reject_code)) {
+			LOGIN_PAYLOAD logi;	// FC-PH Port Login
+			u8 NeedLogin = 0;
+
+			// login payload acceptable; search for WWN in our list
+			// of (previously seen) fcPorts
+			BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
+
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+							   0,	// don't search linked list for port_id
+							   &logi.port_name[0],	// search linked list for WWN
+							   &pLastLoggedInPort);	// must return non-NULL; when a port_id
+			// is not found, this pointer marks the
+			// end of the singly linked list
+			if (pLoggedInPort != NULL)	// WWN found?
+			{
+				// WWN has same port_id as last login?  (Of course, a properly
+				// working FC device should NEVER ACCept a PDISC if it's
+				// port_id changed, but check just in case...)
+				if ((fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id) {
+					// Yes.  We were expecting PDISC?
+					if (pLoggedInPort->pdisc) {
+						int i;
+
+
+						// PDISC expected -- set fields.  (PDISC, Originator)
+						SetLoginFields(pLoggedInPort, fchs, 1, 1);
+
+						// We are ready to resume FCP-SCSI to this device...
+						// Do we need to start anything that was Queued?
+
+						for (i = 0; i < TACH_SEST_LEN; i++) {
+							// see if any exchange for this PDISC'd port was queued
+							if (((fchs->s_id & 0xFFFFFF) == (Exchanges->fcExchange[i].fchs.d_id & 0xFFFFFF))
+							    && (Exchanges->fcExchange[i].status & EXCHANGE_QUEUED)) {
+								fchs->reserved = i;	// copy ExchangeID
+//						                printk(" *Q x_ID %Xh after PDISC* ",i);
+
+								cpqfcTSPutLinkQue(dev, EXCHANGE_QUEUED, fchs);
+							}
+						}
+						// Complete commands Q'd while we were waiting for Login
+						UnblockScsiDevice(dev->HostAdapter, pLoggedInPort);
+					} else {
+						printk("Not expecting PDISC (pdisc=0)\n");
+						NeedLogin = 1;
+					}
+				} else {
+					printk("PDISC PortID change: old %Xh, new %Xh\n", pLoggedInPort->port_id, fchs->s_id & 0xFFFFFF);
+					NeedLogin = 1;
+				}
+			} else {
+				printk("PDISC ACC from unknown WWN\n");
+				NeedLogin = 1;
+			}
 
+			if (NeedLogin) {
+				// The PDISC failed.  Set login struct flags accordingly,
+				// terminate any I/O to this port, and Q a PLOGI
+				if (pLoggedInPort)	// FC device previously known?
+				{
+					cpqfcTSPutLinkQue(dev, ELS_LOGO, fchs);	// Qtype has port_id to send to 
+					// There are a variety of error scenarios which can result
+					// in PDISC failure, so as a catchall, add the check for
+					// duplicate port_id.
+					TestDuplicatePortId(dev, pLoggedInPort);
+
+					// TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
+					pLoggedInPort->pdisc = 0;
+					pLoggedInPort->prli = 0;
+					pLoggedInPort->plogi = 0;
+
+					cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+				}
+				cpqfcTSPutLinkQue(dev, ELS_PLOGI, fchs);
+			}
+		} else {
+			// login payload unacceptable - reason in ls_reject_code
+			// Q up a Logout Request
+			printk("ERROR: Login Payload unacceptable!\n");
 
-  case 0x1020:  // PRLI?
-  {
-    BOOLEAN NeedReject = TRUE;
-    pLoggedInPort = fcFindLoggedInPort( 
-           fcChip, 
-           NULL,       // don't search Scsi Nexus
-	   (fchs->s_id & 0xFFFFFF),  // search linked list for port_id
-           NULL,     // DON'T search linked list for WWN
-           NULL);    // don't care
-      
-    if( pLoggedInPort == NULL ) 
-    {
-      // huh?
-      printk(" Unexpected PRLI Request -not logged in!\n");
-
-      // set reject reason code 
-      ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
-      
-      // Q a LOGOut here?
-    }
-    else
-    {
-      // verify the PRLI ACC payload
-      if( !verify_PRLI( fchs, &ls_reject_code) )
-      {
-        // PRLI Reply is acceptable; were we expecting it?
-        if( pLoggedInPort->plogi ) 
-        { 
-  	  // yes, we expected the PRLI ACC  (not PDISC; not Originator)
-          SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
-
-          // Q an ACCept Reply
-	  cpqfcTSPutLinkQue( cpqfcHBAdata,
-                        ELS_PRLI_ACC, 
-                        fchs );   
-	  
-	  NeedReject = FALSE;
-	}
-        else
-        {
-          // huh?
-          printk(" (unexpected) PRLI REQEST with plogi FALSE\n");
-
-          // set reject reason code 
-          ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
-    
-    	  // Q a LOGOut here?
-	  
-        }
-      }
-      else
-      {
-        printk(" PRLI REQUEST payload failed verify\n");
-        // (reject code set by "verify")
-
-        // Q a LOGOut here?
-      }
-    }
-
-    if( NeedReject )
-    {
-      // Q a ReJecT Reply with reason code
-      fchs->reserved = ls_reject_code;
-      cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_RJT, // Q Type
-                    fchs );  
-    }
-  }
-    break;
- 
-
-    
-
-  case  0x0005:  // LOGOut?
-  {
-  // was this LOGOUT because we sent a ELS_PDISC to an FC device
-  // with changed (or new) port_id, or does the port refuse 
-  // to communicate to us?
-  // We maintain a logout counter - if we get 3 consecutive LOGOuts,
-  // give up!
-    LOGOUT_PAYLOAD logo;
-    BOOLEAN GiveUpOnDevice = FALSE;
-    ULONG ls_reject_code = 0;
-    
-    BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logo, sizeof(logo));
-
-    pLoggedInPort = fcFindLoggedInPort( 
-           fcChip, 
-           NULL,     // don't search Scsi Nexus
-	   0,        // don't search linked list for port_id
-           &logo.port_name[0],     // search linked list for WWN
-           NULL);    // don't care about end of list
-    
-    if( pLoggedInPort ) // found the device?
-    {
-      // Q an ACC reply 
-      cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_LOGO_ACC, // Q Type
-                    fchs );       // device to respond to
-
-      // set login struct fields (LOGO_counter increment)
-      SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
-      
-      // are we an Initiator?
-      if( fcChip->Options.initiator)  
-      {
-        // we're an Initiator, so check if we should 
-	// try (another?) login
-
-	// Fabrics routinely log out from us after
-	// getting device info - don't try to log them
-	// back in.
-	if( (fchs->s_id & 0xFFF000) == 0xFFF000 )
-	{
-	  ; // do nothing
-	}
-	else if( pLoggedInPort->LOGO_counter <= 3)
-	{
-	  // try (another) login (PLOGI request)
-	  
-          cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_PLOGI, // Q Type
-                    fchs );  
-	
-	  // Terminate I/O with "retry" potential
-	  cpqfcTSTerminateExchange( cpqfcHBAdata, 
-			            &pLoggedInPort->ScsiNexus,
-				    PORTID_CHANGED);
-	}
-	else
-	{
-	  printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n",
-			  fchs->s_id &&0xFFFFFF);
-	  GiveUpOnDevice = TRUE;
-	}
-      }
-      else
-      {
-	GiveUpOnDevice = TRUE;
-      }
-
-
-      if( GiveUpOnDevice == TRUE )
-      {
-        cpqfcTSTerminateExchange( cpqfcHBAdata, 
-	                          &pLoggedInPort->ScsiNexus,
-		                  DEVICE_REMOVED);
-      }
-    }  
-    else  // we don't know this WWN!
-    {
-      // Q a ReJecT Reply with reason code
-      fchs->reserved = ls_reject_code;
-      cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_RJT, // Q Type
-                    fchs );  
-    }
-  }
-    break;
-
-
-
-
-  // FABRIC only case
-  case 0x0461:  // ELS RSCN (Registered State Change Notification)?
-  {
-    int Ports;
-    int i;
-    __u32 Buff;
-    // Typically, one or more devices have been added to or dropped
-    // from the Fabric.
-    // The format of this frame is defined in FC-FLA (Rev 2.7, Aug 1997)
-    // The first 32-bit word has a 2-byte Payload Length, which
-    // includes the 4 bytes of the first word.  Consequently,
-    // this PL len must never be less than 4, must be a multiple of 4,
-    // and has a specified max value 256.
-    // (Endianess!)
-    Ports = ((fchs->pl[0] >>24) - 4) / 4;
-    Ports = Ports > 63 ? 63 : Ports;
-    
-    printk(" RSCN ports: %d\n", Ports);
-    if( Ports <= 0 )  // huh?
-    {
-      // ReJecT the command
-      fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 0);
-    
-      cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_RJT, // Q Type
-                    fchs ); 
-      
-      break;
-    }
-    else  // Accept the command
-    {
-       cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_ACC, // Q Type
-                    fchs ); 
-    }
-    
-      // Check the "address format" to determine action.
-      // We have 3 cases:
-      // 0 = Port Address; 24-bit address of affected device
-      // 1 = Area Address; MS 16 bits valid
-      // 2 = Domain Address; MS 8 bits valid
-    for( i=0; i<Ports; i++)
-    { 
-      BigEndianSwap( (UCHAR*)&fchs->pl[i+1],(UCHAR*)&Buff, 4);
-      switch( Buff & 0xFF000000)
-      {
-
-      case 0:  // Port Address?
-	
-      case 0x01000000: // Area Domain?
-      case 0x02000000: // Domain Address
-        // For example, "port_id" 0x201300 
-	// OK, let's try a Name Service Request (Query)
-      fchs->s_id = 0xFFFFFC;  // Name Server Address
-      cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
-
-      break;
-	
-	
-      default:  // huh? new value on version change?
-      break;
-      }
-    }
-  }    
-  break;    
-
-
-
-    
-  default:  // don't support this request (yet)
-    // set reject reason code 
-    fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 
-		                    REQUEST_NOT_SUPPORTED);
-    
-    cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_RJT, // Q Type
-                    fchs );     
-    break;  
-  }
-}
-
-
-static void ProcessELS_Reply( 
-		CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG ox_id = (fchs->ox_rx_id >>16);
-  ULONG ls_reject_code;
-  PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
-  
-  // If this is a valid reply, then we MUST have sent a request.
-  // Verify that we can find a valid request OX_ID corresponding to
-  // this reply
-
-  
-  if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
-  {
-    printk(" *Discarding ACC/RJT frame, xID %04X/%04X* ", 
-		    ox_id, fchs->ox_rx_id & 0xffff);
-    goto Quit;  // exit this routine
-  }
-
-
-  // Is the reply a RJT (reject)?
-  if( (fchs->pl[0] & 0xFFFFL) == 0x01) // Reject reply?
-  {
-//  ******  REJECT REPLY  ********
-    switch( Exchanges->fcExchange[ox_id].type )
-    {
-	  
-    case ELS_FDISC:  // we sent out Fabric Discovery
-    case ELS_FLOGI:  // we sent out FLOGI
-
-      printk("RJT received on Fabric Login from %Xh, reason %Xh\n", 
-        fchs->s_id, fchs->pl[1]);    
-
-    break;
-
-    default:
-    break;
-    }
-      
-    goto Done;
-  }
-
-  // OK, we have an ACCept...
-  // What's the ACC type? (according to what we sent)
-  switch( Exchanges->fcExchange[ox_id].type )
-  {
-	  
-  case ELS_PLOGI:  // we sent out PLOGI
-    if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
-    {
-      LOGIN_PAYLOAD logi;       // FC-PH Port Login
-      
-      // login ACC payload acceptable; search for WWN in our list
-      // of fcPorts
-      
-      BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-   
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-	     NULL,     // don't search Scsi Nexus
-	     0,        // don't search linked list for port_id
-             &logi.port_name[0],     // search linked list for WWN
-             &pLastLoggedInPort);  // must return non-NULL; when a port_id
-                                   // is not found, this pointer marks the
-                                   // end of the singly linked list
-    
-      if( pLoggedInPort == NULL)         // WWN not found - new port
-      {
+		}
+		break;
 
-	pLoggedInPort = CreateFcPort( 
-			  cpqfcHBAdata, 
-			  pLastLoggedInPort, 
-			  fchs,
-			  &logi);
-
-        if( pLoggedInPort == NULL )
-        {
-          printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
-          // Now Q a LOGOut Request, since we won't be talking to that device
-	
-          goto Done;  // exit with error! dropped login frame
-	}
-      }
-      else      // WWN was already known.  Ensure that any open
-	        // exchanges for this WWN are terminated.
-      	// NOTE: It's possible that a device can change its 
-	// 24-bit port_id after a Link init or Fabric change 
-	// (e.g. LIP or Fabric RSCN).  In that case, the old
-	// 24-bit port_id may be duplicated, or no longer exist.
-      {
-
-        cpqfcTSTerminateExchange( cpqfcHBAdata, 
-          &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
-      }
-
-      // We have an fcPort struct - set fields accordingly
-                                    // not PDISC, originator 
-      SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
-			
-      // We just set a "port_id"; is it duplicated?
-      TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
-
-      // For Fabric operation, we issued PLOGI to 0xFFFFFC
-      // so we can send SCR (State Change Registration) 
-      // Check for this special case...
-      if( fchs->s_id == 0xFFFFFC ) 
-      {
-        // PLOGI ACC was a Fabric response... issue SCR
-	fchs->s_id = 0xFFFFFD;  // address for SCR
-        cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_SCR, fchs);
-      }
-
-      else
-      {
-      // Now we need a PRLI to enable FCP-SCSI operation
-      // set flags and Q up a ELS_PRLI
-        cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PRLI, fchs);
-      }
-    }
-    else
-    {
-      // login payload unacceptable - reason in ls_reject_code
-      // Q up a Logout Request
-      printk("Login Payload unacceptable\n");
+	case ELS_PRLI:		// we sent out PRLI
+		pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+						   (fchs->s_id & 0xFFFFFF),	// search linked list for port_id
+						   NULL,	// DON'T search linked list for WWN
+						   NULL);	// don't care
+
+		if (pLoggedInPort == NULL) {
+			// huh?
+			printk(" Unexpected PRLI ACCept frame!\n");
+			// Q a LOGOut here?
+			goto Done;
+		}
+		// verify the PRLI ACC payload
+		if (!verify_PRLI(fchs, &ls_reject_code)) {
+			// PRLI Reply is acceptable; were we expecting it?
+			if (pLoggedInPort->plogi) {
+				// yes, we expected the PRLI ACC  (not PDISC; Originator)
+				SetLoginFields(pLoggedInPort, fchs, 0, 1);
+				// OK, let's send a REPORT_LUNS command to determine
+				// whether VSA or PDA FCP-LUN addressing is used.
+				cpqfcTSPutLinkQue(dev, SCSI_REPORT_LUNS, fchs);
+				// It's possible that a device we were talking to changed 
+				// port_id, and has logged back in.  This function ensures
+				// that I/O will resume.
+				UnblockScsiDevice(dev->HostAdapter, pLoggedInPort);
+			} else {
+				// huh?
+				printk(" (unexpected) PRLI ACCept with plogi 0\n");
+				// Q a LOGOut here?
+				goto Done;
+			}
+		} else {
+			printk(" PRLI ACCept payload failed verify\n");
+			// Q a LOGOut here?
+		}
+		break;
 
-    }
-    break;
+	case ELS_FLOGI:	// we sent out FLOGI (Fabric Login)
+		// update the upper 16 bits of our port_id in Tachyon
+		// the switch adds those upper 16 bits when responding
+		// to us (i.e. we are the destination_id)
+		fcChip->Registers.my_al_pa = (fchs->d_id & 0xFFFFFF);
+		writel(fcChip->Registers.my_al_pa, fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
+
+		// now send out a PLOGI to the well known port_id 0xFFFFFC
+		fchs->s_id = 0xFFFFFC;
+		cpqfcTSPutLinkQue(dev, ELS_PLOGI, fchs);
+		break;
 
 
-  // PDISC logic very similar to PLOGI, except we never want
-  // to allocate mem for "new" port, and we set flags differently
-  // (might combine later with PLOGI logic for efficiency)  
-  case ELS_PDISC:  // we sent out PDISC
-    if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
-    {
-      LOGIN_PAYLOAD logi;       // FC-PH Port Login
-      BOOLEAN NeedLogin = FALSE;
-      
-      // login payload acceptable; search for WWN in our list
-      // of (previously seen) fcPorts
-      
-      BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-   
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-	     NULL,     // don't search Scsi Nexus
-	     0,        // don't search linked list for port_id
-             &logi.port_name[0],     // search linked list for WWN
-             &pLastLoggedInPort);  // must return non-NULL; when a port_id
-                                   // is not found, this pointer marks the
-                                   // end of the singly linked list
-    
-      if( pLoggedInPort != NULL)   // WWN found?
-      {
-        // WWN has same port_id as last login?  (Of course, a properly
-	// working FC device should NEVER ACCept a PDISC if it's
-	// port_id changed, but check just in case...)
-	if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
-	{
-          // Yes.  We were expecting PDISC?
-          if( pLoggedInPort->pdisc )
-	  {
-            int i;
-	    
-	    
-	    // PDISC expected -- set fields.  (PDISC, Originator)
-            SetLoginFields( pLoggedInPort, fchs, TRUE, TRUE);
+	case ELS_FDISC:	// we sent out FDISC (Fabric Discovery (Login))
+		printk(" ELS_FDISC success ");
+		break;
 
-	    // We are ready to resume FCP-SCSI to this device...
-            // Do we need to start anything that was Queued?
+	case ELS_SCR:		// we sent out State Change Registration
+		// now we can issue Name Service Request to find any
+		// Fabric-connected devices we might want to login to.
+		fchs->s_id = 0xFFFFFC;	// Name Server Address
+		cpqfcTSPutLinkQue(dev, FCS_NSR, fchs);
+		break;
 
-            for( i=0; i< TACH_SEST_LEN; i++)
-            {
-              // see if any exchange for this PDISC'd port was queued
-              if( ((fchs->s_id &0xFFFFFF) == 
-                   (Exchanges->fcExchange[i].fchs.d_id & 0xFFFFFF))
-                      &&
-                  (Exchanges->fcExchange[i].status & EXCHANGE_QUEUED))
-              {
-                fchs->reserved = i; // copy ExchangeID
-//                printk(" *Q x_ID %Xh after PDISC* ",i);
-
-                cpqfcTSPutLinkQue( cpqfcHBAdata, EXCHANGE_QUEUED, fchs );
-              }
-            }
-
-	    // Complete commands Q'd while we were waiting for Login
-
-	    UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
-	  }
-	  else
-	  {
-	    printk("Not expecting PDISC (pdisc=FALSE)\n");
-	    NeedLogin = TRUE;
-	  }
+	default:
+		printk(" *Discarding unknown ACC frame, xID %04X/%04X* ", ox_id, fchs->ox_rx_id & 0xffff);
+		break;
 	}
-	else
-	{
-	  printk("PDISC PortID change: old %Xh, new %Xh\n",
-            pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
-          NeedLogin = TRUE;
-		  
-	}
-      }
-      else
-      {
-	printk("PDISC ACC from unknown WWN\n");
-        NeedLogin = TRUE;
-      }
-
-      if( NeedLogin)
-      {
-	
-        // The PDISC failed.  Set login struct flags accordingly,
-	// terminate any I/O to this port, and Q a PLOGI
-	if( pLoggedInPort )  // FC device previously known?
-	{
-
-          cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_LOGO, // Q Type
-                    fchs );   // has port_id to send to 
-
-	  // There are a variety of error scenarios which can result
-  	  // in PDISC failure, so as a catchall, add the check for
-	  // duplicate port_id.
-	  TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
-
-//    TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
-          pLoggedInPort->pdisc = FALSE;
-          pLoggedInPort->prli = FALSE;
-          pLoggedInPort->plogi = FALSE;
-	
-          cpqfcTSTerminateExchange( cpqfcHBAdata, 
-	    &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
-        }
-        cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs );
-      }
-    }
-    else
-    {
-      // login payload unacceptable - reason in ls_reject_code
-      // Q up a Logout Request
-      printk("ERROR: Login Payload unacceptable!\n");
-
-    }
-   
-    break;
-    
-
-
-  case ELS_PRLI:  // we sent out PRLI
-
-
-    pLoggedInPort = fcFindLoggedInPort( 
-           fcChip, 
-           NULL,       // don't search Scsi Nexus
-	   (fchs->s_id & 0xFFFFFF),  // search linked list for port_id
-           NULL,     // DON'T search linked list for WWN
-           NULL);    // don't care
-      
-    if( pLoggedInPort == NULL ) 
-    {
-      // huh?
-      printk(" Unexpected PRLI ACCept frame!\n");
-
-      // Q a LOGOut here?
-
-      goto Done;
-    }
-
-    // verify the PRLI ACC payload
-    if( !verify_PRLI( fchs, &ls_reject_code) )
-    {
-      // PRLI Reply is acceptable; were we expecting it?
-      if( pLoggedInPort->plogi ) 
-      { 
-	// yes, we expected the PRLI ACC  (not PDISC; Originator)
-	SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
-
-        // OK, let's send a REPORT_LUNS command to determine
-	// whether VSA or PDA FCP-LUN addressing is used.
-	
-        cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
-	
-	// It's possible that a device we were talking to changed 
-	// port_id, and has logged back in.  This function ensures
-	// that I/O will resume.
-        UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
-
-      }
-      else
-      {
-        // huh?
-        printk(" (unexpected) PRLI ACCept with plogi FALSE\n");
-
-        // Q a LOGOut here?
-        goto Done;
-      }
-    }
-    else
-    {
-      printk(" PRLI ACCept payload failed verify\n");
-
-      // Q a LOGOut here?
-    }
-
-    break;
- 
-  case ELS_FLOGI:  // we sent out FLOGI (Fabric Login)
-
-    // update the upper 16 bits of our port_id in Tachyon
-    // the switch adds those upper 16 bits when responding
-    // to us (i.e. we are the destination_id)
-    fcChip->Registers.my_al_pa = (fchs->d_id & 0xFFFFFF);
-    writel( fcChip->Registers.my_al_pa,  
-      fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
-
-    // now send out a PLOGI to the well known port_id 0xFFFFFC
-    fchs->s_id = 0xFFFFFC;
-    cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs);
-  
-   break; 
-
-
-  case ELS_FDISC:  // we sent out FDISC (Fabric Discovery (Login))
-
-   printk( " ELS_FDISC success ");
-   break;
-   
-
-  case ELS_SCR:  // we sent out State Change Registration
-    // now we can issue Name Service Request to find any
-    // Fabric-connected devices we might want to login to.
-   
-	
-    fchs->s_id = 0xFFFFFC;  // Name Server Address
-    cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
-    
-
-    break;
-
-    
-  default:
-    printk(" *Discarding unknown ACC frame, xID %04X/%04X* ", 
-   		    ox_id, fchs->ox_rx_id & 0xffff);
-    break;
-  }
-
-  
 Done:
-  // Regardless of whether the Reply is valid or not, the
-  // the exchange is done - complete
-  cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, (fchs->ox_rx_id >>16)); 
-	  
-Quit:    
-  return;
+	// Regardless of whether the Reply is valid or not, the
+	// the exchange is done - complete
+	cpqfcTSCompleteExchange(dev->PciDev, fcChip, (fchs->ox_rx_id >> 16));
+Quit:
+	return;
 }
 
 
@@ -2075,352 +1604,263 @@
 // This is where we process the Directory (Name) Service Reply
 // to know which devices are on the Fabric
 
-static void ProcessFCS_Reply( 
-	CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
+static void ProcessFCS_Reply(CPQFCHBA * dev, TachFCHDR_GCMND * fchs)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG ox_id = (fchs->ox_rx_id >>16);
-//  ULONG ls_reject_code;
-//  PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
-  
-  // If this is a valid reply, then we MUST have sent a request.
-  // Verify that we can find a valid request OX_ID corresponding to
-  // this reply
-
-  if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
-  {
-    printk(" *Discarding Reply frame, xID %04X/%04X* ", 
-		    ox_id, fchs->ox_rx_id & 0xffff);
-    goto Quit;  // exit this routine
-  }
-
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 ox_id = (fchs->ox_rx_id >> 16);
+//	u32 ls_reject_code;
+//	PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
+
+	// If this is a valid reply, then we MUST have sent a request.
+	// Verify that we can find a valid request OX_ID corresponding to
+	// this reply
+
+	if (Exchanges->fcExchange[(fchs->ox_rx_id >> 16)].type == 0) {
+		printk(" *Discarding Reply frame, xID %04X/%04X* ", ox_id, fchs->ox_rx_id & 0xffff);
+		goto Quit;	// exit this routine
+	}
 
-  // OK, we were expecting it.  Now check to see if it's a
-  // "Name Service" Reply, and if so force a re-validation of
-  // Fabric device logins (i.e. Start the login timeout and
-  // send PDISC or PLOGI)
-  // (Endianess Byte Swap?)
-  if( fchs->pl[1] == 0x02FC )  // Name Service
-  {
-    // got a new (or NULL) list of Fabric attach devices... 
-    // Invalidate current logins
-    
-    PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
-    while( pLoggedInPort ) // for all ports which are expecting
-                           // PDISC after the next LIP, set the
-                           // logoutTimer
-    {
+	// OK, we were expecting it.  Now check to see if it's a
+	// "Name Service" Reply, and if so force a re-validation of
+	// Fabric device logins (i.e. Start the login timeout and
+	// send PDISC or PLOGI)
+	// (Endianess Byte Swap?)
+	if (fchs->pl[1] == 0x02FC)	// Name Service
+	{
+		// got a new (or NULL) list of Fabric attach devices... 
+		// Invalidate current logins
 
-      if( (pLoggedInPort->port_id & 0xFFFF00)  // Fabric device?
-		      &&
-          (pLoggedInPort->port_id != 0xFFFFFC) ) // NOT the F_Port
-      {
-        pLoggedInPort->LOGO_timer = 6;  // what's the Fabric timeout??
-                                // suspend any I/O in progress until
-                                // PDISC received...
-        pLoggedInPort->prli = FALSE;   // block FCP-SCSI commands
-      }
-	    
-      pLoggedInPort = pLoggedInPort->pNextPort;
-    }
-    
-    if( fchs->pl[2] == 0x0280)  // ACCept?
-    {
-      // Send PLOGI or PDISC to these Fabric devices
-      SendLogins( cpqfcHBAdata, &fchs->pl[4] );  
-    }
+		PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
+		while (pLoggedInPort)	// for all ports which are expecting
+			// PDISC after the next LIP, set the
+			// logoutTimer
+		{
+
+			if ((pLoggedInPort->port_id & 0xFFFF00)	// Fabric device?
+			    && (pLoggedInPort->port_id != 0xFFFFFC))	// NOT the F_Port
+			{
+				pLoggedInPort->LOGO_timer = 6;	// what's the Fabric timeout??
+				// suspend any I/O in progress until
+				// PDISC received...
+				pLoggedInPort->prli = 0;	// block FCP-SCSI commands
+			}
 
+			pLoggedInPort = pLoggedInPort->pNextPort;
+		}
 
-    // As of this writing, the only reason to reject is because NO
-    // devices are left on the Fabric.  We already started
-    // "logged out" timers; if the device(s) don't come
-    // back, we'll do the implicit logout in the heart beat 
-    // timer routine
-    else  // ReJecT
-    {
-      // this just means no Fabric device is visible at this instant
-    } 
-  }
+		if (fchs->pl[2] == 0x0280)	// ACCept?
+		{
+			// Send PLOGI or PDISC to these Fabric devices
+			SendLogins(dev, &fchs->pl[4]);
+		}
+		// As of this writing, the only reason to reject is because NO
+		// devices are left on the Fabric.  We already started
+		// "logged out" timers; if the device(s) don't come
+		// back, we'll do the implicit logout in the heart beat 
+		// timer routine
+		else		// ReJecT
+		{
+			// this just means no Fabric device is visible at this instant
+		}
+	}
+	// Regardless of whether the Reply is valid or not, the
+	// the exchange is done - complete
+	cpqfcTSCompleteExchange(dev->PciDev, fcChip, (fchs->ox_rx_id >> 16));
 
-  // Regardless of whether the Reply is valid or not, the
-  // the exchange is done - complete
-  cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, (fchs->ox_rx_id >>16));
-	  
-Quit:    
-  return;
+Quit:
+	return;
 }
 
-
-
-
-
-
-
-static void AnalyzeIncomingFrame( 
-        CPQFCHBA *cpqfcHBAdata,
-        ULONG QNdx )
+static void AnalyzeIncomingFrame(CPQFCHBA * dev, u32 QNdx)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
-  TachFCHDR_GCMND* fchs = 
-    (TachFCHDR_GCMND*)fcLQ->Qitem[QNdx].ulBuff;
-//  ULONG ls_reject_code;  // reason for rejecting login
-  LONG ExchangeID;
-//  FC_LOGGEDIN_PORT *pLoggedInPort;
-  BOOLEAN AbortAccept;  
-
-  ENTER("AnalyzeIncomingFrame");
-
-
-
-  switch( fcLQ->Qitem[QNdx].Type) // FCP or Unknown
-  {
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	PFC_LINK_QUE fcLQ = dev->fcLQ;
+	TachFCHDR_GCMND *fchs = (TachFCHDR_GCMND *) fcLQ->Qitem[QNdx].ulBuff;
+//	u32 ls_reject_code;  // reason for rejecting login
+	s32 ExchangeID;
+//	FC_LOGGEDIN_PORT *pLoggedInPort;
+	u8 AbortAccept;
 
-  case SFQ_UNKNOWN:  // unknown frame (e.g. LIP position frame, NOP, etc.)
- 
+	ENTER("AnalyzeIncomingFrame");
 
-      // *********  FC-4 Device Data/ Fibre Channel Service *************
-    if( ((fchs->d_id &0xF0000000) == 0)   // R_CTL (upper nibble) 0x0?
-                &&   
-      (fchs->f_ctl & 0x20000000) )  // TYPE 20h is Fibre Channel Service
-    {
-
-      // ************** FCS Reply **********************
-
-      if( (fchs->d_id & 0xff000000L) == 0x03000000L)  // (31:23 R_CTL)
-      {
-	ProcessFCS_Reply( cpqfcHBAdata, fchs );
-
-      }  // end of  FCS logic
-
-    }
-    
-
-      // ***********  Extended Link Service **************
-
-    else if( fchs->d_id & 0x20000000   // R_CTL 0x2?
-                  &&   
-      (fchs->f_ctl & 0x01000000) )  // TYPE = 1
-    {
-
-                           // these frames are either a response to
-                           // something we sent (0x23) or "unsolicited"
-                           // frames (0x22).
-
-
-      // **************Extended Link REPLY **********************
-                           // R_CTL Solicited Control Reply
-
-      if( (fchs->d_id & 0xff000000L) == 0x23000000L)  // (31:23 R_CTL)
-      {
-
-	ProcessELS_Reply( cpqfcHBAdata, fchs );
-
-      }  // end of  "R_CTL Solicited Control Reply"
-
-
-
-
-       // **************Extended Link REQUEST **********************
-       // (unsolicited commands from another port or task...)
-
-                           // R_CTL Ext Link REQUEST
-      else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
-              (fchs->ox_rx_id != 0xFFFFFFFFL) ) // (ignore LIP frame)
-      {
-
-
-
-	ProcessELS_Request( cpqfcHBAdata, fchs );
-
-      }
-
-
-
-        // ************** LILP **********************
-      else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
-               (fchs->ox_rx_id == 0xFFFFFFFFL)) // (e.g., LIP frames)
-
-      {
-        // SANMark specifies that when available, we must use
-	// the LILP frame to determine which ALPAs to send Port Discovery
-	// to...
-
-        if( fchs->pl[0] == 0x0711L) //  ELS_PLOGI?
+	switch (fcLQ->Qitem[QNdx].Type)	// FCP or Unknown
 	{
-//	  UCHAR *ptr = (UCHAR*)&fchs->pl[1];
-//	  printk(" %d ALPAs found\n", *ptr);
-	  memcpy( fcChip->LILPmap, &fchs->pl[1], 32*4); // 32 DWORDs
-	  fcChip->Options.LILPin = 1; // our LILPmap is valid!
-	  // now post to make Port Discovery happen...
-          cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, fchs);  
-	}
-      }
-    }
-
-     
-    // *****************  BASIC LINK SERVICE *****************
-    
-    else if( fchs->d_id & 0x80000000  // R_CTL:
-                    &&           // Basic Link Service Request
-           !(fchs->f_ctl & 0xFF000000) )  // type=0 for BLS
-    {
+	case SFQ_UNKNOWN:	// unknown frame (e.g. LIP position frame, NOP, etc.)
+		// *********  FC-4 Device Data/ Fibre Channel Service *************
+		if (((fchs->d_id & 0xF0000000) == 0)	// R_CTL (upper nibble) 0x0?
+		    && (fchs->f_ctl & 0x20000000))	// TYPE 20h is Fibre Channel Service
+		{
+			// ************** FCS Reply **********************
+			if ((fchs->d_id & 0xff000000L) == 0x03000000L)	// (31:23 R_CTL)
+			{
+				ProcessFCS_Reply(dev, fchs);
+			}	// end of  FCS logic
+		}
+		// ***********  Extended Link Service **************
+		else if (fchs->d_id & 0x20000000	// R_CTL 0x2?
+			 && (fchs->f_ctl & 0x01000000))	// TYPE = 1
+		{
+			// these frames are either a response to
+			// something we sent (0x23) or "unsolicited"
+			// frames (0x22).
+			// **************Extended Link REPLY **********************
+			// R_CTL Solicited Control Reply
+			if ((fchs->d_id & 0xff000000L) == 0x23000000L)	// (31:23 R_CTL)
+			{
+				ProcessELS_Reply(dev, fchs);
+			}	// end of  "R_CTL Solicited Control Reply"
+			// **************Extended Link REQUEST **********************
+			// (unsolicited commands from another port or task...)
+			// R_CTL Ext Link REQUEST
+			else if ((fchs->d_id & 0xff000000L) == 0x22000000L && (fchs->ox_rx_id != 0xFFFFFFFFL))	// (ignore LIP frame)
+			{
+				ProcessELS_Request(dev, fchs);
+			}
+			// ************** LILP **********************
+			else if ((fchs->d_id & 0xff000000L) == 0x22000000L && (fchs->ox_rx_id == 0xFFFFFFFFL))	// (e.g., LIP frames)
+			{
+				// SANMark specifies that when available, we must use
+				// the LILP frame to determine which ALPAs to send Port Discovery
+				// to...
+				if (fchs->pl[0] == 0x0711L)	//  ELS_PLOGI?
+				{
+//					u8 *ptr = (u8*)&fchs->pl[1];
+//					printk(" %d ALPAs found\n", *ptr);
+					memcpy(fcChip->LILPmap, &fchs->pl[1], 32 * 4);	// 32 DWORDs
+					fcChip->Options.LILPin = 1;	// our LILPmap is valid!
+					// now post to make Port Discovery happen...
+					cpqfcTSPutLinkQue(dev, LINKACTIVE, fchs);
+				}
+			}
+		}
+		// *****************  BASIC LINK SERVICE *****************
+		else if (fchs->d_id & 0x80000000	// R_CTL:
+			 &&	// Basic Link Service Request
+			 !(fchs->f_ctl & 0xFF000000))	// type=0 for BLS
+		{
+			// Check for ABTS (Abort Sequence)
+			if ((fchs->d_id & 0x8F000000) == 0x81000000) {
+				// look for OX_ID, S_ID pair that matches in our
+				// fcExchanges table; if found, reply with ACCept and complete
+				// the exchange
+
+				// Per PLDA, an ABTS is sent by an initiator; therefore
+				// assume that if we have an exhange open to the port who
+				// sent ABTS, it will be the d_id of what we sent.  
+				for (ExchangeID = 0, AbortAccept = 0; ExchangeID < TACH_SEST_LEN; ExchangeID++) {
+					// Valid "target" exchange 24-bit port_id matches? 
+					// NOTE: For the case of handling Intiator AND Target
+					// functions on the same chip, we can have TWO Exchanges
+					// with the same OX_ID -- OX_ID/FFFF for the CMND, and
+					// OX_ID/RX_ID for the XRDY or DATA frame(s).  Ideally,
+					// we would like to support ABTS from Initiators or Targets,
+					// but it's not clear that can be supported on Tachyon for
+					// all cases (requires more investigation).
+
+					if ((Exchanges->fcExchange[ExchangeID].type == SCSI_TWE || Exchanges->fcExchange[ExchangeID].type == SCSI_TRE)
+					    && ((Exchanges->fcExchange[ExchangeID].fchs.d_id & 0xFFFFFF) == (fchs->s_id & 0xFFFFFF))) {
+
+						// target xchnge port_id matches -- how about OX_ID?
+						if ((Exchanges->fcExchange[ExchangeID].fchs.ox_rx_id & 0xFFFF0000)
+						    == (fchs->ox_rx_id & 0xFFFF0000))
+							// yes! post ACCept response; will be completed by fcStart
+						{
+							Exchanges->fcExchange[ExchangeID].status = TARGET_ABORT;
+
+							// copy (add) rx_id field for simplified ACCept reply
+							fchs->ox_rx_id = Exchanges->fcExchange[ExchangeID].fchs.ox_rx_id;
+
+							cpqfcTSPutLinkQue(dev, BLS_ABTS_ACC,	// Q Type 
+									  fchs);	// void QueContent
+							AbortAccept = 1;
+							printk("ACCepting ABTS for x_ID %8.8Xh, SEST pair %8.8Xh\n", fchs->ox_rx_id, Exchanges->fcExchange[ExchangeID].fchs.ox_rx_id);
+							break;	// ABTS can affect only ONE exchange -exit loop
+						}
+					}
+				}	// end of FOR loop
+				if (!AbortAccept)	// can't ACCept ABTS - send Reject
+				{
+					printk("ReJecTing: can't find ExchangeID %8.8Xh for ABTS command\n", fchs->ox_rx_id);
+					if (Exchanges->fcExchange[ExchangeID].type && !(fcChip->SEST->u[ExchangeID].IWE.Hdr_Len & 0x80000000)) {
+						cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+					} else {
+						printk("Unexpected ABTS ReJecT! SEST[%X] Dword 0: %Xh\n", ExchangeID, fcChip->SEST->u[ExchangeID].IWE.Hdr_Len);
+					}
+				}
+			}
+			// Check for BLS {ABTS? (Abort Sequence)} ACCept
+			else if ((fchs->d_id & 0x8F000000) == 0x84000000) {
+				// target has responded with ACC for our ABTS;
+				// complete the indicated exchange with ABORTED status 
+				// Make no checks for correct RX_ID, since
+				// all we need to conform ABTS ACC is the OX_ID.
+				// Verify that the d_id matches!
 
-      // Check for ABTS (Abort Sequence)
-      if( (fchs->d_id & 0x8F000000) == 0x81000000)
-      {
-        // look for OX_ID, S_ID pair that matches in our
-        // fcExchanges table; if found, reply with ACCept and complete
-        // the exchange
-
-        // Per PLDA, an ABTS is sent by an initiator; therefore
-        // assume that if we have an exhange open to the port who
-        // sent ABTS, it will be the d_id of what we sent.  
-        for( ExchangeID = 0, AbortAccept=FALSE;
-             ExchangeID < TACH_SEST_LEN; ExchangeID++)
-        {
-            // Valid "target" exchange 24-bit port_id matches? 
-            // NOTE: For the case of handling Intiator AND Target
-            // functions on the same chip, we can have TWO Exchanges
-            // with the same OX_ID -- OX_ID/FFFF for the CMND, and
-            // OX_ID/RX_ID for the XRDY or DATA frame(s).  Ideally,
-            // we would like to support ABTS from Initiators or Targets,
-            // but it's not clear that can be supported on Tachyon for
-            // all cases (requires more investigation).
-            
-          if( (Exchanges->fcExchange[ ExchangeID].type == SCSI_TWE ||
-               Exchanges->fcExchange[ ExchangeID].type == SCSI_TRE)
-                  &&
-             ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
-             (fchs->s_id & 0xFFFFFF)) )
-          {
-              
-              // target xchnge port_id matches -- how about OX_ID?
-            if( (Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id &0xFFFF0000)
-                    == (fchs->ox_rx_id & 0xFFFF0000) )
-                    // yes! post ACCept response; will be completed by fcStart
-            {
-              Exchanges->fcExchange[ ExchangeID].status = TARGET_ABORT;
-                
-                // copy (add) rx_id field for simplified ACCept reply
-              fchs->ox_rx_id = 
-                Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id;
-                
-              cpqfcTSPutLinkQue( cpqfcHBAdata,
-                            BLS_ABTS_ACC, // Q Type 
-                            fchs );    // void QueContent
-              AbortAccept = TRUE;
-      printk("ACCepting ABTS for x_ID %8.8Xh, SEST pair %8.8Xh\n", 
-             fchs->ox_rx_id, Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id);
-              break;      // ABTS can affect only ONE exchange -exit loop
-            }
-          }
-        }  // end of FOR loop
-        if( !AbortAccept ) // can't ACCept ABTS - send Reject
-        {
-      printk("ReJecTing: can't find ExchangeID %8.8Xh for ABTS command\n", 
-            fchs->ox_rx_id);
-          if( Exchanges->fcExchange[ ExchangeID].type 
-                &&
-              !(fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len
-               & 0x80000000))
-          {
-            cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
-          }
-          else
-          {
-            printk("Unexpected ABTS ReJecT! SEST[%X] Dword 0: %Xh\n", 
-              ExchangeID, fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len);
-          }
-        }
-      }
-
-      // Check for BLS {ABTS? (Abort Sequence)} ACCept
-      else if( (fchs->d_id & 0x8F000000) == 0x84000000)
-      {
-        // target has responded with ACC for our ABTS;
-	// complete the indicated exchange with ABORTED status 
-        // Make no checks for correct RX_ID, since
-	// all we need to conform ABTS ACC is the OX_ID.
-        // Verify that the d_id matches!
- 
-        ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
-//	printk("ABTS ACC x_ID 0x%04X 0x%04X, status %Xh\n", 
+				ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF;	// x_id from ACC
+//      printk("ABTS ACC x_ID 0x%04X 0x%04X, status %Xh\n", 
 //          fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff,
 //          Exchanges->fcExchange[ExchangeID].status);
+				if (ExchangeID < TACH_SEST_LEN)	// x_ID makes sense
+				{
+					// Does "target" exchange 24-bit port_id match? 
+					// (See "NOTE" above for handling Intiator AND Target in
+					// the same device driver)
+					// First, if this is a target response, then we originated
+					// (initiated) it with BLS_ABTS:
+
+					if ((Exchanges->fcExchange[ExchangeID].type == BLS_ABTS) &&
+					    // Second, does the source of this ACC match the destination
+					    // of who we originally sent it to?
+					    ((Exchanges->fcExchange[ExchangeID].fchs.d_id & 0xFFFFFF) == (fchs->s_id & 0xFFFFFF))) {
+						cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+					}
+				}
+			}
+			// Check for BLS {ABTS? (Abort Sequence)} ReJecT
+			else if ((fchs->d_id & 0x8F000000) == 0x85000000) {
+				// target has responded with RJT for our ABTS;
+				// complete the indicated exchange with ABORTED status 
+				// Make no checks for correct RX_ID, since
+				// all we need to conform ABTS ACC is the OX_ID.
+				// Verify that the d_id matches!
+
+				ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF;	// x_id from ACC
+//				printk("BLS_ABTS RJT on Exchange 0x%04X 0x%04X\n", 
+//					fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff);
+
+				if (ExchangeID < TACH_SEST_LEN)	// x_ID makes sense
+				{
+					// Does "target" exchange 24-bit port_id match? 
+					// (See "NOTE" above for handling Intiator AND Target in
+					// the same device driver)
+					// First, if this is a target response, then we originated
+					// (initiated) it with BLS_ABTS:
+
+					if ((Exchanges->fcExchange[ExchangeID].type == BLS_ABTS)
+
+					    &&
+					    // Second, does the source of this ACC match the destination
+					    // of who we originally sent it to?
+					    ((Exchanges->fcExchange[ExchangeID].fchs.d_id & 0xFFFFFF) == (fchs->s_id & 0xFFFFFF))) {
+						// YES! NOTE: There is a bug in CPQ's RA-4000 box 
+						// where the "reason code" isn't returned in the payload
+						// For now, simply presume the reject is because the target
+						// already completed the exchange...
+
+//						printk("complete x_ID %Xh on ABTS RJT\n", ExchangeID);
+						cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+					}
+				}
+			}	// end of ABTS check
+		}		// end of Basic Link Service Request
+		break;
 
-
-	
-        if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
-        {
-            // Does "target" exchange 24-bit port_id match? 
-            // (See "NOTE" above for handling Intiator AND Target in
-            // the same device driver)
-            // First, if this is a target response, then we originated
-	    // (initiated) it with BLS_ABTS:
-	  
-          if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
-
-                  &&
-	    // Second, does the source of this ACC match the destination
-            // of who we originally sent it to?
-             ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
-             (fchs->s_id & 0xFFFFFF)) )
-          {
-            cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID );
-	  }
-        }              
-      }
-      // Check for BLS {ABTS? (Abort Sequence)} ReJecT
-      else if( (fchs->d_id & 0x8F000000) == 0x85000000)
-      {
-        // target has responded with RJT for our ABTS;
-	// complete the indicated exchange with ABORTED status 
-        // Make no checks for correct RX_ID, since
-	// all we need to conform ABTS ACC is the OX_ID.
-        // Verify that the d_id matches!
- 
-        ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
-//	printk("BLS_ABTS RJT on Exchange 0x%04X 0x%04X\n", 
-//          fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff);
-
-        if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
-	{  
-            // Does "target" exchange 24-bit port_id match? 
-            // (See "NOTE" above for handling Intiator AND Target in
-            // the same device driver)
-            // First, if this is a target response, then we originated
-	    // (initiated) it with BLS_ABTS:
-		  
-          if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
-
-                  &&
-	    // Second, does the source of this ACC match the destination
-            // of who we originally sent it to?
-             ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
-             (fchs->s_id & 0xFFFFFF)) )
-          {
-	    // YES! NOTE: There is a bug in CPQ's RA-4000 box 
-	    // where the "reason code" isn't returned in the payload
-	    // For now, simply presume the reject is because the target
-	    // already completed the exchange...
-	    
-//            printk("complete x_ID %Xh on ABTS RJT\n", ExchangeID);
-            cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID );
-	  }
-	} 
-      }  // end of ABTS check
-    }  // end of Basic Link Service Request
-    break;
-  
-    default:
-      printk("AnalyzeIncomingFrame: unknown type: %Xh(%d)\n",
-        fcLQ->Qitem[QNdx].Type,
-        fcLQ->Qitem[QNdx].Type);
-    break;
-  }
+	default:
+		printk("AnalyzeIncomingFrame: unknown type: %Xh(%d)\n", fcLQ->Qitem[QNdx].Type, fcLQ->Qitem[QNdx].Type);
+		break;
+	}
 }
 
 
@@ -2428,506 +1868,433 @@
 // initialization (e.g. LIP).
 // Also may be called if from Fabric Name Service logic.
 
-static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds )
+static void SendLogins(CPQFCHBA * dev, __u32 * FabricPortIds)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG ulStatus=0;
-  TachFCHDR_GCMND fchs;  // copy fields for transmission
-  int i;
-  ULONG loginType;
-  LONG ExchangeID;
-  PFC_LOGGEDIN_PORT pLoggedInPort;
-  __u32 PortIds[ number_of_al_pa];
-  int NumberOfPorts=0;
-
-  // We're going to presume (for now) that our limit of Fabric devices
-  // is the same as the number of alpa on a private loop (126 devices).
-  // (Of course this could be changed to support however many we have
-  // memory for).
-  memset( &PortIds[0], 0, sizeof(PortIds));
-   
-  // First, check if this login is for our own Link Initialization
-  // (e.g. LIP on FC-AL), or if we have knowledge of Fabric devices
-  // from a switch.  If we are logging into Fabric devices, we'll
-  // have a non-NULL FabricPortId pointer
-  
-  if( FabricPortIds != NULL) // may need logins
-  {
-    int LastPort=FALSE;
-    i = 0;
-    while( !LastPort)
-    {
-      // port IDs From NSR payload; byte swap needed?
-      BigEndianSwap( (UCHAR*)FabricPortIds, (UCHAR*)&PortIds[i], 4);
- 
-//      printk("FPortId[%d] %Xh ", i, PortIds[i]);
-      if( PortIds[i] & 0x80000000)
-	LastPort = TRUE;
-      
-      PortIds[i] &= 0xFFFFFF; // get 24-bit port_id
-      // some non-Fabric devices (like the Crossroads Fibre/Scsi bridge)
-      // erroneously use ALPA 0.
-      if( PortIds[i]  ) // need non-zero port_id...
-        i++;
-      
-      if( i >= number_of_al_pa ) // (in)sanity check
-	break;
-      FabricPortIds++;  // next...
-    }
-
-    NumberOfPorts = i;
-//    printk("NumberOf Fabric ports %d", NumberOfPorts);
-  }
-  
-  else  // need to send logins on our "local" link
-  {
-  
-    // are we a loop port?  If so, check for reception of LILP frame,
-    // and if received use it (SANMark requirement)
-    if( fcChip->Options.LILPin )
-    {
-      int j=0;
-      // sanity check on number of ALPAs from LILP frame...
-      // For format of LILP frame, see FC-AL specs or 
-      // "Fibre Channel Bench Reference", J. Stai, 1995 (ISBN 1-879936-17-8)
-      // First byte is number of ALPAs
-      i = fcChip->LILPmap[0] >= (32*4) ? 32*4 : fcChip->LILPmap[0];
-      NumberOfPorts = i;
-//      printk(" LILP alpa count %d ", i);
-      while( i > 0)
-      {
-	PortIds[j] = fcChip->LILPmap[1+ j];
-	j++; i--;
-      }
-    }
-    else  // have to send login to everybody
-    {
-      int j=0;
-      i = number_of_al_pa;
-      NumberOfPorts = i;
-      while( i > 0)
-      {
-        PortIds[j] = valid_al_pa[j]; // all legal ALPAs
-	j++; i--;
-      }
-    }
-  }
-
-
-  // Now we have a copy of the port_ids (and how many)...
-  for( i = 0; i < NumberOfPorts; i++)
-  {
-    // 24-bit FC Port ID
-    fchs.s_id = PortIds[i];  // note: only 8-bits used for ALPA
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 ulStatus = 0;
+	TachFCHDR_GCMND fchs;	// copy fields for transmission
+	int i;
+	u32 loginType;
+	s32 ExchangeID;
+	PFC_LOGGEDIN_PORT pLoggedInPort;
+	__u32 PortIds[number_of_al_pa];
+	int NumberOfPorts = 0;
+
+	// We're going to presume (for now) that our limit of Fabric devices
+	// is the same as the number of alpa on a private loop (126 devices).
+	// (Of course this could be changed to support however many we have
+	// memory for).
+	memset(&PortIds[0], 0, sizeof(PortIds));
+
+	// First, check if this login is for our own Link Initialization
+	// (e.g. LIP on FC-AL), or if we have knowledge of Fabric devices
+	// from a switch.  If we are logging into Fabric devices, we'll
+	// have a non-NULL FabricPortId pointer
 
-
-    // don't log into ourselves (Linux Scsi disk scan will stop on
-    // no TARGET support error on us, and quit trying for rest of devices)
-    if( (fchs.s_id & 0xFF ) == (fcChip->Registers.my_al_pa & 0xFF) )
-      continue;
-
-    // fabric login needed?
-    if( (fchs.s_id == 0) || 
-        (fcChip->Options.fabric == 1) )
-    {
-      fcChip->Options.flogi = 1;  // fabric needs longer for login
-      // Do we need FLOGI or FDISC?
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-             NULL,           // don't search SCSI Nexus
-             0xFFFFFC,       // search linked list for Fabric port_id
-             NULL,           // don't search WWN
-             NULL);          // (don't care about end of list)
-
-      if( pLoggedInPort )    // If found, we have prior experience with
-                             // this port -- check whether PDISC is needed
-      {
-        if( pLoggedInPort->flogi )
+	if (FabricPortIds != NULL)	// may need logins
 	{
-	  // does the switch support FDISC?? (FLOGI for now...)
-          loginType = ELS_FLOGI;  // prior FLOGI still valid
-	}
-        else
-          loginType = ELS_FLOGI;  // expired FLOGI
-      }
-      else                      // first FLOGI?
-        loginType = ELS_FLOGI;  
-
-
-      fchs.s_id = 0xFFFFFE;   // well known F_Port address
-
-      // Fabrics are not required to support FDISC, and
-      // it's not clear if that helps us anyway, since
-      // we'll want a Name Service Request to re-verify
-      // visible devices...
-      // Consequently, we always want our upper 16 bit
-      // port_id to be zero (we'll be rejected if we
-      // use our prior port_id if we've been plugged into
-      // a different switch port).
-      // Trick Tachyon to send to ALPA 0 (see TL/TS UG, pg 87)
-      // If our ALPA is 55h for instance, we want the FC frame
-      // s_id to be 0x000055, while Tach's my_al_pa register
-      // must be 0x000155, to force an OPN at ALPA 0 
-      // (the Fabric port)
-      fcChip->Registers.my_al_pa &= 0xFF; // only use ALPA for FLOGI
-      writel( fcChip->Registers.my_al_pa | 0x0100,  
-        fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
-    }
+		int LastPort = 0;
+		i = 0;
+		while (!LastPort) {
+			// port IDs From NSR payload; byte swap needed?
+			BigEndianSwap((u8 *) FabricPortIds, (u8 *) & PortIds[i], 4);
+
+//			printk("FPortId[%d] %Xh ", i, PortIds[i]);
+			if (PortIds[i] & 0x80000000)
+				LastPort = 1;
+
+			PortIds[i] &= 0xFFFFFF;	// get 24-bit port_id
+			// some non-Fabric devices (like the Crossroads Fibre/Scsi bridge)
+			// erroneously use ALPA 0.
+			if (PortIds[i])	// need non-zero port_id...
+				i++;
+
+			if (i >= number_of_al_pa)	// (in)sanity check
+				break;
+			FabricPortIds++;	// next...
+		}
 
-    else // not FLOGI...
-    {
-      // should we send PLOGI or PDISC?  Check if any prior port_id
-      // (e.g. alpa) completed a PLOGI/PRLI exchange by checking 
-      // the pdisc flag.
-
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-             NULL,           // don't search SCSI Nexus
-             fchs.s_id,      // search linked list for al_pa
-             NULL,           // don't search WWN
-             NULL);          // (don't care about end of list)
-
-             
-
-      if( pLoggedInPort )      // If found, we have prior experience with
-                             // this port -- check whether PDISC is needed
-      {
-        if( pLoggedInPort->pdisc )
+		NumberOfPorts = i;
+//    printk("NumberOf Fabric ports %d", NumberOfPorts);
+	}
+	else			// need to send logins on our "local" link
 	{
-          loginType = ELS_PDISC;  // prior PLOGI and PRLI maybe still valid
-           
+		// are we a loop port?  If so, check for reception of LILP frame,
+		// and if received use it (SANMark requirement)
+		if (fcChip->Options.LILPin) {
+			int j = 0;
+			// sanity check on number of ALPAs from LILP frame...
+			// For format of LILP frame, see FC-AL specs or 
+			// "Fibre Channel Bench Reference", J. Stai, 1995 (ISBN 1-879936-17-8)
+			// First byte is number of ALPAs
+			i = fcChip->LILPmap[0] >= (32 * 4) ? 32 * 4 : fcChip->LILPmap[0];
+			NumberOfPorts = i;
+//			printk(" LILP alpa count %d ", i);
+			while (i > 0) {
+				PortIds[j] = fcChip->LILPmap[1 + j];
+				j++;
+				i--;
+			}
+		}
+		else		// have to send login to everybody
+		{
+			int j = 0;
+			i = number_of_al_pa;
+			NumberOfPorts = i;
+			while (i > 0) {
+				PortIds[j] = valid_al_pa[j];	// all legal ALPAs
+				j++;
+				i--;
+			}
+		}
 	}
-        else
-          loginType = ELS_PLOGI;  // prior knowledge, but can't use PDISC
-      }
-      else                      // never talked to this port_id before
-        loginType = ELS_PLOGI;  // prior knowledge, but can't use PDISC
-    }
-
-
-    
-    ulStatus = cpqfcTSBuildExchange(
-          cpqfcHBAdata,
-          loginType,            // e.g. PLOGI
-          &fchs,        // no incoming frame (we are originator)
-          NULL,         // no data (no scatter/gather list)
-          &ExchangeID );// fcController->fcExchanges index, -1 if failed
 
-    if( !ulStatus ) // Exchange setup OK?
-    {
-      ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
-      if( !ulStatus )
-      {
-          // submitted to Tach's Outbound Que (ERQ PI incremented)
-          // waited for completion for ELS type (Login frames issued
-          // synchronously)
+	// Now we have a copy of the port_ids (and how many)...
+	for (i = 0; i < NumberOfPorts; i++) {
+		// 24-bit FC Port ID
+		fchs.s_id = PortIds[i];	// note: only 8-bits used for ALPA
+		// don't log into ourselves (Linux Scsi disk scan will stop on
+		// no TARGET support error on us, and quit trying for rest of devices)
+		if ((fchs.s_id & 0xFF) == (fcChip->Registers.my_al_pa & 0xFF))
+			continue;
+		// fabric login needed?
+		if ((fchs.s_id == 0) || (fcChip->Options.fabric == 1)) {
+			fcChip->Options.flogi = 1;	// fabric needs longer for login
+			// Do we need FLOGI or FDISC?
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search SCSI Nexus
+							   0xFFFFFC,	// search linked list for Fabric port_id
+							   NULL,	// don't search WWN
+							   NULL);	// (don't care about end of list)
+
+			if (pLoggedInPort)	// If found, we have prior experience with
+				// this port -- check whether PDISC is needed
+			{
+				if (pLoggedInPort->flogi) {
+					// does the switch support FDISC?? (FLOGI for now...)
+					loginType = ELS_FLOGI;	// prior FLOGI still valid
+				} else
+					loginType = ELS_FLOGI;	// expired FLOGI
+			} else	// first FLOGI?
+				loginType = ELS_FLOGI;
+
+			fchs.s_id = 0xFFFFFE;	// well known F_Port address
+
+			// Fabrics are not required to support FDISC, and
+			// it's not clear if that helps us anyway, since
+			// we'll want a Name Service Request to re-verify
+			// visible devices...
+			// Consequently, we always want our upper 16 bit
+			// port_id to be zero (we'll be rejected if we
+			// use our prior port_id if we've been plugged into
+			// a different switch port).
+			// Trick Tachyon to send to ALPA 0 (see TL/TS UG, pg 87)
+			// If our ALPA is 55h for instance, we want the FC frame
+			// s_id to be 0x000055, while Tach's my_al_pa register
+			// must be 0x000155, to force an OPN at ALPA 0 
+			// (the Fabric port)
+			fcChip->Registers.my_al_pa &= 0xFF;	// only use ALPA for FLOGI
+			writel(fcChip->Registers.my_al_pa | 0x0100, fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
+		}
+		else		// not FLOGI...
+		{
+			// should we send PLOGI or PDISC?  Check if any prior port_id
+			// (e.g. alpa) completed a PLOGI/PRLI exchange by checking 
+			// the pdisc flag.
+
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search SCSI Nexus
+							   fchs.s_id,	// search linked list for al_pa
+							   NULL,	// don't search WWN
+							   NULL);	// (don't care about end of list)
+
+			if (pLoggedInPort)	// If found, we have prior experience with
+				// this port -- check whether PDISC is needed
+			{
+				if (pLoggedInPort->pdisc) {
+					loginType = ELS_PDISC;	// prior PLOGI and PRLI maybe still valid
+				} else
+					loginType = ELS_PLOGI;	// prior knowledge, but can't use PDISC
+			} else	// never talked to this port_id before
+				loginType = ELS_PLOGI;	// prior knowledge, but can't use PDISC
+		}
 
-	if( loginType == ELS_PDISC )
-	{
-	  // now, we really shouldn't Revalidate SEST exchanges until
-	  // we get an ACC reply from our target and verify that
-	  // the target address/WWN is unchanged.  However, when a fast
-	  // target gets the PDISC, they can send SEST Exchange data
-	  // before we even get around to processing the PDISC ACC.
-	  // Consequently, we lose the I/O.
-	  // To avoid this, go ahead and Revalidate when the PDISC goes
-	  // out, anticipating that the ACC will be truly acceptable
-	  // (this happens 99.9999....% of the time).
-	  // If we revalidate a SEST write, and write data goes to a
-	  // target that is NOT the one we originated the WRITE to,
-	  // that target is required (FCP-SCSI specs, etc) to discard 
-	  // our WRITE data.
-
-          // Re-validate SEST entries (Tachyon hardware assists)
-          RevalidateSEST( cpqfcHBAdata->HostAdapter, pLoggedInPort); 
-    //TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
-	}
-      }
-      else  // give up immediately on error
-      {
+		ulStatus = cpqfcTSBuildExchange(dev, loginType,	// e.g. PLOGI
+						&fchs,	// no incoming frame (we are originator)
+						NULL,	// no data (no scatter/gather list)
+						&ExchangeID);	// fcController->fcExchanges index, -1 if failed
+
+		if (!ulStatus)	// Exchange setup OK?
+		{
+			ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
+			if (!ulStatus) {
+				// submitted to Tach's Outbound Que (ERQ PI incremented)
+				// waited for completion for ELS type (Login frames issued
+				// synchronously)
+
+				if (loginType == ELS_PDISC) {
+					// now, we really shouldn't Revalidate SEST exchanges until
+					// we get an ACC reply from our target and verify that
+					// the target address/WWN is unchanged.  However, when a fast
+					// target gets the PDISC, they can send SEST Exchange data
+					// before we even get around to processing the PDISC ACC.
+					// Consequently, we lose the I/O.
+					// To avoid this, go ahead and Revalidate when the PDISC goes
+					// out, anticipating that the ACC will be truly acceptable
+					// (this happens 99.9999....% of the time).
+					// If we revalidate a SEST write, and write data goes to a
+					// target that is NOT the one we originated the WRITE to,
+					// that target is required (FCP-SCSI specs, etc) to discard 
+					// our WRITE data.
+
+					// Re-validate SEST entries (Tachyon hardware assists)
+					RevalidateSEST(dev->HostAdapter, pLoggedInPort);
+					//TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
+				}
+			} else	// give up immediately on error
+			{
 #ifdef LOGIN_DBG
-        printk("SendLogins: fcStartExchange failed: %Xh\n", ulStatus );
+				printk("SendLogins: fcStartExchange failed: %Xh\n", ulStatus);
 #endif
-        break;
-      }
+				break;
+			}
+
 
-              
-      if( fcChip->Registers.FMstatus.value & 0x080 ) // LDn during Port Disc.
-      {
-        ulStatus = LNKDWN_OSLS;
+			if (fcChip->Registers.FMstatus.value & 0x080)	// LDn during Port Disc.
+			{
+				ulStatus = LNKDWN_OSLS;
 #ifdef LOGIN_DBG
-        printk("SendLogins: PortDisc aborted (LDn) @alpa %Xh\n", fchs.s_id);
+				printk("SendLogins: PortDisc aborted (LDn) @alpa %Xh\n", fchs.s_id);
 #endif
-        break;
-      }
-        // Check the exchange for bad status (i.e. FrameTimeOut),
-        // and complete on bad status (most likely due to BAD_ALPA)
-        // on LDn, DPC function may already complete (ABORT) a started
-        // exchange, so check type first (type = 0 on complete).
-      if( Exchanges->fcExchange[ExchangeID].status )
-      {
-#ifdef LOGIN_DBG 
- 	printk("completing x_ID %X on status %Xh\n", 
-          ExchangeID, Exchanges->fcExchange[ExchangeID].status);
+				break;
+			}
+			// Check the exchange for bad status (i.e. FrameTimeOut),
+			// and complete on bad status (most likely due to BAD_ALPA)
+			// on LDn, DPC function may already complete (ABORT) a started
+			// exchange, so check type first (type = 0 on complete).
+			if (Exchanges->fcExchange[ExchangeID].status) {
+#ifdef LOGIN_DBG
+				printk("completing x_ID %X on status %Xh\n", ExchangeID, Exchanges->fcExchange[ExchangeID].status);
 #endif
-        cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
-      }
-    }
-    else   // Xchange setup failed...
-    {
+				cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+			}
+		} else		// Xchange setup failed...
+		{
 #ifdef LOGIN_DBG
-      printk("FC: cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
+			printk("FC: cpqfcTSBuildExchange failed: %Xh\n", ulStatus);
 #endif
-      break;
-    }
-  }
-  if( !ulStatus )
-  {
-    // set the event signifying that all ALPAs were sent out.
+			break;
+		}
+	}
+	if (!ulStatus) {
+		// set the event signifying that all ALPAs were sent out.
 #ifdef LOGIN_DBG
-    printk("SendLogins: PortDiscDone\n");
+		printk("SendLogins: PortDiscDone\n");
 #endif
-    cpqfcHBAdata->PortDiscDone = 1;
-
-
-    // TL/TS UG, pg. 184
-    // 0x0065 = 100ms for RT_TOV
-    // 0x01f5 = 500ms for ED_TOV
-    fcChip->Registers.ed_tov.value = 0x006501f5L; 
-    writel( fcChip->Registers.ed_tov.value,
-      (fcChip->Registers.ed_tov.address));
-
-    // set the LP_TOV back to ED_TOV (i.e. 500 ms)
-    writel( 0x00000010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
-  }
-  else
-  {
-    printk("SendLogins: failed at xchng %Xh, alpa %Xh, status %Xh\n", 
-      ExchangeID, fchs.s_id, ulStatus);
-  }
-  LEAVE("SendLogins");
+		dev->PortDiscDone = 1;
+		// TL/TS UG, pg. 184
+		// 0x0065 = 100ms for RT_TOV
+		// 0x01f5 = 500ms for ED_TOV
+		fcChip->Registers.ed_tov.value = 0x006501f5L;
+		writel(fcChip->Registers.ed_tov.value, (fcChip->Registers.ed_tov.address));
+
+		// set the LP_TOV back to ED_TOV (i.e. 500 ms)
+		writel(0x00000010, fcChip->Registers.ReMapMemBase + TL_MEM_FM_TIMEOUT2);
+	} else {
+		printk("SendLogins: failed at xchng %Xh, alpa %Xh, status %Xh\n", ExchangeID, fchs.s_id, ulStatus);
+	}
+	LEAVE("SendLogins");
 
 }
 
-
 // for REPORT_LUNS documentation, see "In-Depth Exploration of Scsi",
 // D. Deming, 1994, pg 7-19 (ISBN 1-879936-08-9)
-static void ScsiReportLunsDone(Scsi_Cmnd *Cmnd)
+static void ScsiReportLunsDone(Scsi_Cmnd * Cmnd)
 {
-  struct Scsi_Host *HostAdapter = Cmnd->host;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  PFC_LOGGEDIN_PORT pLoggedInPort; 
-  int LunListLen=0;
-  int i;
-  ULONG x_ID = 0xFFFFFFFF;
-  UCHAR *ucBuff = Cmnd->request_buffer;
-
-//  printk("cpqfcTS: ReportLunsDone \n");
-  // first, we need to find the Exchange for this command,
-  // so we can find the fcPort struct to make the indicated
-  // changes.
-  for( i=0; i< TACH_SEST_LEN; i++)
-  {
-    if( Exchanges->fcExchange[i].type   // exchange defined?
-                   &&
-       (Exchanges->fcExchange[i].Cmnd == Cmnd) ) // matches?
-	      
-    {
-      x_ID = i;  // found exchange!
-      break;
-    }
-  }
-  if( x_ID == 0xFFFFFFFF)
-  {
-//    printk("cpqfcTS: ReportLuns failed - no FC Exchange\n");
-    goto Done;  // Report Luns FC Exchange gone; 
-                // exchange probably Terminated by Implicit logout
-  }
+	struct Scsi_Host *shpnt = Cmnd->host;
+	CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	PFC_LOGGEDIN_PORT pLoggedInPort;
+	int LunListLen = 0;
+	int i;
+	u32 x_ID = 0xFFFFFFFF;
+	u8 *ucBuff = Cmnd->request_buffer;
+
+	//  printk("cpqfcTS: ReportLunsDone \n");
+	// first, we need to find the Exchange for this command,
+	// so we can find the fcPort struct to make the indicated
+	// changes.
+	for (i = 0; i < TACH_SEST_LEN; i++) {
+		if (Exchanges->fcExchange[i].type	// exchange defined?
+		    && (Exchanges->fcExchange[i].Cmnd == Cmnd))	// matches?
+
+		{
+			x_ID = i;	// found exchange!
+			break;
+		}
+	}
+	if (x_ID == 0xFFFFFFFF) {
+//		printk("cpqfcTS: ReportLuns failed - no FC Exchange\n");
+		goto Done;	// Report Luns FC Exchange gone; 
+		// exchange probably Terminated by Implicit logout
+	}
 
+	// search linked list for the port_id we sent INQUIRY to
+	pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// DON'T search Scsi Nexus (we will set it)
+					   Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF, NULL,	// DON'T search linked list for FC WWN
+					   NULL);	// DON'T care about end of list
+
+	if (!pLoggedInPort) {
+//		printk("cpqfcTS: ReportLuns failed - device gone\n");
+		goto Done;	// error! can't find logged in Port
+	}
+	LunListLen = ucBuff[3];
+	LunListLen += ucBuff[2] >> 8;
 
-  // search linked list for the port_id we sent INQUIRY to
-  pLoggedInPort = fcFindLoggedInPort( fcChip,
-    NULL,     // DON'T search Scsi Nexus (we will set it)
-    Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,        
-    NULL,     // DON'T search linked list for FC WWN
-    NULL);    // DON'T care about end of list
- 
-  if( !pLoggedInPort )
-  {
-//    printk("cpqfcTS: ReportLuns failed - device gone\n");
-    goto Done; // error! can't find logged in Port
-  }    
-  LunListLen = ucBuff[3];
-  LunListLen += ucBuff[2]>>8;
+	if (!LunListLen)	// failed
+	{
+		// generically speaking, a soft error means we should retry...
+		if ((Cmnd->result >> 16) == DID_SOFT_ERROR) {
+			if (((Cmnd->sense_buffer[2] & 0xF) == 0x6) && (Cmnd->sense_buffer[12] == 0x29))	// Sense Code "reset"
+			{
+				TachFCHDR_GCMND *fchs = &Exchanges->fcExchange[x_ID].fchs;
+				// did we fail because of "check condition, device reset?"
+				// e.g. the device was reset (i.e., at every power up)
+				// retry the Report Luns
+
+				// who are we sending it to?
+				// we know this because we have a copy of the command
+				// frame from the original Report Lun command -
+				// switch the d_id/s_id fields, because the Exchange Build
+				// context is "reply to source".
 
-  if( !LunListLen )  // failed
-  {
-    // generically speaking, a soft error means we should retry...
-    if( (Cmnd->result >> 16) == DID_SOFT_ERROR )
-    {
-      if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
-	        (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
-      {
-        TachFCHDR_GCMND *fchs = &Exchanges->fcExchange[ x_ID].fchs;
-      // did we fail because of "check condition, device reset?"
-      // e.g. the device was reset (i.e., at every power up)
-      // retry the Report Luns
-      
-      // who are we sending it to?
-      // we know this because we have a copy of the command
-      // frame from the original Report Lun command -
-      // switch the d_id/s_id fields, because the Exchange Build
-      // context is "reply to source".
-      
-        fchs->s_id = fchs->d_id; // (temporarily re-use the struct)
-        cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
-      }
-    }
-    else  // probably, the device doesn't support Report Luns
-      pLoggedInPort->ScsiNexus.VolumeSetAddressing = 0;  
-  }
-  else  // we have LUN info - check VSA mode
-  {
-    // for now, assume all LUNs will have same addr mode
-    // for VSA, payload byte 8 will be 0x40; otherwise, 0
-    pLoggedInPort->ScsiNexus.VolumeSetAddressing = ucBuff[8];  
-      
-    // Since we got a Report Luns answer, set lun masking flag
-    pLoggedInPort->ScsiNexus.LunMasking = 1;
+				fchs->s_id = fchs->d_id;	// (temporarily re-use the struct)
+				cpqfcTSPutLinkQue(dev, SCSI_REPORT_LUNS, fchs);
+			}
+		} else		// probably, the device doesn't support Report Luns
+			pLoggedInPort->ScsiNexus.VolumeSetAddressing = 0;
+	} else			// we have LUN info - check VSA mode
+	{
+		// for now, assume all LUNs will have same addr mode
+		// for VSA, payload byte 8 will be 0x40; otherwise, 0
+		pLoggedInPort->ScsiNexus.VolumeSetAddressing = ucBuff[8];
 
-    if( LunListLen > 8*CPQFCTS_MAX_LUN)   // We expect CPQFCTS_MAX_LUN max
-      LunListLen = 8*CPQFCTS_MAX_LUN;
+		// Since we got a Report Luns answer, set lun masking flag
+		pLoggedInPort->ScsiNexus.LunMasking = 1;
+
+		if (LunListLen > 8 * CPQFCTS_MAX_LUN)	// We expect CPQFCTS_MAX_LUN max
+			LunListLen = 8 * CPQFCTS_MAX_LUN;
 
 /*   
-    printk("Device WWN %08X%08X Reports Luns @: ", 
-          (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF), 
-          (ULONG)(pLoggedInPort->u.liWWN>>32));
+		printk("Device WWN %08X%08X Reports Luns @: ", 
+			(u32)(pLoggedInPort->u.liWWN &0xFFFFFFFF), 
+			(u32)(pLoggedInPort->u.liWWN>>32));
 	    
-    for( i=8; i<LunListLen+8; i+=8)
-    {  
-      printk("%02X%02X ", ucBuff[i], ucBuff[i+1] );
-    }
-    printk("\n");
+		for( i=8; i<LunListLen+8; i+=8)
+		{  
+			printk("%02X%02X ", ucBuff[i], ucBuff[i+1] );
+		}
+		printk("\n");
 */
-    
-    // Since the device was kind enough to tell us where the
-    // LUNs are, lets ensure they are contiguous for Linux's
-    // SCSI driver scan, which expects them to start at 0.
-    // Since Linux only supports 8 LUNs, only copy the first
-    // eight from the report luns command
-
-    // e.g., the Compaq RA4x00 f/w Rev 2.54 and above may report
-    // LUNs 4001, 4004, etc., because other LUNs are masked from
-    // this HBA (owned by someone else).  We'll make those appear as
-    // LUN 0, 1... to Linux
-    {
-      int j;
-      int AppendLunList = 0;
-      // Walk through the LUN list.  The 'j' array number is
-      // Linux's lun #, while the value of .lun[j] is the target's
-      // lun #.
-      // Once we build a LUN list, it's possible for a known device 
-      // to go offline while volumes (LUNs) are added.  Later,
-      // the device will do another PLOGI ... Report Luns command,
-      // and we must not alter the existing Linux Lun map.
-      // (This will be very rare).
-      for( j=0; j < CPQFCTS_MAX_LUN; j++)
-      {
-        if( pLoggedInPort->ScsiNexus.lun[j] != 0xFF )
-	{
-	  AppendLunList = 1;
-	  break;
-	}
-      }
-      if( AppendLunList )
-      {
-	int k;
-        int FreeLunIndex;
-//        printk("cpqfcTS: AppendLunList\n");
-
-	// If we get a new Report Luns, we cannot change
-	// any existing LUN mapping! (Only additive entry)
-	// For all LUNs in ReportLun list
-	// if RL lun != ScsiNexus lun
-	//   if RL lun present in ScsiNexus lun[], continue
-	//   else find ScsiNexus lun[]==FF and add, continue
-	
-        for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
-	{
-          if( pLoggedInPort->ScsiNexus.lun[j] != ucBuff[i+1] )
-	  {
-	    // something changed from the last Report Luns
-	    printk(" cpqfcTS: Report Lun change!\n");
-	    for( k=0, FreeLunIndex=CPQFCTS_MAX_LUN; 
-                 k < CPQFCTS_MAX_LUN; k++)
-            {
-	      if( pLoggedInPort->ScsiNexus.lun[k] == 0xFF)
-	      {
-		FreeLunIndex = k;
-		break;
-	      }
-              if( pLoggedInPort->ScsiNexus.lun[k] == ucBuff[i+1] )
-		break; // we already masked this lun
-	    }
-	    if( k >= CPQFCTS_MAX_LUN )
-	    {
-	      printk(" no room for new LUN %d\n", ucBuff[i+1]);
-	    }
-	    else if( k == FreeLunIndex )  // need to add LUN
-	    {
-	      pLoggedInPort->ScsiNexus.lun[k] = ucBuff[i+1];
-//	      printk("add [%d]->%02d\n", k, pLoggedInPort->ScsiNexus.lun[k]);
-	      
-	    }
-	    else
-	    {
-	      // lun already known
-	    }
-	    break;
-	  }
-	}
-	// print out the new list...
-	for( j=0; j< CPQFCTS_MAX_LUN; j++)
-	{
-	  if( pLoggedInPort->ScsiNexus.lun[j] == 0xFF)
-	    break; // done
-//	  printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
-	}
-      }
-      else
-      {
-//	  printk("Linux SCSI LUNs[] -> Device LUNs: ");
-	// first time - this is easy
-        for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
-	{
-          pLoggedInPort->ScsiNexus.lun[j] = ucBuff[i+1];
-//	  printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
+
+		// Since the device was kind enough to tell us where the
+		// LUNs are, lets ensure they are contiguous for Linux's
+		// SCSI driver scan, which expects them to start at 0.
+		// Since Linux only supports 8 LUNs, only copy the first
+		// eight from the report luns command
+
+		// e.g., the Compaq RA4x00 f/w Rev 2.54 and above may report
+		// LUNs 4001, 4004, etc., because other LUNs are masked from
+		// this HBA (owned by someone else).  We'll make those appear as
+		// LUN 0, 1... to Linux
+		{
+			int j;
+			int AppendLunList = 0;
+			// Walk through the LUN list.  The 'j' array number is
+			// Linux's lun #, while the value of .lun[j] is the target's
+			// lun #.
+			// Once we build a LUN list, it's possible for a known device 
+			// to go offline while volumes (LUNs) are added.  Later,
+			// the device will do another PLOGI ... Report Luns command,
+			// and we must not alter the existing Linux Lun map.
+			// (This will be very rare).
+			for (j = 0; j < CPQFCTS_MAX_LUN; j++) {
+				if (pLoggedInPort->ScsiNexus.lun[j] != 0xFF) {
+					AppendLunList = 1;
+					break;
+				}
+			}
+			if (AppendLunList) {
+				int k;
+				int FreeLunIndex;
+//				printk("cpqfcTS: AppendLunList\n");
+
+				// If we get a new Report Luns, we cannot change
+				// any existing LUN mapping! (Only additive entry)
+				// For all LUNs in ReportLun list
+				// if RL lun != ScsiNexus lun
+				//   if RL lun present in ScsiNexus lun[], continue
+				//   else find ScsiNexus lun[]==FF and add, continue
+
+				for (i = 8, j = 0; i < LunListLen + 8 && j < CPQFCTS_MAX_LUN; i += 8, j++) {
+					if (pLoggedInPort->ScsiNexus.lun[j] != ucBuff[i + 1]) {
+						// something changed from the last Report Luns
+						printk(" cpqfcTS: Report Lun change!\n");
+						for (k = 0, FreeLunIndex = CPQFCTS_MAX_LUN; k < CPQFCTS_MAX_LUN; k++) {
+							if (pLoggedInPort->ScsiNexus.lun[k] == 0xFF) {
+								FreeLunIndex = k;
+								break;
+							}
+							if (pLoggedInPort->ScsiNexus.lun[k] == ucBuff[i + 1])
+								break;	// we already masked this lun
+						}
+						if (k >= CPQFCTS_MAX_LUN) {
+							printk(" no room for new LUN %d\n", ucBuff[i + 1]);
+						} else if (k == FreeLunIndex)	// need to add LUN
+						{
+							pLoggedInPort->ScsiNexus.lun[k] = ucBuff[i + 1];
+//							printk("add [%d]->%02d\n", k, pLoggedInPort->ScsiNexus.lun[k]);
+
+						} else {
+							// lun already known
+						}
+						break;
+					}
+				}
+				// print out the new list...
+				for (j = 0; j < CPQFCTS_MAX_LUN; j++) {
+					if (pLoggedInPort->ScsiNexus.lun[j] == 0xFF)
+						break;	// done
+//					printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
+				}
+			} else {
+//				printk("Linux SCSI LUNs[] -> Device LUNs: ");
+				// first time - this is easy
+				for (i = 8, j = 0; i < LunListLen + 8 && j < CPQFCTS_MAX_LUN; i += 8, j++) {
+					pLoggedInPort->ScsiNexus.lun[j] = ucBuff[i + 1];
+//					printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
+				}
+//				printk("\n");
+			}
+		}
 	}
-//	printk("\n");
-      }
-    }
-  }
 
-Done:  ;
+      Done:;
 }
 
-static void 
-call_scsi_done(Scsi_Cmnd *Cmnd)
+static void call_scsi_done(Scsi_Cmnd * Cmnd)
 {
 	// We have to reinitialize sent_command here, so the scsi-mid
 	// layer won't re-use the scsi command leaving it set incorrectly.
 	// (incorrectly for our purposes...it's normally unused.)
 
-        if (Cmnd->SCp.sent_command != 0) {	// was it a passthru?
+	if (Cmnd->SCp.sent_command != 0) {	// was it a passthru?
 		Cmnd->SCp.sent_command = 0;
 		Cmnd->result &= 0xff00ffff;
-		Cmnd->result |= (DID_PASSTHROUGH << 16);  // prevents retry
+		Cmnd->result |= (DID_PASSTHROUGH << 16);	// prevents retry
 	}
 	if (Cmnd->scsi_done != NULL)
-		(*Cmnd->scsi_done)(Cmnd);
+		(*Cmnd->scsi_done) (Cmnd);
 }
 
 // After successfully getting a "Process Login" (PRLI) from an
@@ -2939,361 +2306,301 @@
 // driver model, which expects a contiguous LUNs starting at 0,
 // will use the ReportLuns info to map from "device" to "Linux" 
 // LUNs.
-static void IssueReportLunsCommand( 
-              CPQFCHBA* cpqfcHBAdata, 
-	      TachFCHDR_GCMND* fchs)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  PFC_LOGGEDIN_PORT pLoggedInPort; 
-  Scsi_Cmnd *Cmnd;
-  LONG x_ID;
-  ULONG ulStatus;
-  UCHAR *ucBuff;
-
-  if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
-  {
-    printk("Discard Q'd ReportLun command\n");
-    goto Done;
-  }
-
-  // find the device (from port_id) we're talking to
-  pLoggedInPort = fcFindLoggedInPort( fcChip,
-        NULL,     // DON'T search Scsi Nexus 
-  	fchs->s_id & 0xFFFFFF,        
-	NULL,     // DON'T search linked list for FC WWN
-        NULL);    // DON'T care about end of list
-  if( pLoggedInPort ) // we'd BETTER find it!
-  {
-
-
-    if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) )
-      goto Done;  // forget it - FC device not a "target"
-
-    // now use the port's Scsi Command buffer for the 
-    // Report Luns Command
- 
-    Cmnd = &pLoggedInPort->ScsiCmnd; 
-    ucBuff = pLoggedInPort->ReportLunsPayload;
-    
-    memset( Cmnd, 0, sizeof(Scsi_Cmnd));
-    memset( ucBuff, 0, REPORT_LUNS_PL);
-    
-    Cmnd->scsi_done = ScsiReportLunsDone;
-    Cmnd->host = cpqfcHBAdata->HostAdapter;
-
-    Cmnd->request_buffer = pLoggedInPort->ReportLunsPayload; 
-    Cmnd->request_bufflen = REPORT_LUNS_PL; 
-	    
-    Cmnd->cmnd[0] = 0xA0;
-    Cmnd->cmnd[8] = REPORT_LUNS_PL >> 8;
-    Cmnd->cmnd[9] = (UCHAR)REPORT_LUNS_PL;
-    Cmnd->cmd_len = 12;
-
-    Cmnd->channel = pLoggedInPort->ScsiNexus.channel;
-    Cmnd->target = pLoggedInPort->ScsiNexus.target;
+static void IssueReportLunsCommand(CPQFCHBA * dev, TachFCHDR_GCMND * fchs)
+{
+	PTACHYON fcChip = &dev->fcChip;
+	PFC_LOGGEDIN_PORT pLoggedInPort;
+	Scsi_Cmnd *Cmnd;
+	s32 x_ID;
+	u32 ulStatus;
+	u8 *ucBuff;
 
-	    
-    ulStatus = cpqfcTSBuildExchange(
-      cpqfcHBAdata,
-      SCSI_IRE, 
-      fchs,
-      Cmnd,         // buffer for Report Lun data
-      &x_ID );// fcController->fcExchanges index, -1 if failed
+	if (!dev->PortDiscDone)	// cleared by LDn
+	{
+		printk("Discard Q'd ReportLun command\n");
+		goto Done;
+	}
+	// find the device (from port_id) we're talking to
+	pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// DON'T search Scsi Nexus 
+					   fchs->s_id & 0xFFFFFF, NULL,	// DON'T search linked list for FC WWN
+					   NULL);	// DON'T care about end of list
+	if (pLoggedInPort)	// we'd BETTER find it!
+	{
 
-    if( !ulStatus ) // Exchange setup?
-    {
-      ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
-      if( !ulStatus )
-      {
-        // submitted to Tach's Outbound Que (ERQ PI incremented)
-        // waited for completion for ELS type (Login frames issued
-        // synchronously)
-      }
-      else
-        // check reason for Exchange not being started - we might
-        // want to Queue and start later, or fail with error
-      {
-  
-      }
-    }
 
-    else   // Xchange setup failed...
-      printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
-  }
-  else     // like, we just got a PRLI ACC, and now the port is gone?
-  {
-    printk(" can't send ReportLuns - no login for port_id %Xh\n",
-	    fchs->s_id & 0xFFFFFF);
-  }
+		if (!(pLoggedInPort->fcp_info & TARGET_FUNCTION))
+			goto Done;	// forget it - FC device not a "target"
 
+		// now use the port's Scsi Command buffer for the 
+		// Report Luns Command
 
+		Cmnd = &pLoggedInPort->ScsiCmnd;
+		ucBuff = pLoggedInPort->ReportLunsPayload;
 
-Done: ;
+		memset(Cmnd, 0, sizeof(Scsi_Cmnd));
+		memset(ucBuff, 0, REPORT_LUNS_PL);
+
+		Cmnd->scsi_done = ScsiReportLunsDone;
+		Cmnd->host = dev->HostAdapter;
+
+		Cmnd->request_buffer = pLoggedInPort->ReportLunsPayload;
+		Cmnd->request_bufflen = REPORT_LUNS_PL;
+
+		Cmnd->cmnd[0] = 0xA0;
+		Cmnd->cmnd[8] = REPORT_LUNS_PL >> 8;
+		Cmnd->cmnd[9] = (u8) REPORT_LUNS_PL;
+		Cmnd->cmd_len = 12;
+
+		Cmnd->channel = pLoggedInPort->ScsiNexus.channel;
+		Cmnd->target = pLoggedInPort->ScsiNexus.target;
+
+
+		ulStatus = cpqfcTSBuildExchange(dev, SCSI_IRE, fchs, Cmnd,	// buffer for Report Lun data
+						&x_ID);	// fcController->fcExchanges index, -1 if failed
+
+		if (!ulStatus)	// Exchange setup?
+		{
+			ulStatus = cpqfcTSStartExchange(dev, x_ID);
+			if (!ulStatus) {
+				// submitted to Tach's Outbound Que (ERQ PI incremented)
+				// waited for completion for ELS type (Login frames issued
+				// synchronously)
+			} else
+				// check reason for Exchange not being started - we might
+				// want to Queue and start later, or fail with error
+			{
+			}
+		}
 
+		else		// Xchange setup failed...
+			printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus);
+	} else			// like, we just got a PRLI ACC, and now the port is gone?
+	{
+		printk(" can't send ReportLuns - no login for port_id %Xh\n", fchs->s_id & 0xFFFFFF);
+	}
+Done:;
 }
 
-
-
-
-
-
-
-static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata)
+static void CompleteBoardLockCmnd(CPQFCHBA * dev)
 {
-  int i;
-  for( i = CPQFCTS_REQ_QUEUE_LEN-1; i>= 0; i--)
-  {
-    if( cpqfcHBAdata->BoardLockCmnd[i] != NULL )
-    {
-      Scsi_Cmnd *Cmnd = cpqfcHBAdata->BoardLockCmnd[i];
-      cpqfcHBAdata->BoardLockCmnd[i] = NULL;
-      Cmnd->result = (DID_SOFT_ERROR << 16);  // ask for retry
-//      printk(" BoardLockCmnd[%d] %p Complete, chnl/target/lun %d/%d/%d\n",
-//        i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
-      call_scsi_done(Cmnd);
-    }
-  }
+	int i;
+	for (i = CPQFCTS_REQ_QUEUE_LEN - 1; i >= 0; i--) {
+		if (dev->BoardLockCmnd[i] != NULL) {
+			Scsi_Cmnd *Cmnd = dev->BoardLockCmnd[i];
+			dev->BoardLockCmnd[i] = NULL;
+			Cmnd->result = (DID_SOFT_ERROR << 16);	// ask for retry
+//			printk(" BoardLockCmnd[%d] %p Complete, chnl/target/lun %d/%d/%d\n",
+//				i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
+			call_scsi_done(Cmnd);
+		}
+	}
 }
 
+// runs every 1 second for FC exchange timeouts and implicit FC device logouts
 
+void cpqfcTSheartbeat(unsigned long ptr)
+{
+	CPQFCHBA *dev = (CPQFCHBA *) ptr;
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
+	u32 i;
+	unsigned long flags;
+	DECLARE_MUTEX_LOCKED(BoardLock);
 
+	PCI_TRACE(0xA8)
 
+	if (dev->BoardLock)	// Worker Task Running?
+		goto Skip;
 
+	spin_lock_irqsave(&io_request_lock, flags);	// STOP _que function
 
-// runs every 1 second for FC exchange timeouts and implicit FC device logouts
-
-void cpqfcTSheartbeat( unsigned long ptr )
-{
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)ptr;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts; 
-  ULONG i;
-  unsigned long flags;
-  DECLARE_MUTEX_LOCKED(BoardLock);
-  
-  PCI_TRACE( 0xA8)
-
-  if( cpqfcHBAdata->BoardLock) // Worker Task Running?
-    goto Skip;
-
-  spin_lock_irqsave( &io_request_lock, flags); // STOP _que function
-
-  PCI_TRACE( 0xA8)
-
-
-  cpqfcHBAdata->BoardLock = &BoardLock; // stop Linux SCSI command queuing
-  
-  // release the IO lock (and re-enable interrupts)
-  spin_unlock_irqrestore( &io_request_lock, flags);
-  
-  // Ensure no contention from  _quecommand or Worker process 
-  CPQ_SPINLOCK_HBA( cpqfcHBAdata)
-  
-  PCI_TRACE( 0xA8)
-  
-
-  disable_irq( cpqfcHBAdata->HostAdapter->irq);  // our IRQ
-
-  // Complete the "bad target" commands (normally only used during
-  // initialization, since we aren't supposed to call "scsi_done"
-  // inside the queuecommand() function).  (this is overly contorted,
-  // scsi_done can be safely called from queuecommand for
-  // this bad target case.  May want to simplify this later)
+	PCI_TRACE(0xA8)
 
-  for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
-  {
-    if( cpqfcHBAdata->BadTargetCmnd[i] )
-    {
-      Scsi_Cmnd *Cmnd = cpqfcHBAdata->BadTargetCmnd[i];
-      cpqfcHBAdata->BadTargetCmnd[i] = NULL;
-      Cmnd->result = (DID_BAD_TARGET << 16);
-      call_scsi_done(Cmnd);
-    }
-    else
-      break;
-  }
+	dev->BoardLock = &BoardLock;	// stop Linux SCSI command queuing
 
-  
-  // logged in ports -- re-login check (ports required to verify login with
-  // PDISC after LIP within 2 secs)
-
-  // prevent contention
-  while( pLoggedInPort ) // for all ports which are expecting
-                         // PDISC after the next LIP, check to see if
-                         // time is up!
-  {
-      // Important: we only detect "timeout" condition on TRANSITION
-      // from non-zero to zero
-    if( pLoggedInPort->LOGO_timer )  // time-out "armed"?
-    {
-      if( !(--pLoggedInPort->LOGO_timer) ) // DEC from 1 to 0?
-      {
-          // LOGOUT time!  Per PLDA, PDISC hasn't complete in 2 secs, so
-          // issue LOGO request and destroy all I/O with other FC port(s).
-        
-/*          
-        printk(" ~cpqfcTS heartbeat: LOGOut!~ ");
-        printk("Linux SCSI Chanl/Target %d/%d (port_id %06Xh) WWN %08X%08X\n", 
-        pLoggedInPort->ScsiNexus.channel, 
-        pLoggedInPort->ScsiNexus.target, 
-	pLoggedInPort->port_id,
-          (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF), 
-          (ULONG)(pLoggedInPort->u.liWWN>>32));
+	// release the IO lock (and re-enable interrupts)
+	spin_unlock_irqrestore(&io_request_lock, flags);
 
-*/
-        cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);
+	// Ensure no contention from  _quecommand or Worker process 
+	CPQ_SPINLOCK_HBA(dev)
 
-      }
-      // else simply decremented - maybe next time...
-    }
-    pLoggedInPort = pLoggedInPort->pNextPort;
-  }
+	PCI_TRACE(0xA8)
 
+	disable_irq(dev->HostAdapter->irq);	// our IRQ
 
+	// Complete the "bad target" commands (normally only used during
+	// initialization, since we aren't supposed to call "scsi_done"
+	// inside the queuecommand() function).  (this is overly contorted,
+	// scsi_done can be safely called from queuecommand for
+	// this bad target case.  May want to simplify this later)
 
-  
-  
-  // ************  FC EXCHANGE TIMEOUT CHECK **************
-  
-  for( i=0; i< TACH_MAX_XID; i++)
-  {
-    if( Exchanges->fcExchange[i].type )  // exchange defined?
-    {
+	for (i = 0; i < CPQFCTS_MAX_TARGET_ID; i++) {
+		if (dev->BadTargetCmnd[i]) {
+			Scsi_Cmnd *Cmnd = dev->BadTargetCmnd[i];
+			dev->BadTargetCmnd[i] = NULL;
+			Cmnd->result = (DID_BAD_TARGET << 16);
+			call_scsi_done(Cmnd);
+		} else
+			break;
+	}
 
-      if( !Exchanges->fcExchange[i].timeOut ) // time expired
-      {
-        // Set Exchange timeout status
-        Exchanges->fcExchange[i].status |= FC2_TIMEOUT;
-
-        if( i >= TACH_SEST_LEN ) // Link Service Exchange
-        {
-          cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, i);  // Don't "abort" LinkService
-        }
-        
-        else  // SEST Exchange TO -- may post ABTS to Worker Thread Que
-        {
-	  // (Make sure we don't keep timing it out; let other functions
-	  // complete it or set the timeOut as needed)
-	  Exchanges->fcExchange[i].timeOut = 30000; // seconds default
-
-          if( Exchanges->fcExchange[i].type 
-                  & 
-              (BLS_ABTS | BLS_ABTS_ACC )  )
-          {
-	    // For BLS_ABTS*, an upper level might still have
-	    // an outstanding command waiting for low-level completion.
-	    // Also, in the case of a WRITE, we MUST get confirmation
-	    // of either ABTS ACC or RJT before re-using the Exchange.
-	    // It's possible that the RAID cache algorithm can hang
-	    // if we fail to complete a WRITE to a LBA, when a READ
-	    // comes later to that same LBA.  Therefore, we must
-	    // ensure that the target verifies receipt of ABTS for
-	    // the exchange
-	   
-	    printk("~TO Q'd ABTS (x_ID %Xh)~ ", i); 
-//            TriggerHBA( fcChip->Registers.ReMapMemBase);
-
-	    // On timeout of a ABTS exchange, check to
-	    // see if the FC device has a current valid login.
-	    // If so, restart it.
-	    pLoggedInPort = fcFindLoggedInPort( fcChip,
-              Exchanges->fcExchange[i].Cmnd, // find Scsi Nexus
-              0,        // DON'T search linked list for FC port id
-	      NULL,     // DON'T search linked list for FC WWN
-              NULL);    // DON'T care about end of list
-
-	    // device exists?
-	    if( pLoggedInPort ) // device exists?
-	    {
-	      if( pLoggedInPort->prli ) // logged in for FCP-SCSI?
-	      {
-		// attempt to restart the ABTS
-		printk(" ~restarting ABTS~ ");
-                cpqfcTSStartExchange( cpqfcHBAdata, i );
-
-	      }
-	    }
-          }
-	  else  // not an ABTS
-	  { 
-           
-            // We expect the WorkerThread to change the xchng type to
-            // abort and set appropriate timeout.
-            cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i ); // timed-out
-	  }
-        }
-      }
-      else  // time not expired...
-      {
-        // decrement timeout: 1 or more seconds left
-        --Exchanges->fcExchange[i].timeOut;
-      }
-    }
-  }
 
+	// logged in ports -- re-login check (ports required to verify login with
+	// PDISC after LIP within 2 secs)
 
-  enable_irq( cpqfcHBAdata->HostAdapter->irq);
- 
+	// prevent contention
+	while (pLoggedInPort)	// for all ports which are expecting
+				// PDISC after the next LIP, check to see if
+				// time is up!
+	{
+		// Important: we only detect "timeout" condition on TRANSITION
+		// from non-zero to zero
+		if (pLoggedInPort->LOGO_timer)	// time-out "armed"?
+		{
+			if (!(--pLoggedInPort->LOGO_timer))	// DEC from 1 to 0?
+			{
+				// LOGOUT time!  Per PLDA, PDISC hasn't complete in 2 secs, so
+				// issue LOGO request and destroy all I/O with other FC port(s).
 
-  CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
+/*          
+			        printk(" ~cpqfcTS heartbeat: LOGOut!~ ");
+        			printk("Linux SCSI Chanl/Target %d/%d (port_id %06Xh) WWN %08X%08X\n", 
+				        pLoggedInPort->ScsiNexus.channel, 
+				        pLoggedInPort->ScsiNexus.target, 
+					pLoggedInPort->port_id,
+				        (u32)(pLoggedInPort->u.liWWN &0xFFFFFFFF), 
+				        (u32)(pLoggedInPort->u.liWWN>>32));
+*/
+				cpqfcTSImplicitLogout(dev, pLoggedInPort);
 
-  cpqfcHBAdata->BoardLock = NULL; // Linux SCSI commands may be queued
+			}
+			// else simply decremented - maybe next time...
+		}
+		pLoggedInPort = pLoggedInPort->pNextPort;
+	}
 
-  // Now, complete any Cmnd we Q'd up while BoardLock was held
+	// ************  FC EXCHANGE TIMEOUT CHECK **************
 
-  CompleteBoardLockCmnd( cpqfcHBAdata);
- 
+	for (i = 0; i < TACH_MAX_XID; i++) {
+		if (Exchanges->fcExchange[i].type)	// exchange defined?
+		{
+
+			if (!Exchanges->fcExchange[i].timeOut)	// time expired
+			{
+				// Set Exchange timeout status
+				Exchanges->fcExchange[i].status |= FC2_TIMEOUT;
+
+				if (i >= TACH_SEST_LEN)	// Link Service Exchange
+				{
+					cpqfcTSCompleteExchange(dev->PciDev, fcChip, i);	// Don't "abort" LinkService
+				}
+				else	// SEST Exchange TO -- may post ABTS to Worker Thread Que
+				{
+					// (Make sure we don't keep timing it out; let other functions
+					// complete it or set the timeOut as needed)
+					Exchanges->fcExchange[i].timeOut = 30000;	// seconds default
+
+					if (Exchanges->fcExchange[i].type & (BLS_ABTS | BLS_ABTS_ACC)) {
+						// For BLS_ABTS*, an upper level might still have
+						// an outstanding command waiting for low-level completion.
+						// Also, in the case of a WRITE, we MUST get confirmation
+						// of either ABTS ACC or RJT before re-using the Exchange.
+						// It's possible that the RAID cache algorithm can hang
+						// if we fail to complete a WRITE to a LBA, when a READ
+						// comes later to that same LBA.  Therefore, we must
+						// ensure that the target verifies receipt of ABTS for
+						// the exchange
+
+						printk("~TO Q'd ABTS (x_ID %Xh)~ ", i);
+//						TriggerHBA( fcChip->Registers.ReMapMemBase);
+
+						// On timeout of a ABTS exchange, check to
+						// see if the FC device has a current valid login.
+						// If so, restart it.
+						pLoggedInPort = fcFindLoggedInPort(fcChip, Exchanges->fcExchange[i].Cmnd,	// find Scsi Nexus
+										   0,	// DON'T search linked list for FC port id
+										   NULL,	// DON'T search linked list for FC WWN
+										   NULL);	// DON'T care about end of list
+						// device exists?
+						if (pLoggedInPort)	// device exists?
+						{
+							if (pLoggedInPort->prli)	// logged in for FCP-SCSI?
+							{
+								// attempt to restart the ABTS
+								printk(" ~restarting ABTS~ ");
+								cpqfcTSStartExchange(dev, i);
+
+							}
+						}
+					} else	// not an ABTS
+					{
+
+						// We expect the WorkerThread to change the xchng type to
+						// abort and set appropriate timeout.
+						cpqfcTSPutLinkQue(dev, BLS_ABTS, &i);	// timed-out
+					}
+				}
+			} else	// time not expired...
+			{
+				// decrement timeout: 1 or more seconds left
+				--Exchanges->fcExchange[i].timeOut;
+			}
+		}
+	}
 
-  // restart the timer to run again (1 sec later)
+	enable_irq(dev->HostAdapter->irq);
+	CPQ_SPINUNLOCK_HBA(dev)
+	dev->BoardLock = NULL;	// Linux SCSI commands may be queued
+	// Now, complete any Cmnd we Q'd up while BoardLock was held
+	CompleteBoardLockCmnd(dev);
+	// restart the timer to run again (1 sec later)
 Skip:
-  mod_timer( &cpqfcHBAdata->cpqfcTStimer, jiffies + HZ);
-  
-  PCI_TRACEO( i, 0xA8)
-  return;
+	mod_timer(&dev->cpqfcTStimer, jiffies + HZ);
+	PCI_TRACEO(i, 0xA8)
+	return;
 }
 
 
 // put valid FC-AL physical address in spec order
-static const UCHAR valid_al_pa[]={
-    0xef, 0xe8, 0xe4, 0xe2, 
-    0xe1, 0xE0, 0xDC, 0xDA, 
-    0xD9, 0xD6, 0xD5, 0xD4, 
-    0xD3, 0xD2, 0xD1, 0xCe, 
-    0xCd, 0xCc, 0xCb, 0xCa, 
-    0xC9, 0xC7, 0xC6, 0xC5, 
-    0xC3, 0xBc, 0xBa, 0xB9,
-    0xB6, 0xB5, 0xB4, 0xB3, 
-    0xB2, 0xB1, 0xae, 0xad,
-    0xAc, 0xAb, 0xAa, 0xA9, 
-
-    0xA7, 0xA6, 0xA5, 0xA3, 
-    0x9f, 0x9e, 0x9d, 0x9b, 
-    0x98, 0x97, 0x90, 0x8f, 
-    0x88, 0x84, 0x82, 0x81, 
-    0x80, 0x7c, 0x7a, 0x79, 
-    0x76, 0x75, 0x74, 0x73, 
-    0x72, 0x71, 0x6e, 0x6d, 
-    0x6c, 0x6b, 0x6a, 0x69, 
-    0x67, 0x66, 0x65, 0x63, 
-    0x5c, 0x5a, 0x59, 0x56, 
-    
-    0x55, 0x54, 0x53, 0x52, 
-    0x51, 0x4e, 0x4d, 0x4c, 
-    0x4b, 0x4a, 0x49, 0x47, 
-    0x46, 0x45, 0x43, 0x3c,
-    0x3a, 0x39, 0x36, 0x35, 
-    0x34, 0x33, 0x32, 0x31, 
-    0x2e, 0x2d, 0x2c, 0x2b, 
-    0x2a, 0x29, 0x27, 0x26, 
-    0x25, 0x23, 0x1f, 0x1E,
-    0x1d, 0x1b, 0x18, 0x17, 
-
-    0x10, 0x0f, 8, 4, 2, 1 }; // ALPA 0 (Fabric) is special case
-
-const int number_of_al_pa = (sizeof(valid_al_pa) );
+static const u8 valid_al_pa[] = {
+	0xef, 0xe8, 0xe4, 0xe2,
+	0xe1, 0xE0, 0xDC, 0xDA,
+	0xD9, 0xD6, 0xD5, 0xD4,
+	0xD3, 0xD2, 0xD1, 0xCe,
+	0xCd, 0xCc, 0xCb, 0xCa,
+	0xC9, 0xC7, 0xC6, 0xC5,
+	0xC3, 0xBc, 0xBa, 0xB9,
+	0xB6, 0xB5, 0xB4, 0xB3,
+	0xB2, 0xB1, 0xae, 0xad,
+	0xAc, 0xAb, 0xAa, 0xA9,
+
+	0xA7, 0xA6, 0xA5, 0xA3,
+	0x9f, 0x9e, 0x9d, 0x9b,
+	0x98, 0x97, 0x90, 0x8f,
+	0x88, 0x84, 0x82, 0x81,
+	0x80, 0x7c, 0x7a, 0x79,
+	0x76, 0x75, 0x74, 0x73,
+	0x72, 0x71, 0x6e, 0x6d,
+	0x6c, 0x6b, 0x6a, 0x69,
+	0x67, 0x66, 0x65, 0x63,
+	0x5c, 0x5a, 0x59, 0x56,
+
+	0x55, 0x54, 0x53, 0x52,
+	0x51, 0x4e, 0x4d, 0x4c,
+	0x4b, 0x4a, 0x49, 0x47,
+	0x46, 0x45, 0x43, 0x3c,
+	0x3a, 0x39, 0x36, 0x35,
+	0x34, 0x33, 0x32, 0x31,
+	0x2e, 0x2d, 0x2c, 0x2b,
+	0x2a, 0x29, 0x27, 0x26,
+	0x25, 0x23, 0x1f, 0x1E,
+	0x1d, 0x1b, 0x18, 0x17,
 
+	0x10, 0x0f, 8, 4, 2, 1
+};				// ALPA 0 (Fabric) is special case
 
+const int number_of_al_pa = (sizeof(valid_al_pa));
 
 // this function looks up an al_pa from the table of valid al_pa's
 // we decrement from the last decimal loop ID, because soft al_pa
@@ -3306,16 +2613,16 @@
 //  -1      - invalid al_pa (not all 8 bit values are legal)
 
 #if (0)
-static int GetLoopID( ULONG al_pa )
+static int GetLoopID(u32 al_pa)
 {
-  int i;
+	int i;
 
-  for( i = number_of_al_pa -1; i >= 0; i--)  // dec.
-  {
-    if( valid_al_pa[i] == (UCHAR)al_pa )  // take lowest 8 bits
-      return i;  // success - found valid al_pa; return decimal LoopID
-  }
-  return -1; // failed - not found
+	for (i = number_of_al_pa - 1; i >= 0; i--)	// dec.
+	{
+		if (valid_al_pa[i] == (u8) al_pa)	// take lowest 8 bits
+			return i;	// success - found valid al_pa; return decimal LoopID
+	}
+	return -1;		// failed - not found
 }
 #endif
 
@@ -3330,739 +2637,620 @@
 //     (NULL if not found)
 //   pLastLoggedInPort - ptr to last struct (for adding new ones)
 // 
-PFC_LOGGEDIN_PORT  fcFindLoggedInPort( 
-  PTACHYON fcChip, 
-  Scsi_Cmnd *Cmnd, // search linked list for Scsi Nexus (channel/target/lun)
-  ULONG port_id,   // search linked list for al_pa, or
-  UCHAR wwn[8],    // search linked list for WWN, or...
-  PFC_LOGGEDIN_PORT *pLastLoggedInPort )
-             
-{
-  PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts; 
-  BOOLEAN target_id_valid=FALSE;
-  BOOLEAN port_id_valid=FALSE;
-  BOOLEAN wwn_valid=FALSE;
-  int i;
-
-
-  if( Cmnd != NULL )
-    target_id_valid = TRUE;
-  
-  else if( port_id ) // note! 24-bit NULL address is illegal
-    port_id_valid = TRUE;
+PFC_LOGGEDIN_PORT fcFindLoggedInPort(PTACHYON fcChip, Scsi_Cmnd * Cmnd,	// search linked list for Scsi Nexus (channel/target/lun)
+				     u32 port_id,	// search linked list for al_pa, or
+				     u8 wwn[8],	// search linked list for WWN, or...
+				     PFC_LOGGEDIN_PORT * pLastLoggedInPort)
+{
+	PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
+	u8 target_id_valid = 0;
+	u8 port_id_valid = 0;
+	u8 wwn_valid = 0;
+	int i;
+
+
+	if (Cmnd != NULL)
+		target_id_valid = 1;
+
+	else if (port_id)	// note! 24-bit NULL address is illegal
+		port_id_valid = 1;
+
+	else {
+		if (wwn)	// non-null arg? (OK to pass NULL when not searching WWN)
+		{
+			for (i = 0; i < 8; i++)	// valid WWN passed?  NULL WWN invalid
+			{
+				if (wwn[i] != 0)
+					wwn_valid = 1;	// any non-zero byte makes (presumably) valid
+			}
+		}
+	}
+	// check other options ...
 
-  else
-  {
-    if( wwn ) // non-null arg? (OK to pass NULL when not searching WWN)
-    {
-      for( i=0; i<8; i++)  // valid WWN passed?  NULL WWN invalid
-      {
-        if( wwn[i] != 0 )
-          wwn_valid = TRUE;  // any non-zero byte makes (presumably) valid
-      }
-    }
-  }
-                // check other options ...
 
+	// In case multiple search options are given, we use a priority
+	// scheme:
+	// While valid pLoggedIn Ptr
+	//   If port_id is valid
+	//     if port_id matches, return Ptr
+	//   If wwn is valid
+	//     if wwn matches, return Ptr
+	//   Next Ptr in list
+	//
+	// Return NULL (not found)
 
-  // In case multiple search options are given, we use a priority
-  // scheme:
-  // While valid pLoggedIn Ptr
-  //   If port_id is valid
-  //     if port_id matches, return Ptr
-  //   If wwn is valid
-  //     if wwn matches, return Ptr
-  //   Next Ptr in list
-  //
-  // Return NULL (not found)
- 
-      
-  while( pLoggedInPort ) // NULL marks end of list (1st ptr always valid)
-  {
-    if( pLastLoggedInPort ) // caller's pointer valid?
-      *pLastLoggedInPort = pLoggedInPort;  // end of linked list
-    
-    if( target_id_valid )
-    {
-      // check Linux Scsi Cmnd for channel/target Nexus match
-      // (all luns are accessed through matching "pLoggedInPort")
-      if( (pLoggedInPort->ScsiNexus.target == Cmnd->target)
-                &&
-          (pLoggedInPort->ScsiNexus.channel == Cmnd->channel))
-      {
-        // For "passthru" modes, the IOCTL caller is responsible
-	// for setting the FCP-LUN addressing
-	if( !Cmnd->SCp.sent_command ) // NOT passthru?
+
+	while (pLoggedInPort)	// NULL marks end of list (1st ptr always valid)
 	{
-	
-          // set the FCP-LUN addressing type
-          Cmnd->SCp.phase = pLoggedInPort->ScsiNexus.VolumeSetAddressing;	
-
-          // set the Device Type we got from the snooped INQUIRY string
-	  Cmnd->SCp.Message = pLoggedInPort->ScsiNexus.InqDeviceType;
-
-	  // handle LUN masking; if not "default" (illegal) lun value,
-	  // the use it.  These lun values are set by a successful
-	  // Report Luns command
-          if( pLoggedInPort->ScsiNexus.LunMasking == 1) 
-	  {
-            // we KNOW all the valid LUNs... 0xFF is invalid!
-            Cmnd->SCp.have_data_in = pLoggedInPort->ScsiNexus.lun[Cmnd->lun];
-	    if (pLoggedInPort->ScsiNexus.lun[Cmnd->lun] == 0xFF)
-		return NULL;
-	    // printk("xlating lun %d to 0x%02x\n", Cmnd->lun, 
-            //	pLoggedInPort->ScsiNexus.lun[Cmnd->lun]);
-	  }
-	  else
-	    Cmnd->SCp.have_data_in = Cmnd->lun; // Linux & target luns match
-	}
-	break; // found it!
-      }
-    }
-    
-    if( port_id_valid ) // look for alpa first
-    {
-      if( pLoggedInPort->port_id == port_id )
-          break;  // found it!
-    }
-    if( wwn_valid ) // look for wwn second
-    {
+		if (pLastLoggedInPort)	// caller's pointer valid?
+			*pLastLoggedInPort = pLoggedInPort;	// end of linked list
 
-      if( !memcmp( &pLoggedInPort->u.ucWWN[0], &wwn[0], 8))
-      {  
-                 // all 8 bytes of WWN match
-        break;   // found it!
-      }
-    }
-                
-    pLoggedInPort = pLoggedInPort->pNextPort; // try next port
-  }
+		if (target_id_valid) {
+			// check Linux Scsi Cmnd for channel/target Nexus match
+			// (all luns are accessed through matching "pLoggedInPort")
+			if ((pLoggedInPort->ScsiNexus.target == Cmnd->target)
+			    && (pLoggedInPort->ScsiNexus.channel == Cmnd->channel)) {
+				// For "passthru" modes, the IOCTL caller is responsible
+				// for setting the FCP-LUN addressing
+				if (!Cmnd->SCp.sent_command)	// NOT passthru?
+				{
+
+					// set the FCP-LUN addressing type
+					Cmnd->SCp.phase = pLoggedInPort->ScsiNexus.VolumeSetAddressing;
+
+					// set the Device Type we got from the snooped INQUIRY string
+					Cmnd->SCp.Message = pLoggedInPort->ScsiNexus.InqDeviceType;
+
+					// handle LUN masking; if not "default" (illegal) lun value,
+					// the use it.  These lun values are set by a successful
+					// Report Luns command
+					if (pLoggedInPort->ScsiNexus.LunMasking == 1) {
+						// we KNOW all the valid LUNs... 0xFF is invalid!
+						if (Cmnd->lun > sizeof(pLoggedInPort->ScsiNexus.lun)){
+							// printk("cpqfcTS FATAL: Invalid LUN index !!!!\n ");
+							return NULL;
+						}
+						Cmnd->SCp.have_data_in = pLoggedInPort->ScsiNexus.lun[Cmnd->lun];
+						if (pLoggedInPort->ScsiNexus.lun[Cmnd->lun] == 0xFF)
+							return NULL;
+						// printk("xlating lun %d to 0x%02x\n", Cmnd->lun, 
+						//  pLoggedInPort->ScsiNexus.lun[Cmnd->lun]);
+					} else
+						Cmnd->SCp.have_data_in = Cmnd->lun;	// Linux & target luns match
+				}
+				break;	// found it!
+			}
+		}
 
-  return pLoggedInPort;
-}
+		if (port_id_valid)	// look for alpa first
+		{
+			if (pLoggedInPort->port_id == port_id)
+				break;	// found it!
+		}
+		if (wwn_valid)	// look for wwn second
+		{
 
+			if (!memcmp(&pLoggedInPort->u.ucWWN[0], &wwn[0], 8)) {
+				// all 8 bytes of WWN match
+				break;	// found it!
+			}
+		}
 
+		pLoggedInPort = pLoggedInPort->pNextPort;	// try next port
+	}
 
+	return pLoggedInPort;
+}
 
 // 
 // We need to examine the SEST table and re-validate
 // any open Exchanges for this LoggedInPort
 // To make Tachyon pay attention, Freeze FCP assists,
 // set VAL bits, Unfreeze FCP assists
-static void RevalidateSEST( struct Scsi_Host *HostAdapter, 
-		        PFC_LOGGEDIN_PORT pLoggedInPort)
+static void RevalidateSEST(struct Scsi_Host *shpnt, PFC_LOGGEDIN_PORT pLoggedInPort)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG x_ID;
-  BOOLEAN TachFroze = FALSE;
-  
-  
-  // re-validate any SEST exchanges that are permitted
-  // to survive the link down (e.g., good PDISC performed)
-  for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
-  {
-
-    // If the SEST entry port_id matches the pLoggedInPort,
-    // we need to re-validate
-    if( (Exchanges->fcExchange[ x_ID].type == SCSI_IRE)
-         || 
-	(Exchanges->fcExchange[ x_ID].type == SCSI_IWE))
-    {
-		     
-      if( (Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF)  // (24-bit port ID)
-            == pLoggedInPort->port_id) 
-      {
-//	printk(" re-val xID %Xh ", x_ID);
-        if( !TachFroze )  // freeze if not already frozen
-          TachFroze |= FreezeTach( cpqfcHBAdata);
-        fcChip->SEST->u[ x_ID].IWE.Hdr_Len |= 0x80000000; // set VAL bit
-      }
-    } 
-  }
-
-  if( TachFroze) 
-  { 
-    fcChip->UnFreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
-  }
-} 
+	CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 x_ID;
+	u8 TachFroze = 0;
+
+
+	// re-validate any SEST exchanges that are permitted
+	// to survive the link down (e.g., good PDISC performed)
+	for (x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) {
+
+		// If the SEST entry port_id matches the pLoggedInPort,
+		// we need to re-validate
+		if ((Exchanges->fcExchange[x_ID].type == SCSI_IRE)
+		    || (Exchanges->fcExchange[x_ID].type == SCSI_IWE)) {
+			if ((Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF) == pLoggedInPort->port_id) 	// (24-bit port ID)
+			{
+//				printk(" re-val xID %Xh ", x_ID);
+				if (!TachFroze)	// freeze if not already frozen
+					TachFroze |= FreezeTach(dev);
+				fcChip->SEST->u[x_ID].IWE.Hdr_Len |= 0x80000000;	// set VAL bit
+			}
+		}
+	}
+	if (TachFroze) {
+		fcChip->UnFreezeTachyon(fcChip, 2);	// both ERQ and FCP assists
+	}
+}
 
 
 // Complete an Linux Cmnds that we Queued because
 // our FC link was down (cause immediate retry)
 
-static void UnblockScsiDevice( struct Scsi_Host *HostAdapter, 
-		        PFC_LOGGEDIN_PORT pLoggedInPort)
+static void UnblockScsiDevice(struct Scsi_Host *shpnt, PFC_LOGGEDIN_PORT pLoggedInPort)
 {
-//  Scsi_Device *sdev = HostAdapter->host_queue;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  Scsi_Cmnd* *SCptr = &cpqfcHBAdata->LinkDnCmnd[0];
-  Scsi_Cmnd *Cmnd;
-  int indx;
-
- 
-  
-  // if the device was previously "blocked", make sure
-  // we unblock it so Linux SCSI will resume
-
-  pLoggedInPort->device_blocked = FALSE; // clear our flag
-
-  // check the Link Down command ptr buffer;
-  // we can complete now causing immediate retry
-  for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++, SCptr++)
-  {
-    if( *SCptr != NULL ) // scsi command to complete?
-    {
+//  Scsi_Device *sdev = shpnt->host_queue;
+	CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
+	Scsi_Cmnd **SCptr = &dev->LinkDnCmnd[0];
+	Scsi_Cmnd *Cmnd;
+	int indx;
+
+	// if the device was previously "blocked", make sure
+	// we unblock it so Linux SCSI will resume
+
+	pLoggedInPort->device_blocked = 0;	// clear our flag
+
+	// check the Link Down command ptr buffer;
+	// we can complete now causing immediate retry
+	for (indx = 0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++, SCptr++) {
+		if (*SCptr != NULL)	// scsi command to complete?
+		{
 #ifdef DUMMYCMND_DBG
-      printk("complete Cmnd %p in LinkDnCmnd[%d]\n", *SCptr,indx);
+			printk("complete Cmnd %p in LinkDnCmnd[%d]\n", *SCptr, indx);
 #endif
-      Cmnd = *SCptr;
-
+			Cmnd = *SCptr;
 
-      // Are there any Q'd commands for this target?
-      if( (Cmnd->target == pLoggedInPort->ScsiNexus.target)
-	       &&
-          (Cmnd->channel == pLoggedInPort->ScsiNexus.channel) )
-      {
-        Cmnd->result = (DID_SOFT_ERROR <<16); // force retry
-        if( Cmnd->scsi_done == NULL) 
-	{
-          printk("LinkDnCmnd scsi_done ptr null, port_id %Xh\n",
-		  pLoggedInPort->port_id);
-	  Cmnd->SCp.sent_command = 0;
+			// Are there any Q'd commands for this target?
+			if ((Cmnd->target == pLoggedInPort->ScsiNexus.target)
+			    && (Cmnd->channel == pLoggedInPort->ScsiNexus.channel)) {
+				Cmnd->result = (DID_SOFT_ERROR << 16);	// force retry
+				if (Cmnd->scsi_done == NULL) {
+					printk("LinkDnCmnd scsi_done ptr null, port_id %Xh\n", pLoggedInPort->port_id);
+					Cmnd->SCp.sent_command = 0;
+				} else
+					call_scsi_done(Cmnd);
+				*SCptr = NULL;	// free this slot for next use
+			}
+		}
 	}
-	else
-	  call_scsi_done(Cmnd);
-        *SCptr = NULL;  // free this slot for next use
-      }
-    }
-  }
 }
 
-  
+
 //#define WWN_DBG 1
 
-static void SetLoginFields(
-  PFC_LOGGEDIN_PORT pLoggedInPort,
-  TachFCHDR_GCMND* fchs,
-  BOOLEAN PDisc,
-  BOOLEAN Originator)
-{
-  LOGIN_PAYLOAD logi;       // FC-PH Port Login
-  PRLI_REQUEST prli;  // copy for BIG ENDIAN switch
-  int i;
+static void SetLoginFields(PFC_LOGGEDIN_PORT pLoggedInPort, TachFCHDR_GCMND * fchs, u8 PDisc, u8 Originator)
+{
+	LOGIN_PAYLOAD logi;	// FC-PH Port Login
+	PRLI_REQUEST prli;	// copy for BIG ENDIAN switch
+	int i;
 #ifdef WWN_DBG
-  ULONG ulBuff;
+	u32 ulBuff;
 #endif
 
-  BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
+	BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
 
-  pLoggedInPort->Originator = Originator;
-  pLoggedInPort->port_id = fchs->s_id & 0xFFFFFF;
-  
-  switch( fchs->pl[0] & 0xffff )
-  {
-  case 0x00000002:  //  PLOGI or PDISC ACCept?
-    if( PDisc )     // PDISC accept
-      goto PDISC_case;
-
-  case 0x00000003:  //  ELS_PLOGI or ELS_PLOGI_ACC
-
-  // Login BB_credit typically 0 for Tachyons
-    pLoggedInPort->BB_credit = logi.cmn_services.bb_credit;
-
-    // e.g. 128, 256, 1024, 2048 per FC-PH spec
-    // We have to use this when setting up SEST Writes,
-    // since that determines frame size we send.
-    pLoggedInPort->rx_data_size = logi.class3.rx_data_size;
-    pLoggedInPort->plogi = TRUE;
-    pLoggedInPort->pdisc = FALSE;
-    pLoggedInPort->prli = FALSE;    // ELS_PLOGI resets
-    pLoggedInPort->flogi = FALSE;   // ELS_PLOGI resets
-    pLoggedInPort->logo = FALSE;    // ELS_PLOGI resets
-    pLoggedInPort->LOGO_counter = 0;// ELS_PLOGI resets
-    pLoggedInPort->LOGO_timer = 0;// ELS_PLOGI resets
-
-    // was this PLOGI to a Fabric?
-    if( pLoggedInPort->port_id == 0xFFFFFC ) // well know address
-      pLoggedInPort->flogi = TRUE;
+	pLoggedInPort->Originator = Originator;
+	pLoggedInPort->port_id = fchs->s_id & 0xFFFFFF;
+
+	switch (fchs->pl[0] & 0xffff) {
+	case 0x00000002:	//  PLOGI or PDISC ACCept?
+		if (PDisc)	// PDISC accept
+			goto PDISC_case;
+
+	case 0x00000003:	//  ELS_PLOGI or ELS_PLOGI_ACC
+
+		// Login BB_credit typically 0 for Tachyons
+		pLoggedInPort->BB_credit = logi.cmn_services.bb_credit;
+
+		// e.g. 128, 256, 1024, 2048 per FC-PH spec
+		// We have to use this when setting up SEST Writes,
+		// since that determines frame size we send.
+		pLoggedInPort->rx_data_size = logi.class3.rx_data_size;
+		pLoggedInPort->plogi = 1;
+		pLoggedInPort->pdisc = 0;
+		pLoggedInPort->prli = 0;	// ELS_PLOGI resets
+		pLoggedInPort->flogi = 0;	// ELS_PLOGI resets
+		pLoggedInPort->logo = 0;	// ELS_PLOGI resets
+		pLoggedInPort->LOGO_counter = 0;	// ELS_PLOGI resets
+		pLoggedInPort->LOGO_timer = 0;	// ELS_PLOGI resets
+
+		// was this PLOGI to a Fabric?
+		if (pLoggedInPort->port_id == 0xFFFFFC)	// well know address
+			pLoggedInPort->flogi = 1;
 
 
-    for( i=0; i<8; i++)   // copy the LOGIN port's WWN
-      pLoggedInPort->u.ucWWN[i] = logi.port_name[i];  
+		for (i = 0; i < 8; i++)	// copy the LOGIN port's WWN
+			pLoggedInPort->u.ucWWN[i] = logi.port_name[i];
 
 #ifdef WWN_DBG
-    ulBuff = (ULONG)pLoggedInPort->u.liWWN;
-    if( pLoggedInPort->Originator)
-      printk("o");
-    else
-      printk("r");
-    printk("PLOGI port_id %Xh, WWN %08X",
-      pLoggedInPort->port_id, ulBuff);
+		ulBuff = (u32) pLoggedInPort->u.liWWN;
+		if (pLoggedInPort->Originator)
+			printk("o");
+		else
+			printk("r");
+		printk("PLOGI port_id %Xh, WWN %08X", pLoggedInPort->port_id, ulBuff);
 
-    ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
-    printk("%08Xh fcPort %p\n", ulBuff, pLoggedInPort);
+		ulBuff = (u32) (pLoggedInPort->u.liWWN >> 32);
+		printk("%08Xh fcPort %p\n", ulBuff, pLoggedInPort);
 #endif
-    break;
-
-
-
-  
-  case 0x00000005:  //  ELS_LOGO (logout)
-
+		break;
 
-    pLoggedInPort->plogi = FALSE;
-    pLoggedInPort->pdisc = FALSE;
-    pLoggedInPort->prli = FALSE;   // ELS_PLOGI resets
-    pLoggedInPort->flogi = FALSE;  // ELS_PLOGI resets
-    pLoggedInPort->logo = TRUE;    // ELS_PLOGI resets
-    pLoggedInPort->LOGO_counter++; // ELS_PLOGI resets
-    pLoggedInPort->LOGO_timer = 0;
+	case 0x00000005:	//  ELS_LOGO (logout)
+		pLoggedInPort->plogi = 0;
+		pLoggedInPort->pdisc = 0;
+		pLoggedInPort->prli = 0;	// ELS_PLOGI resets
+		pLoggedInPort->flogi = 0;	// ELS_PLOGI resets
+		pLoggedInPort->logo = 1;	// ELS_PLOGI resets
+		pLoggedInPort->LOGO_counter++;	// ELS_PLOGI resets
+		pLoggedInPort->LOGO_timer = 0;
 #ifdef WWN_DBG
-    ulBuff = (ULONG)pLoggedInPort->u.liWWN;
-    if( pLoggedInPort->Originator)
-      printk("o");
-    else
-      printk("r");
-    printk("LOGO port_id %Xh, WWN %08X",
-      pLoggedInPort->port_id, ulBuff);
+		ulBuff = (u32) pLoggedInPort->u.liWWN;
+		if (pLoggedInPort->Originator)
+			printk("o");
+		else
+			printk("r");
+		printk("LOGO port_id %Xh, WWN %08X", pLoggedInPort->port_id, ulBuff);
 
-    ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
-    printk("%08Xh\n", ulBuff);
+		ulBuff = (u32) (pLoggedInPort->u.liWWN >> 32);
+		printk("%08Xh\n", ulBuff);
 #endif
-    break;
-
-
+		break;
 
-PDISC_case:
-  case 0x00000050: //  ELS_PDISC or ELS_PDISC_ACC
-    pLoggedInPort->LOGO_timer = 0;  // stop the time-out
-      
-    pLoggedInPort->prli = TRUE;     // ready to accept FCP-SCSI I/O
-    
+	PDISC_case:
+	case 0x00000050:	//  ELS_PDISC or ELS_PDISC_ACC
+		pLoggedInPort->LOGO_timer = 0;	// stop the time-out
 
-      
+		pLoggedInPort->prli = 1;	// ready to accept FCP-SCSI I/O
 #ifdef WWN_DBG
-    ulBuff = (ULONG)pLoggedInPort->u.liWWN;
-    if( pLoggedInPort->Originator)
-      printk("o");
-    else
-      printk("r");
-    printk("PDISC port_id %Xh, WWN %08X",
-      pLoggedInPort->port_id, ulBuff);
+		ulBuff = (u32) pLoggedInPort->u.liWWN;
+		if (pLoggedInPort->Originator)
+			printk("o");
+		else
+			printk("r");
+		printk("PDISC port_id %Xh, WWN %08X", pLoggedInPort->port_id, ulBuff);
 
-    ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
-    printk("%08Xh\n", ulBuff);
+		ulBuff = (u32) (pLoggedInPort->u.liWWN >> 32);
+		printk("%08Xh\n", ulBuff);
 #endif
+		break;
 
-
-    
-    break;
-
-
-    
-  case  0x1020L: //  PRLI?
-  case  0x1002L: //  PRLI ACCept?
-    BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli, sizeof(prli));
-
-    pLoggedInPort->fcp_info = prli.fcp_info; // target/initiator flags
-    pLoggedInPort->prli = TRUE;  // PLOGI resets, PDISC doesn't
-
-    pLoggedInPort->pdisc = TRUE;  // expect to send (or receive) PDISC
-                                  // next time
-    pLoggedInPort->LOGO_timer = 0;  // will be set next LinkDown
+	case 0x1020L:		//  PRLI?
+	case 0x1002L:		//  PRLI ACCept?
+		BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & prli, sizeof(prli));
+
+		pLoggedInPort->fcp_info = prli.fcp_info;	// target/initiator flags
+		pLoggedInPort->prli = 1;	// PLOGI resets, PDISC doesn't
+
+		pLoggedInPort->pdisc = 1;	// expect to send (or receive) PDISC
+		// next time
+		pLoggedInPort->LOGO_timer = 0;	// will be set next LinkDown
 #ifdef WWN_DBG
-    ulBuff = (ULONG)pLoggedInPort->u.liWWN;
-    if( pLoggedInPort->Originator)
-      printk("o");
-    else
-      printk("r");
-    printk("PRLI port_id %Xh, WWN %08X",
-      pLoggedInPort->port_id, ulBuff);
+		ulBuff = (u32) pLoggedInPort->u.liWWN;
+		if (pLoggedInPort->Originator)
+			printk("o");
+		else
+			printk("r");
+		printk("PRLI port_id %Xh, WWN %08X", pLoggedInPort->port_id, ulBuff);
 
-    ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
-      printk("%08Xh\n", ulBuff);
+		ulBuff = (u32) (pLoggedInPort->u.liWWN >> 32);
+		printk("%08Xh\n", ulBuff);
 #endif
-
-    break;
-
-  }
-
-  return;
+		break;
+	}
+	return;
 }
 
-
-
-
-
-
-static void BuildLinkServicePayload( PTACHYON fcChip, ULONG type, void* payload)
+static void BuildLinkServicePayload(PTACHYON fcChip, u32 type, void *payload)
 {
-  LOGIN_PAYLOAD *plogi;  // FC-PH Port Login
-  LOGIN_PAYLOAD PlogiPayload;   // copy for BIG ENDIAN switch
-  PRLI_REQUEST  *prli;          // FCP-SCSI Process Login
-  PRLI_REQUEST  PrliPayload;    // copy for BIG ENDIAN switch
-  LOGOUT_PAYLOAD  *logo;
-  LOGOUT_PAYLOAD  LogoutPayload;
-//  PRLO_REQUEST  *prlo;
-//  PRLO_REQUEST  PrloPayload;
-  REJECT_MESSAGE rjt, *prjt;
-
-  memset( &PlogiPayload, 0, sizeof( PlogiPayload));
-  plogi = &PlogiPayload;    // load into stack buffer,
-                                // then BIG-ENDIAN switch a copy to caller
-
-
-  switch( type )  // payload type can be ELS_PLOGI, ELS_PRLI, ADISC, ...
-  {
-    case ELS_FDISC:
-    case ELS_FLOGI:
-    case ELS_PLOGI_ACC:   // FC-PH PORT Login Accept
-    case ELS_PLOGI:   // FC-PH PORT Login
-    case ELS_PDISC:   // FC-PH2 Port Discovery - same payload as ELS_PLOGI
-      plogi->login_cmd = LS_PLOGI;
-      if( type == ELS_PDISC)
-        plogi->login_cmd = LS_PDISC;
-      else if( type == ELS_PLOGI_ACC )
-        plogi->login_cmd = LS_ACC;
-
-      plogi->cmn_services.bb_credit = 0x00;
-      plogi->cmn_services.lowest_ver = fcChip->lowest_FCPH_ver;
-      plogi->cmn_services.highest_ver = fcChip->highest_FCPH_ver;
-      plogi->cmn_services.bb_rx_size = TACHLITE_TS_RX_SIZE;
-      plogi->cmn_services.common_features = CONTINUOSLY_INCREASING |
-              RANDOM_RELATIVE_OFFSET;
-
-             // fill in with World Wide Name based Port Name - 8 UCHARs
-             // get from Tach registers WWN hi & lo
-      LoadWWN( fcChip, plogi->port_name, 0);
-             // fill in with World Wide Name based Node/Fabric Name - 8 UCHARs
-             // get from Tach registers WWN hi & lo
-      LoadWWN( fcChip, plogi->node_name, 1);
-
-	// For Seagate Drives.
-	//
-      plogi->cmn_services.common_features |= 0x800;
-      plogi->cmn_services.rel_offset = 0xFE;
-      plogi->cmn_services.concurrent_seq = 1;
-      plogi->class1.service_options = 0x00;
-      plogi->class2.service_options = 0x00;
-      plogi->class3.service_options = CLASS_VALID;
-      plogi->class3.initiator_control = 0x00;
-      plogi->class3.rx_data_size = MAX_RX_PAYLOAD;
-      plogi->class3.recipient_control =
-             ERROR_DISCARD | ONE_CATEGORY_SEQUENCE;
-      plogi->class3.concurrent_sequences = 1;
-      plogi->class3.open_sequences = 1;
-      plogi->vendor_id[0] = 'C'; plogi->vendor_id[1] = 'Q';
-      plogi->vendor_version[0] = 'C'; plogi->vendor_version[1] = 'Q';
-      plogi->vendor_version[2] = ' '; plogi->vendor_version[3] = '0';
-      plogi->vendor_version[4] = '0'; plogi->vendor_version[5] = '0';
-
-
-      // FLOGI specific fields... (see FC-FLA, Rev 2.7, Aug 1999, sec 5.1)
-      if( (type == ELS_FLOGI) || (type == ELS_FDISC) )
-      {
-        if( type == ELS_FLOGI )
-  	  plogi->login_cmd = LS_FLOGI;  
-	else
-  	  plogi->login_cmd = LS_FDISC;  
-
-        plogi->cmn_services.lowest_ver = 0x20;
-        plogi->cmn_services.common_features = 0x0800;
-        plogi->cmn_services.rel_offset = 0;
-        plogi->cmn_services.concurrent_seq = 0;
-
-        plogi->class3.service_options = 0x8800;
-        plogi->class3.rx_data_size = 0;
-        plogi->class3.recipient_control = 0;
-        plogi->class3.concurrent_sequences = 0;
-        plogi->class3.open_sequences = 0;
-      }
-      
-              // copy back to caller's buff, w/ BIG ENDIAN swap
-      BigEndianSwap( (UCHAR*)&PlogiPayload, payload,  sizeof(PlogiPayload));
-      break;
-
-    
-    case ELS_ACC:       // generic Extended Link Service ACCept	    
-      plogi->login_cmd = LS_ACC;
-              // copy back to caller's buff, w/ BIG ENDIAN swap
-      BigEndianSwap( (UCHAR*)&PlogiPayload, payload,  4);
-      break;
-
-
-      
-    case ELS_SCR:    // Fabric State Change Registration
-    {
-      SCR_PL scr;     // state change registration
-
-      memset( &scr, 0, sizeof(scr));
-
-      scr.command = LS_SCR;  // 0x62000000
-                             // see FC-FLA, Rev 2.7, Table A.22 (pg 82)
-      scr.function = 3;      // 1 = Events detected by Fabric
-                             // 2 = N_Port detected registration
-                             // 3 = Full registration
-      
-      // copy back to caller's buff, w/ BIG ENDIAN swap
-      BigEndianSwap( (UCHAR*)&scr, payload,  sizeof(SCR_PL));
-    }
-    
-    break;
-
-    
-    case FCS_NSR:    // Fabric Name Service Request
-    {
-      NSR_PL nsr;    // Name Server Req. payload
-
-      memset( &nsr, 0, sizeof(NSR_PL));
-
-                             // see Brocade Fabric Programming Guide,
-                             // Rev 1.3, pg 4-44
-      nsr.CT_Rev = 0x01000000;
-      nsr.FCS_Type = 0xFC020000;
-      nsr.Command_code = 0x01710000;
-      nsr.FCP = 8;
-     
-      // copy back to caller's buff, w/ BIG ENDIAN swap
-      BigEndianSwap( (UCHAR*)&nsr, payload,  sizeof(NSR_PL));
-    }
-    
-    break;
-
-
-
-    
-    case ELS_LOGO:   // FC-PH PORT LogOut
-      logo = &LogoutPayload;    // load into stack buffer,
-                                // then BIG-ENDIAN switch a copy to caller
-      logo->cmd = LS_LOGO;
-                                // load the 3 UCHARs of the node name
-                                // (if private loop, upper two UCHARs 0)
-      logo->reserved = 0;
-
-      logo->n_port_identifier[0] = (UCHAR)(fcChip->Registers.my_al_pa);
-      logo->n_port_identifier[1] =
-                     (UCHAR)(fcChip->Registers.my_al_pa>>8);
-      logo->n_port_identifier[2] =
-                     (UCHAR)(fcChip->Registers.my_al_pa>>16);
-             // fill in with World Wide Name based Port Name - 8 UCHARs
-             // get from Tach registers WWN hi & lo
-      LoadWWN( fcChip, logo->port_name, 0);
-
-      BigEndianSwap( (UCHAR*)&LogoutPayload,
-                     payload,  sizeof(LogoutPayload) );  // 16 UCHAR struct
-      break;
-
-
-    case ELS_LOGO_ACC:     // Logout Accept (FH-PH pg 149, table 74)
-      logo = &LogoutPayload;    // load into stack buffer,
-                                // then BIG-ENDIAN switch a copy to caller
-      logo->cmd = LS_ACC;
-      BigEndianSwap( (UCHAR*)&LogoutPayload, payload, 4 );  // 4 UCHAR cmnd
-      break;
-      
-
-    case ELS_RJT:          // ELS_RJT link service reject (FH-PH pg 155)
-
-      prjt = (REJECT_MESSAGE*)payload;  // pick up passed data
-      rjt.command_code = ELS_RJT;
-                       // reverse fields, because of Swap that follows...
-      rjt.vendor = prjt->reserved; // vendor specific
-      rjt.explain = prjt->reason; //
-      rjt.reason = prjt->explain; //
-      rjt.reserved = prjt->vendor; //
-                       // BIG-ENDIAN switch a copy to caller
-      BigEndianSwap( (UCHAR*)&rjt, payload, 8 );  // 8 UCHAR cmnd
-      break;
+	LOGIN_PAYLOAD *plogi;	// FC-PH Port Login
+	LOGIN_PAYLOAD PlogiPayload;	// copy for BIG ENDIAN switch
+	PRLI_REQUEST *prli;	// FCP-SCSI Process Login
+	PRLI_REQUEST PrliPayload;	// copy for BIG ENDIAN switch
+	LOGOUT_PAYLOAD *logo;
+	LOGOUT_PAYLOAD LogoutPayload;
+//	PRLO_REQUEST  *prlo;
+//	PRLO_REQUEST  PrloPayload;
+	REJECT_MESSAGE rjt, *prjt;
+
+	memset(&PlogiPayload, 0, sizeof(PlogiPayload));
+	plogi = &PlogiPayload;	// load into stack buffer,
+	// then BIG-ENDIAN switch a copy to caller
 
+	switch (type)		// payload type can be ELS_PLOGI, ELS_PRLI, ADISC, ...
+	{
+	case ELS_FDISC:
+	case ELS_FLOGI:
+	case ELS_PLOGI_ACC:	// FC-PH PORT Login Accept
+	case ELS_PLOGI:	// FC-PH PORT Login
+	case ELS_PDISC:	// FC-PH2 Port Discovery - same payload as ELS_PLOGI
+		plogi->login_cmd = LS_PLOGI;
+		if (type == ELS_PDISC)
+			plogi->login_cmd = LS_PDISC;
+		else if (type == ELS_PLOGI_ACC)
+			plogi->login_cmd = LS_ACC;
+
+		plogi->cmn_services.bb_credit = 0x00;
+		plogi->cmn_services.lowest_ver = fcChip->lowest_FCPH_ver;
+		plogi->cmn_services.highest_ver = fcChip->highest_FCPH_ver;
+		plogi->cmn_services.bb_rx_size = TACHLITE_TS_RX_SIZE;
+		plogi->cmn_services.common_features = CONTINUOSLY_INCREASING | RANDOM_RELATIVE_OFFSET;
+
+		// fill in with World Wide Name based Port Name - 8 u8s
+		// get from Tach registers WWN hi & lo
+		LoadWWN(fcChip, plogi->port_name, 0);
+		// fill in with World Wide Name based Node/Fabric Name - 8 u8s
+		// get from Tach registers WWN hi & lo
+		LoadWWN(fcChip, plogi->node_name, 1);
+
+		// For Seagate Drives.
+		//
+		plogi->cmn_services.common_features |= 0x800;
+		plogi->cmn_services.rel_offset = 0xFE;
+		plogi->cmn_services.concurrent_seq = 1;
+		plogi->class1.service_options = 0x00;
+		plogi->class2.service_options = 0x00;
+		plogi->class3.service_options = CLASS_VALID;
+		plogi->class3.initiator_control = 0x00;
+		plogi->class3.rx_data_size = MAX_RX_PAYLOAD;
+		plogi->class3.recipient_control = ERROR_DISCARD | ONE_CATEGORY_SEQUENCE;
+		plogi->class3.concurrent_sequences = 1;
+		plogi->class3.open_sequences = 1;
+		plogi->vendor_id[0] = 'C';
+		plogi->vendor_id[1] = 'Q';
+		plogi->vendor_version[0] = 'C';
+		plogi->vendor_version[1] = 'Q';
+		plogi->vendor_version[2] = ' ';
+		plogi->vendor_version[3] = '0';
+		plogi->vendor_version[4] = '0';
+		plogi->vendor_version[5] = '0';
+
+		// FLOGI specific fields... (see FC-FLA, Rev 2.7, Aug 1999, sec 5.1)
+		if ((type == ELS_FLOGI) || (type == ELS_FDISC)) {
+			if (type == ELS_FLOGI)
+				plogi->login_cmd = LS_FLOGI;
+			else
+				plogi->login_cmd = LS_FDISC;
+
+			plogi->cmn_services.lowest_ver = 0x20;
+			plogi->cmn_services.common_features = 0x0800;
+			plogi->cmn_services.rel_offset = 0;
+			plogi->cmn_services.concurrent_seq = 0;
+
+			plogi->class3.service_options = 0x8800;
+			plogi->class3.rx_data_size = 0;
+			plogi->class3.recipient_control = 0;
+			plogi->class3.concurrent_sequences = 0;
+			plogi->class3.open_sequences = 0;
+		}
+		// copy back to caller's buff, w/ BIG ENDIAN swap
+		BigEndianSwap((u8 *) & PlogiPayload, payload, sizeof(PlogiPayload));
+		break;
 
+	case ELS_ACC:		// generic Extended Link Service ACCept     
+		plogi->login_cmd = LS_ACC;
+		// copy back to caller's buff, w/ BIG ENDIAN swap
+		BigEndianSwap((u8 *) & PlogiPayload, payload, 4);
+		break;
 
+	case ELS_SCR:		// Fabric State Change Registration
+		{
+			SCR_PL scr;	// state change registration
+
+			memset(&scr, 0, sizeof(scr));
+
+			scr.command = LS_SCR;	// 0x62000000
+			// see FC-FLA, Rev 2.7, Table A.22 (pg 82)
+			scr.function = 3;	// 1 = Events detected by Fabric
+			// 2 = N_Port detected registration
+			// 3 = Full registration
 
+			// copy back to caller's buff, w/ BIG ENDIAN swap
+			BigEndianSwap((u8 *) & scr, payload, sizeof(SCR_PL));
+		}
+		break;
 
-    case ELS_PRLI_ACC:  // Process Login ACCept
-    case ELS_PRLI:  // Process Login
-    case ELS_PRLO:  // Process Logout
-      memset( &PrliPayload, 0, sizeof( PrliPayload));
-      prli = &PrliPayload;      // load into stack buffer,
+	case FCS_NSR:		// Fabric Name Service Request
+		{
+			NSR_PL nsr;	// Name Server Req. payload
+
+			memset(&nsr, 0, sizeof(NSR_PL));
+
+			// see Brocade Fabric Programming Guide,
+			// Rev 1.3, pg 4-44
+			nsr.CT_Rev = 0x01000000;
+			nsr.FCS_Type = 0xFC020000;
+			nsr.Command_code = 0x01710000;
+			nsr.FCP = 8;
 
-      if( type == ELS_PRLI )
-        prli->cmd = 0x20;  // Login
-      else if( type == ELS_PRLO )
-        prli->cmd = 0x21;  // Logout
-      else if( type == ELS_PRLI_ACC )
-      {
-        prli->cmd = 0x02;  // Login ACCept
-        prli->valid = REQUEST_EXECUTED;
-      }
+			// copy back to caller's buff, w/ BIG ENDIAN swap
+			BigEndianSwap((u8 *) & nsr, payload, sizeof(NSR_PL));
+		}
+		break;
 
+	case ELS_LOGO:		// FC-PH PORT LogOut
+		logo = &LogoutPayload;	// load into stack buffer,
+		// then BIG-ENDIAN switch a copy to caller
+		logo->cmd = LS_LOGO;
+		// load the 3 u8s of the node name
+		// (if private loop, upper two u8s 0)
+		logo->reserved = 0;
+
+		logo->n_port_identifier[0] = (u8) (fcChip->Registers.my_al_pa);
+		logo->n_port_identifier[1] = (u8) (fcChip->Registers.my_al_pa >> 8);
+		logo->n_port_identifier[2] = (u8) (fcChip->Registers.my_al_pa >> 16);
+		// fill in with World Wide Name based Port Name - 8 u8s
+		// get from Tach registers WWN hi & lo
+		LoadWWN(fcChip, logo->port_name, 0);
 
-      prli->valid |= SCSI_FCP | ESTABLISH_PAIR;
-      prli->fcp_info = READ_XFER_RDY;
-      prli->page_length = 0x10;
-      prli->payload_length = 20;
-                                // Can be initiator AND target
+		BigEndianSwap((u8 *) & LogoutPayload, payload, sizeof(LogoutPayload));	// 16 u8 struct
+		break;
 
-      if( fcChip->Options.initiator )
-        prli->fcp_info |= INITIATOR_FUNCTION;
-      if( fcChip->Options.target )
-        prli->fcp_info |= TARGET_FUNCTION;
+	case ELS_LOGO_ACC:	// Logout Accept (FH-PH pg 149, table 74)
+		logo = &LogoutPayload;	// load into stack buffer,
+		// then BIG-ENDIAN switch a copy to caller
+		logo->cmd = LS_ACC;
+		BigEndianSwap((u8 *) & LogoutPayload, payload, 4);	// 4 u8 cmnd
+		break;
 
-      BigEndianSwap( (UCHAR*)&PrliPayload, payload,  prli->payload_length);
-      break;
+	case ELS_RJT:		// ELS_RJT link service reject (FH-PH pg 155)
+		prjt = (REJECT_MESSAGE *) payload;	// pick up passed data
+		rjt.command_code = ELS_RJT;
+		// reverse fields, because of Swap that follows...
+		rjt.vendor = prjt->reserved;	// vendor specific
+		rjt.explain = prjt->reason;	//
+		rjt.reason = prjt->explain;	//
+		rjt.reserved = prjt->vendor;	//
+		// BIG-ENDIAN switch a copy to caller
+		BigEndianSwap((u8 *) & rjt, payload, 8);	// 8 u8 cmnd
+		break;
 
+	case ELS_PRLI_ACC:	// Process Login ACCept
+	case ELS_PRLI:		// Process Login
+	case ELS_PRLO:		// Process Logout
+		memset(&PrliPayload, 0, sizeof(PrliPayload));
+		prli = &PrliPayload;	// load into stack buffer,
+
+		if (type == ELS_PRLI)
+			prli->cmd = 0x20;	// Login
+		else if (type == ELS_PRLO)
+			prli->cmd = 0x21;	// Logout
+		else if (type == ELS_PRLI_ACC) {
+			prli->cmd = 0x02;	// Login ACCept
+			prli->valid = REQUEST_EXECUTED;
+		}
+		prli->valid |= SCSI_FCP | ESTABLISH_PAIR;
+		prli->fcp_info = READ_XFER_RDY;
+		prli->page_length = 0x10;
+		prli->payload_length = 20;
+		// Can be initiator AND target
+
+		if (fcChip->Options.initiator)
+			prli->fcp_info |= INITIATOR_FUNCTION;
+		if (fcChip->Options.target)
+			prli->fcp_info |= TARGET_FUNCTION;
 
+		BigEndianSwap((u8 *) & PrliPayload, payload, prli->payload_length);
+		break;
 
-    default:  // no can do - programming error
-      printk(" BuildLinkServicePayload unknown!\n");
-      break;
-  }
+	default:		// no can do - programming error
+		printk(" BuildLinkServicePayload unknown!\n");
+		break;
+	}
 }
 
-// loads 8 UCHARs for PORT name or NODE name base on
+// loads 8 u8s for PORT name or NODE name base on
 // controller's WWN.
-void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type)
+void LoadWWN(PTACHYON fcChip, u8 * dest, u8 type)
 {
-  UCHAR* bPtr, i;
-
-  switch( type )
-  {
-    case 0:  // Port_Name
-      bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
-      for( i =0; i<4; i++)
-        dest[i] = *bPtr++;
-      bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
-      for( i =4; i<8; i++)
-        dest[i] = *bPtr++;
-      break;
-    case 1:  // Node/Fabric _Name
-      bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
-      for( i =0; i<4; i++)
-        dest[i] = *bPtr++;
-      bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
-      for( i =4; i<8; i++)
-        dest[i] = *bPtr++;
-      break;
-  }
-  
-}
+	u8 *bPtr, i;
 
+	switch (type) {
+	case 0:		// Port_Name
+		bPtr = (u8 *) & fcChip->Registers.wwn_hi;
+		for (i = 0; i < 4; i++)
+			dest[i] = *bPtr++;
+		bPtr = (u8 *) & fcChip->Registers.wwn_lo;
+		for (i = 4; i < 8; i++)
+			dest[i] = *bPtr++;
+		break;
+	case 1:		// Node/Fabric _Name
+		bPtr = (u8 *) & fcChip->Registers.wwn_hi;
+		for (i = 0; i < 4; i++)
+			dest[i] = *bPtr++;
+		bPtr = (u8 *) & fcChip->Registers.wwn_lo;
+		for (i = 4; i < 8; i++)
+			dest[i] = *bPtr++;
+		break;
+	}
 
+}
 
 // We check the Port Login payload for required values.  Note that
 // ELS_PLOGI and ELS_PDISC (Port DISCover) use the same payload.
 
+int verify_PLOGI(PTACHYON fcChip, TachFCHDR_GCMND * fchs, u32 * reject_explain)
+{
+	LOGIN_PAYLOAD login;
 
-int verify_PLOGI( PTACHYON fcChip,
-                  TachFCHDR_GCMND* fchs, 
-                  ULONG* reject_explain)
-{
-  LOGIN_PAYLOAD	login;
-
-                  // source, dest, len (should be mult. of 4)
-  BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&login,  sizeof(login));
-
-                            // check FC version
-                            // if other port's highest supported version
-                            // is less than our lowest, and 
-                            // if other port's lowest
-  if( login.cmn_services.highest_ver < fcChip->lowest_FCPH_ver ||
-      login.cmn_services.lowest_ver > fcChip->highest_FCPH_ver )
-  {
-    *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
-    return LOGICAL_ERROR;
-  }
-
-                            // Receive Data Field Size must be >=128
-                            // per FC-PH
-  if (login.cmn_services.bb_rx_size < 128)
-  {
-    *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, DATA_FIELD_SIZE_ERROR);
-    return LOGICAL_ERROR;
-  }
+	// source, dest, len (should be mult. of 4)
+	BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & login, sizeof(login));
 
-                            // Only check Class 3 params
-  if( login.class3.service_options & CLASS_VALID)
-  {
-    if (login.class3.rx_data_size < 128)
-    {
-      *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INVALID_CSP);
-      return LOGICAL_ERROR;
-    }
-    if( login.class3.initiator_control & XID_REQUIRED)
-    {
-      *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INITIATOR_CTL_ERROR);
-      return LOGICAL_ERROR;
-    }
-  }
-  return 0;   // success
+	// check FC version
+	// if other port's highest supported version
+	// is less than our lowest, and 
+	// if other port's lowest
+	if (login.cmn_services.highest_ver < fcChip->lowest_FCPH_ver || login.cmn_services.lowest_ver > fcChip->highest_FCPH_ver) {
+		*reject_explain = LS_RJT_REASON(LOGICAL_ERROR, OPTIONS_ERROR);
+		return LOGICAL_ERROR;
+	}
+	// Receive Data Field Size must be >=128
+	// per FC-PH
+	if (login.cmn_services.bb_rx_size < 128) {
+		*reject_explain = LS_RJT_REASON(LOGICAL_ERROR, DATA_FIELD_SIZE_ERROR);
+		return LOGICAL_ERROR;
+	}
+	// Only check Class 3 params
+	if (login.class3.service_options & CLASS_VALID) {
+		if (login.class3.rx_data_size < 128) {
+			*reject_explain = LS_RJT_REASON(LOGICAL_ERROR, INVALID_CSP);
+			return LOGICAL_ERROR;
+		}
+		if (login.class3.initiator_control & XID_REQUIRED) {
+			*reject_explain = LS_RJT_REASON(LOGICAL_ERROR, INITIATOR_CTL_ERROR);
+			return LOGICAL_ERROR;
+		}
+	}
+	return 0;		// success
 }
 
-
-
-
-int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain)
+int verify_PRLI(TachFCHDR_GCMND * fchs, u32 * reject_explain)
 {
-  PRLI_REQUEST prli;  // buffer for BIG ENDIAN
+	PRLI_REQUEST prli;	// buffer for BIG ENDIAN
 
-                  // source, dest, len (should be mult. of 4)
-  BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli,  sizeof(prli));
+	// source, dest, len (should be mult. of 4)
+	BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & prli, sizeof(prli));
 
-  if( prli.fcp_info == 0 )  // i.e., not target or initiator?
-  {
-    *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
-    return LOGICAL_ERROR;
-  }
+	if (prli.fcp_info == 0)	// i.e., not target or initiator?
+	{
+		*reject_explain = LS_RJT_REASON(LOGICAL_ERROR, OPTIONS_ERROR);
+		return LOGICAL_ERROR;
+	}
 
-  return 0;  // success
+	return 0;		// success
 }
 
-
-// SWAP UCHARs as required by Fibre Channel (i.e. BIG ENDIAN)
+// SWAP u8s as required by Fibre Channel (i.e. BIG ENDIAN)
 // INPUTS:
-//   source   - ptr to LITTLE ENDIAN ULONGS
-//   cnt      - number of UCHARs to switch (should be mult. of ULONG)
+//   source   - ptr to LITTLE ENDIAN u32S
+//   cnt      - number of u8s to switch (should be mult. of u32)
 // OUTPUTS:
 //   dest     - ptr to BIG ENDIAN copy
 // RETURN:
 //   none
 //
-void BigEndianSwap( UCHAR *source, UCHAR *dest,  USHORT cnt)
+void BigEndianSwap(u8 * source, u8 * dest, u16 cnt)
 {
-  int i,j;
+	int i, j;
 
-  source+=3;   // start at MSB of 1st ULONG
-  for( j=0; j < cnt; j+=4, source+=4, dest+=4)  // every ULONG
-  {
-    for( i=0; i<4; i++)  // every UCHAR in ULONG
-          *(dest+i) = *(source-i);
-  }
+	source += 3;		// start at MSB of 1st u32
+	for (j = 0; j < cnt; j += 4, source += 4, dest += 4)	// every u32
+	{
+		for (i = 0; i < 4; i++)	// every u8 in u32
+			*(dest + i) = *(source - i);
+	}
 }
 
-
-
-
 // Build FC Exchanges............
 
-static void  buildFCPstatus( 
-  PTACHYON fcChip, 
-  ULONG ExchangeID);
-
-static LONG FindFreeExchange( PTACHYON fcChip, ULONG type );
-
-static ULONG build_SEST_sgList( 
-  struct pci_dev *pcidev,
-  ULONG *SESTalPairStart,
-  Scsi_Cmnd *Cmnd,
-  ULONG *sgPairs,
-  PSGPAGES *sgPages_head  // link list of TL Ext. S/G pages from O/S Pool
-);
-
-static int build_FCP_payload( Scsi_Cmnd *Cmnd, 
-  UCHAR* payload, ULONG type, ULONG fcp_dl );
-
+static void buildFCPstatus(PTACHYON fcChip, u32 ExchangeID);
+static s32 FindFreeExchange(PTACHYON fcChip, u32 type);
+static u32 build_SEST_sgList(struct pci_dev *pcidev, u32 * SESTalPairStart, Scsi_Cmnd * Cmnd, u32 * sgPairs, PSGPAGES * sgPages_head);	// link list of TL Ext. S/G pages from O/S Pool
+static int build_FCP_payload(Scsi_Cmnd * Cmnd, u8 * payload, u32 type, u32 fcp_dl);
 
 /*
                              IRB
@@ -4118,7 +3306,7 @@
 // SEST entry, and several frame headers and data buffers all
 // logically linked together.
 // Inputs:
-//   cpqfcHBAdata  - controller struct
+//   dev  - controller struct
 //   type          - PLOGI, SCSI_IWE, etc.
 //   InFCHS        - Incoming Tachlite FCHS which prompted this exchange
 //                   (only s_id set if we are originating)
@@ -4143,990 +3331,807 @@
 // return success
 
 //sbuildex
-ULONG cpqfcTSBuildExchange(
-  CPQFCHBA *cpqfcHBAdata,
-  ULONG type, // e.g. PLOGI
-  TachFCHDR_GCMND* InFCHS,  // incoming FCHS
-  void *Data,               // the CDB, scatter/gather, etc.  
-  LONG *fcExchangeIndex )   // points to allocated exchange, 
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG ulStatus = 0;  // assume OK
-  USHORT ox_ID, rx_ID=0xFFFF;
-  ULONG SfsLen=0L;
-  TachLiteIRB* pIRB;
-  IRBflags IRB_flags;
-  UCHAR *pIRB_flags = (UCHAR*)&IRB_flags;
-  TachFCHDR_GCMND* CMDfchs;
-  TachFCHDR* dataHDR;     // 32 byte HEADER ONLY FCP-DATA buffer
-  TachFCHDR_RSP* rspHDR;     // 32 byte header + RSP payload
-  Scsi_Cmnd *Cmnd = (Scsi_Cmnd*)Data;   // Linux Scsi CDB, S/G, ...
-  TachLiteIWE* pIWE;
-  TachLiteIRE* pIRE;
-  TachLiteTWE* pTWE;
-  TachLiteTRE* pTRE;
-  ULONG fcp_dl;           // total byte length of DATA transferred
-  ULONG fl;               // frame length (FC frame size, 128, 256, 512, 1024)
-  ULONG sgPairs;          // number of valid scatter/gather pairs
-  int FCP_SCSI_command;
-  BA_ACC_PAYLOAD *ba_acc;
-  BA_RJT_PAYLOAD *ba_rjt;
-
-                          // check passed ARGS
-  if( !fcChip->ERQ )      // NULL ptr means uninitialized Tachlite chip
-    return INVALID_ARGS;
-
-
-  if( type == SCSI_IRE ||
-      type == SCSI_TRE ||
-      type == SCSI_IWE ||
-      type == SCSI_TWE)
-    FCP_SCSI_command = 1;
-
-  else
-    FCP_SCSI_command = 0;
-
-
-                     // for commands that pass payload data (e.g. SCSI write)
-                     // examine command struct - verify that the
-                     // length of s/g buffers is adequate for total payload
-                     // length (end of list is NULL address)
-
-  if( FCP_SCSI_command )
-  {
-    if( Data )     // must have data descriptor (S/G list -- at least
-                   // one address with at least 1 byte of data)
-    {
-      // something to do (later)?
-    }
-
-    else
-      return INVALID_ARGS;  // invalid DATA ptr
-  }
-
-    
-
-         // we can build an Exchange for later Queuing (on the TL chip)
-         // if an empty slot is available in the DevExt for this controller
-         // look for available Exchange slot...
-
-  if( type != FCP_RESPONSE &&
-      type != BLS_ABTS &&
-      type != BLS_ABTS_ACC )  // already have Exchange slot!
-    *fcExchangeIndex = FindFreeExchange( fcChip, type );
-
-  if( *fcExchangeIndex != -1 )   // Exchange is available?
-  {
-                     // assign tmp ptr (shorthand)
-    CMDfchs = &Exchanges->fcExchange[ *fcExchangeIndex].fchs; 
-
-    if( Cmnd != NULL ) // (necessary for ABTS cases)
-    {
-      Exchanges->fcExchange[ *fcExchangeIndex].Cmnd = Cmnd; // Linux Scsi
-      Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort = 
-	fcFindLoggedInPort( fcChip,
-          Exchanges->fcExchange[ *fcExchangeIndex].Cmnd, // find Scsi Nexus
-          0,        // DON'T search linked list for FC port id
-	  NULL,     // DON'T search linked list for FC WWN
-          NULL);    // DON'T care about end of list
-
-    }
-
-
-                     // Build the command frame header (& data) according
-                     // to command type
-
-                     // fields common for all SFS frame types
-    CMDfchs->reserved = 0L; // must clear
-    CMDfchs->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; LCr=0, no TS
-    
-             // get the destination port_id from incoming FCHS
-             // (initialized before calling if we're Originator)
-             // Frame goes to port it was from - the source_id
-    
-    CMDfchs->d_id = InFCHS->s_id &0xFFFFFF; // destination (add R_CTL later)
-    CMDfchs->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
+u32 cpqfcTSBuildExchange(CPQFCHBA * dev, u32 type,	// e.g. PLOGI
+			   TachFCHDR_GCMND * InFCHS,	// incoming FCHS
+			   void *Data,	// the CDB, scatter/gather, etc.  
+			   s32 * fcExchangeIndex)	// points to allocated exchange, 
+{
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 ulStatus = 0;	// assume OK
+	u16 ox_ID, rx_ID = 0xFFFF;
+	u32 SfsLen = 0L;
+	TachLiteIRB *pIRB;
+	IRBflags IRB_flags;
+	u8 *pIRB_flags = (u8 *) & IRB_flags;
+	TachFCHDR_GCMND *CMDfchs;
+	TachFCHDR *dataHDR;	// 32 byte HEADER ONLY FCP-DATA buffer
+	TachFCHDR_RSP *rspHDR;	// 32 byte header + RSP payload
+	Scsi_Cmnd *Cmnd = (Scsi_Cmnd *) Data;	// Linux Scsi CDB, S/G, ...
+	TachLiteIWE *pIWE;
+	TachLiteIRE *pIRE;
+	TachLiteTWE *pTWE;
+	TachLiteTRE *pTRE;
+	u32 fcp_dl;		// total byte length of DATA transferred
+	u32 fl;		// frame length (FC frame size, 128, 256, 512, 1024)
+	u32 sgPairs;		// number of valid scatter/gather pairs
+	int FCP_SCSI_command;
+	BA_ACC_PAYLOAD *ba_acc;
+	BA_RJT_PAYLOAD *ba_rjt;
+
+	// check passed ARGS
+	if (!fcChip->ERQ)	// NULL ptr means uninitialized Tachlite chip
+		return INVALID_ARGS;
 
-
-    // now enter command-specific fields
-    switch( type )
-    {
-
-    case BLS_NOP:   // FC defined basic link service command NO-OP
-                // ensure unique X_IDs! (use tracking function)
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 32L;        // add len to LSB (header only - no payload)
-
-                   // TYPE[31-24] 00 Basic Link Service
-                   // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
-      CMDfchs->d_id |= 0x80000000L;  // R_CTL = 80 for NOP (Basic Link Ser.)
-      CMDfchs->f_ctl = 0x00310000L;  // xchng originator, 1st seq,....
-      CMDfchs->seq_cnt = 0x0L;
-      CMDfchs->ox_rx_id = 0xFFFF;        // RX_ID for now; OX_ID on start
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-      CMDfchs->pl[0] = 0xaabbccddL;   // words 8-15 frame data payload (n/a)
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // seconds
-                                      // (NOP should complete ~instantly)
-      break;
-
-
-    
-    
-    case BLS_ABTS_ACC:  // Abort Sequence ACCept
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 32 + 12;    // add len to LSB (header + 3 DWORD payload)
-
-      CMDfchs->d_id |= 0x84000000L;  // R_CTL = 84 for BASIC ACCept
-                   // TYPE[31-24] 00 Basic Link Service
-                   // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
-      CMDfchs->f_ctl = 0x00910000L;  // xchnge responder, last seq, xfer SI
-                   // CMDfchs->seq_id & count might be set from DataHdr?
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
-                        // (Timeout in case of weird error)
-      
-      // now set the ACCept payload...
-      ba_acc = (BA_ACC_PAYLOAD*)&CMDfchs->pl[0];
-      memset( ba_acc, 0, sizeof( BA_ACC_PAYLOAD));
-      // Since PLDA requires (only) entire Exchange aborts, we don't need
-      // to worry about what the last sequence was.
-
-      // We expect that a "target" task is accepting the abort, so we
-      // can use the OX/RX ID pair 
-      ba_acc->ox_rx_id = CMDfchs->ox_rx_id;
- 
-      // source, dest, #bytes
-      BigEndianSwap((UCHAR *)&CMDfchs->ox_rx_id, (UCHAR *)&ba_acc->ox_rx_id, 4);
-
-      ba_acc->low_seq_cnt = 0;
-      ba_acc->high_seq_cnt = 0xFFFF;
-
-
-      break;
-    
-
-    case BLS_ABTS_RJT:  // Abort Sequence ACCept
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 32 + 12;    // add len to LSB (header + 3 DWORD payload)
-
-      CMDfchs->d_id |= 0x85000000L;  // R_CTL = 85 for BASIC ReJecT
-                   // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
-                   // TYPE[31-24] 00 Basic Link Service
-      CMDfchs->f_ctl = 0x00910000L;  // xchnge responder, last seq, xfer SI
-                   // CMDfchs->seq_id & count might be set from DataHdr?
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
-                        // (Timeout in case of weird error)
-      
-      CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // copy from sender!
-      
-      // now set the ReJecT payload...
-      ba_rjt = (BA_RJT_PAYLOAD*)&CMDfchs->pl[0];
-      memset( ba_rjt, 0, sizeof( BA_RJT_PAYLOAD));
-
-      // We expect that a "target" task couldn't find the Exhange in the
-      // array of active exchanges, so we use a new LinkService X_ID.
-      // See Reject payload description in FC-PH (Rev 4.3), pg. 140
-      ba_rjt->reason_code = 0x09; // "unable to perform command request"
-      ba_rjt->reason_explain = 0x03; // invalid OX/RX ID pair
-
-
-      break;
-    
-    
-    case BLS_ABTS:   // FC defined basic link service command ABTS 
-                     // Abort Sequence
-                     
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 32L;        // add len to LSB (header only - no payload)
-
-                   // TYPE[31-24] 00 Basic Link Service
-                   // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
-      CMDfchs->d_id |= 0x81000000L;  // R_CTL = 81 for ABTS
-      CMDfchs->f_ctl = 0x00110000L;  // xchnge originator, last seq, xfer SI
-                   // CMDfchs->seq_id & count might be set from DataHdr?
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
-                        // (ABTS must timeout when responder is gone)
-      break;
-
-    
-    
-    case FCS_NSR:    // Fabric Name Service Request
-       Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
-
-
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
-                         // OX_ID, linked to Driver Transaction ID
-                         // (fix-up at Queing time)
-      CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
-                                    // OX_ID set at ERQueing time
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += (32L + sizeof(NSR_PL)); // add len (header & NSR payload)
-
-      CMDfchs->d_id |= 0x02000000L;  // R_CTL = 02 for -
-                                   // Name Service Request: Unsolicited 
-                   // TYPE[31-24] 01 Extended Link Service
-                   // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
-      CMDfchs->f_ctl = 0x20210000L;
-                   // OX_ID will be fixed-up at Tachyon enqueing time
-      CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-      BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
-
-   
-    
-    
-    
-    
-      break;
-    
-    
-    
-    
-    case ELS_PLOGI:  // FC-PH extended link service command Port Login
-      // (May, 2000)
-      // NOTE! This special case facilitates SANMark testing.  The SANMark
-      // test script for initialization-timeout.fcal.SANMark-1.fc
-      // "eats" the OPN() primitive without issuing an R_RDY, causing
-      // Tachyon to report LST (loop state timeout), which causes a
-      // LIP.  To avoid this, simply send out the frame (i.e. assuming a
-      // buffer credit of 1) without waiting for R_RDY.  Many FC devices
-      // (other than Tachyon) have been doing this for years.  We don't
-      // ever want to do this for non-Link Service frames unless the
-      // other device really did report non-zero login BB credit (i.e.
-      // in the PLOGI ACCept frame).
-//      CMDfchs->sof_eof |= 0x00000400L;  // LCr=1
-    
-    case ELS_FDISC:  // Fabric Discovery (Login)
-    case ELS_FLOGI:  // Fabric Login
-    case ELS_SCR:    // Fabric State Change Registration
-    case ELS_LOGO:   // FC-PH extended link service command Port Logout
-    case ELS_PDISC:  // FC-PH extended link service cmnd Port Discovery
-    case ELS_PRLI:   // FC-PH extended link service cmnd Process Login
-
-      Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
-
-
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
-                         // OX_ID, linked to Driver Transaction ID
-                         // (fix-up at Queing time)
-      CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
-                                    // OX_ID set at ERQueing time
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      if( type == ELS_LOGO )
-        SfsLen += (32L + 16L); //  add len (header & PLOGI payload)
-      else if( type == ELS_PRLI )
-        SfsLen += (32L + 20L); //  add len (header & PRLI payload)
-      else if( type == ELS_SCR )
-        SfsLen += (32L + sizeof(SCR_PL)); //  add len (header & SCR payload)
-      else
-        SfsLen += (32L + 116L); //  add len (header & PLOGI payload)
-
-      CMDfchs->d_id |= 0x22000000L;  // R_CTL = 22 for -
-                                   // Extended Link_Data: Unsolicited Control
-                   // TYPE[31-24] 01 Extended Link Service
-                   // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
-      CMDfchs->f_ctl = 0x01210000L;
-                   // OX_ID will be fixed-up at Tachyon enqueing time
-      CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-      BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
-
-      break;
-
-
-
-    case ELS_LOGO_ACC: // FC-PH extended link service logout accept
-    case ELS_RJT:          // extended link service reject (add reason)
-    case ELS_ACC:      // ext. link service generic accept
-    case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
-    case ELS_PRLI_ACC: // ext. link service process login accept
-
-
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // assume done
-                // ensure unique X_IDs! (use tracking function)
-                // OX_ID from initiator cmd
-      ox_ID = (USHORT)(InFCHS->ox_rx_id >> 16); 
-      rx_ID = 0xFFFF; // RX_ID, linked to Driver Exchange ID
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      if( type == ELS_RJT )
-      {
-        SfsLen += (32L + 8L); //  add len (header + payload)
-
-        // ELS_RJT reason codes (utilize unused "reserved" field)
-        CMDfchs->pl[0] = 1;
-        CMDfchs->pl[1] = InFCHS->reserved;  
-          
-      }
-      else if( (type == ELS_LOGO_ACC) || (type == ELS_ACC)  )
-        SfsLen += (32L + 4L); //  add len (header + payload)
-      else if( type == ELS_PLOGI_ACC )
-        SfsLen += (32L + 116L); //  add len (header + payload)
-      else if( type == ELS_PRLI_ACC )
-        SfsLen += (32L + 20L); //  add len (header + payload)
-
-      CMDfchs->d_id |= 0x23000000L;  // R_CTL = 23 for -
-                                   // Extended Link_Data: Control Reply
-                   // TYPE[31-24] 01 Extended Link Service
-                   // f_ctl[23:0] exchg responder, last seq, e_s, tsi
-      CMDfchs->f_ctl = 0x01990000L;
-      CMDfchs->seq_cnt = 0x0L;
-      CMDfchs->ox_rx_id = 0L;        // clear
-      CMDfchs->ox_rx_id = ox_ID; // load upper 16 bits
-      CMDfchs->ox_rx_id <<= 16;      // shift them
-
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-      BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
-
-      break;
-
-
-                         // Fibre Channel SCSI 'originator' sequences...
-                         // (originator means 'initiator' in FCP-SCSI)
-
-    case SCSI_IWE: // TachLite Initiator Write Entry
-    {
-      PFC_LOGGEDIN_PORT pLoggedInPort = 
-        Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort;
-
-      Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // FC2 timeout
-                       
-      // first, build FCP_CMND
-      // unique X_ID fix-ups in StartExchange 
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS FCP-CMND (not SEST index)
-
-      // NOTE: unlike FC LinkService login frames, normal
-      // SCSI commands are sent without outgoing verification
-      IRB_flags.DCM = 1;    // Disable completion message for Cmnd frame
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 64L;        // add len to LSB (header & CMND payload)
-
-      CMDfchs->d_id |= (0x06000000L);  // R_CTL = 6 for command
-
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
-                   //             valid RO
-      CMDfchs->f_ctl = 0x08210008L;
-      CMDfchs->seq_cnt = 0x0L;
-      CMDfchs->ox_rx_id = 0L;        // clear for now (-or- in later)
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-                   // now, fill out FCP-DATA header
-                   // (use buffer inside SEST object)
-      dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
-      dataHDR->reserved = 0L; // must clear
-      dataHDR->sof_eof = 0x75002000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
-      dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
-      dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] xfer S.I.| valid RO
-      dataHDR->f_ctl = 0x08010008L;
-      dataHDR->seq_cnt = 0x02000000L;  // sequence ID: df_ctl : seqence count
-      dataHDR->ox_rx_id = 0L;        // clear; fix-up dataHDR fields later
-      dataHDR->ro = 0x0L;    // relative offset (n/a)
-
-                   // Now setup the SEST entry
-      pIWE = &fcChip->SEST->u[ *fcExchangeIndex ].IWE;
-      
-                   // fill out the IWE:
-
-                // VALid entry:Dir outbound:DCM:enable CM:enal INT: FC frame len
-      pIWE->Hdr_Len = 0x8e000020L; // data frame Len always 32 bytes
-      
-      
-      // from login parameters with other port, what's the largest frame
-      // we can send? 
-      if( pLoggedInPort == NULL) 
-      {
-	ulStatus = INVALID_ARGS;  // failed! give up
-	break;
-      }
-      if( pLoggedInPort->rx_data_size  >= 2048)
-        fl = 0x00020000;  // 2048 code (only support 1024!)
-      else if( pLoggedInPort->rx_data_size  >= 1024)
-        fl = 0x00020000;  // 1024 code
-      else if( pLoggedInPort->rx_data_size  >= 512)
-        fl = 0x00010000;  // 512 code
-      else
-	fl = 0;  // 128 bytes -- should never happen
-      
-      
-      pIWE->Hdr_Len |= fl; // add xmit FC frame len for data phase
-      pIWE->Hdr_Addr = fcChip->SEST->base + 
-		((unsigned long)&fcChip->SEST->DataHDR[*fcExchangeIndex] - 
-			(unsigned long)fcChip->SEST);
-
-      pIWE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
-      pIWE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
-      
-      memset( &fcChip->SEST->RspHDR[ *fcExchangeIndex].pl, 0, 
-        sizeof( FCP_STATUS_RESPONSE) );  // clear out previous status
- 
-      pIWE->RSP_Addr = fcChip->SEST->base + 
-		((unsigned long)&fcChip->SEST->RspHDR[*fcExchangeIndex] - 
-			(unsigned long)fcChip->SEST);
-
-                   // Do we need local or extended gather list?
-                   // depends on size - we can handle 3 len/addr pairs
-                   // locally.
-
-      fcp_dl = build_SEST_sgList( 
-	cpqfcHBAdata->PciDev,
-        &pIWE->GLen1, 
-        Cmnd,       // S/G list
-        &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
-        &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
-
-      if( !fcp_dl ) // error building S/G list?
-      {
-        ulStatus = MEMPOOL_FAIL;
-        break;      // give up
-      }
-
-                             // Now that we know total data length in
-                             // the passed S/G buffer, set FCP CMND frame
-      build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
-
-
-      
-      if( sgPairs > 3 )  // need extended s/g list
-        pIWE->Buff_Off = 0x78000000L; // extended data | (no offset)
-      else               // local data pointers (in SEST)
-        pIWE->Buff_Off = 0xf8000000L; // local data | (no offset)
-
-                              // ULONG 5
-      pIWE->Link = 0x0000ffffL;   // Buff_Index | Link
-
-      pIWE->RX_ID = 0x0L;     // DWord 6: RX_ID set by target XFER_RDY
-
-                                      // DWord 7
-      pIWE->Data_Len = 0L;    // TL enters rcv'd XFER_RDY BURST_LEN
-      pIWE->Exp_RO = 0L;      // DWord 8
-                              // DWord 9
-      pIWE->Exp_Byte_Cnt = fcp_dl;  // sum of gather buffers
-    }
-    break;
-
-
-
-
-
-    case SCSI_IRE: // TachLite Initiator Read Entry
-
-      if( Cmnd->timeout != 0)
-      {
-//	printk("Cmnd->timeout %d\n", Cmnd->timeout);
-	// per Linux Scsi
-        Exchanges->fcExchange[ *fcExchangeIndex].timeOut = Cmnd->timeout;
-      }
-      else  // use our best guess, based on FC & device
-      {
-
-        if( Cmnd->SCp.Message == 1 ) // Tape device? (from INQUIRY)	
-	{
-	  // turn off our timeouts (for now...)
-          Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 0xFFFFFFFF; 
-	}
+	if (type == SCSI_IRE || type == SCSI_TRE || type == SCSI_IWE || type == SCSI_TWE)
+		FCP_SCSI_command = 1;
 	else
-	{
-          Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
-          Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // per SCSI req.
-	}
-      }
-
-  
-      // first, build FCP_CMND
-
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS FCP-CMND (not SEST index)
-                            // NOTE: unlike FC LinkService login frames,
-                            // normal SCSI commands are sent "open loop"
-      IRB_flags.DCM = 1;    // Disable completion message for Cmnd frame
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 64L;        // add len to LSB (header & CMND payload)
-
-      CMDfchs->d_id |= (0x06000000L);  // R_CTL = 6 for command
-
-             // TYPE[31-24] 8 for FCP SCSI
-             // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
-             //             valid RO
-      CMDfchs->f_ctl = 0x08210008L;
-      CMDfchs->seq_cnt = 0x0L;
-      // x_ID & data direction bit set later
-      CMDfchs->ox_rx_id = 0xFFFF;        // clear
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-
-
-                   // Now setup the SEST entry
-      pIRE = &fcChip->SEST->u[ *fcExchangeIndex ].IRE;
-
-      // fill out the IRE:
-      // VALid entry:Dir outbound:enable CM:enal INT:
-      pIRE->Seq_Accum = 0xCE000000L; // VAL,DIR inbound,DCM| INI,DAT,RSP
-
-      pIRE->reserved = 0L;
-      pIRE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
-      pIRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
-
-      pIRE->RSP_Addr = fcChip->SEST->base + 
-		((unsigned long)&fcChip->SEST->RspHDR[*fcExchangeIndex] - 
-			(unsigned long)fcChip->SEST);
-      
-                   // Do we need local or extended gather list?
-                   // depends on size - we can handle 3 len/addr pairs
-                   // locally.
-
-      fcp_dl = build_SEST_sgList( 
-	cpqfcHBAdata->PciDev,
-        &pIRE->SLen1, 
-        Cmnd,       // SCSI command Data desc. with S/G list
-        &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
-        &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
-      
-      
-      if( !fcp_dl ) // error building S/G list?
-      {
-	// It is permissible to have a ZERO LENGTH Read command.
-	// If there is the case, simply set fcp_dl (and Exp_Byte_Cnt)
-	// to 0 and continue.
-	if( Cmnd->request_bufflen == 0 )
-	{
-	  fcp_dl = 0; // no FC DATA frames expected
+		FCP_SCSI_command = 0;
 
+	// for commands that pass payload data (e.g. SCSI write)
+	// examine command struct - verify that the
+	// length of s/g buffers is adequate for total payload
+	// length (end of list is NULL address)
+
+	if (FCP_SCSI_command) {
+		if (Data)	// must have data descriptor (S/G list -- at least
+			// one address with at least 1 byte of data)
+		{
+			// something to do (later)?
+		}
+		else
+			return INVALID_ARGS;	// invalid DATA ptr
 	}
-	else
-	{
-          ulStatus = MEMPOOL_FAIL;
-          break;      // give up
-	}
-      }
-
-      // now that we know the S/G length, build CMND payload
-      build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
-
-      
-      if( sgPairs > 3 )  // need extended s/g list
-        pIRE->Buff_Off = 0x00000000; // DWord 4: extended s/g list, no offset
-      else
-        pIRE->Buff_Off = 0x80000000; // local data, no offset
-      
-      pIRE->Buff_Index = 0x0L;    // DWord 5: Buff_Index | Reserved
-
-      pIRE->Exp_RO  = 0x0L;       // DWord 6: Expected Rel. Offset
-
-      pIRE->Byte_Count = 0;  // DWord 7: filled in by TL on err
-      pIRE->reserved_ = 0;   // DWord 8: reserved
-                             // NOTE: 0 length READ is OK.
-      pIRE->Exp_Byte_Cnt = fcp_dl;// DWord 9: sum of scatter buffers
-      
-      break;
-
-
-
-
-                         // Fibre Channel SCSI 'responder' sequences...
-                         // (originator means 'target' in FCP-SCSI)
-    case SCSI_TWE: // TachLite Target Write Entry
-
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
-
-                       // first, build FCP_CMND
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (XFER_RDY)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
-
-      CMDfchs->d_id |= (0x05000000L);  // R_CTL = 5 for XFER_RDY
-
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] exchg responder, 1st seq, xfer S.I.
-                //             valid RO
-      CMDfchs->f_ctl = 0x08810008L;
-      CMDfchs->seq_cnt = 0x01000000; // sequence ID: df_ctl: sequence count
-                       // use originator (other port's) OX_ID
-      CMDfchs->ox_rx_id = InFCHS->ox_rx_id;     // we want upper 16 bits
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-                   // now, fill out FCP-RSP header
-                   // (use buffer inside SEST object)
-
-      rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
-      rspHDR->reserved = 0L; // must clear
-      rspHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
-      rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
-      rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] responder|last seq| xfer S.I.
-      rspHDR->f_ctl = 0x08910000L;
-      rspHDR->seq_cnt = 0x03000000;  // sequence ID
-      rspHDR->ox_rx_id = InFCHS->ox_rx_id; // gives us OX_ID
-      rspHDR->ro = 0x0L;    // relative offset (n/a)
-
-
-                   // Now setup the SEST entry
-                   
-      pTWE = &fcChip->SEST->u[ *fcExchangeIndex ].TWE;
-
-      // fill out the TWE:
-
-      // VALid entry:Dir outbound:enable CM:enal INT:
-      pTWE->Seq_Accum = 0xC4000000L;  // upper word flags
-      pTWE->reserved = 0L;
-      pTWE->Remote_Node_ID = 0L; // no more auto RSP frame! (TL/TS change)
-      pTWE->Remote_Node_ID |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
-      
-
-                   // Do we need local or extended gather list?
-                   // depends on size - we can handle 3 len/addr pairs
-                   // locally.
-
-      fcp_dl = build_SEST_sgList( 
-	cpqfcHBAdata->PciDev,
-        &pTWE->SLen1, 
-        Cmnd,       // S/G list
-        &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
-        &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
-      
-      
-      if( !fcp_dl ) // error building S/G list?
-      {
-        ulStatus = MEMPOOL_FAIL;
-        break;      // give up
-      }
-
-      // now that we know the S/G length, build CMND payload
-      build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
-
-      
-      if( sgPairs > 3 )  // need extended s/g list
-        pTWE->Buff_Off = 0x00000000; // extended s/g list, no offset
-      else
-        pTWE->Buff_Off = 0x80000000; // local data, no offset
-      
-      pTWE->Buff_Index = 0;     // Buff_Index | Link
-      pTWE->Exp_RO = 0;
-      pTWE->Byte_Count = 0;  // filled in by TL on err
-      pTWE->reserved_ = 0;
-      pTWE->Exp_Byte_Cnt = fcp_dl;// sum of scatter buffers
-      
-      break;
-
-
-
-
-
-
-    case SCSI_TRE: // TachLite Target Read Entry
-
-      // It doesn't make much sense for us to "time-out" a READ,
-      // but we'll use it for design consistency and internal error recovery.
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
-
-      // I/O request block settings...
-      *pIRB_flags = 0;      // clear IRB flags
-                                  // check PRLI (process login) info
-                                  // to see if Initiator Requires XFER_RDY
-                                  // if not, don't send one!
-                                  // { PRLI check...}
-      IRB_flags.SFA = 0;    // don't send XFER_RDY - start data
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
-
 
-      
-      // now, fill out FCP-DATA header
-                   // (use buffer inside SEST object)
-      dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
-
-      dataHDR->reserved = 0L; // must clear
-      dataHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn no UAM; no CLS,noLCr,no TS
-      dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
-      dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
-
-
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] exchg responder, not 1st seq, xfer S.I.
-                   //             valid RO
-      dataHDR->f_ctl = 0x08810008L;
-      dataHDR->seq_cnt = 0x01000000;  // sequence ID (no XRDY)
-      dataHDR->ox_rx_id = InFCHS->ox_rx_id & 0xFFFF0000; // we want upper 16 bits
-      dataHDR->ro = 0x0L;    // relative offset (n/a)
-
-                   // now, fill out FCP-RSP header
-                   // (use buffer inside SEST object)
-      rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
-
-      rspHDR->reserved = 0L; // must clear
-      rspHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
-      rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
-      rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] responder|last seq| xfer S.I.
-      rspHDR->f_ctl = 0x08910000L;
-      rspHDR->seq_cnt = 0x02000000;  // sequence ID: df_ctl: sequence count
-
-      rspHDR->ro = 0x0L;    // relative offset (n/a)
-
-
-      // Now setup the SEST entry
-      pTRE = &fcChip->SEST->u[ *fcExchangeIndex ].TRE;
-
-
-      // VALid entry:Dir outbound:enable CM:enal INT:
-      pTRE->Hdr_Len = 0x86010020L; // data frame Len always 32 bytes
-      pTRE->Hdr_Addr =  // bus address of dataHDR;
-            fcChip->SEST->base + 
-		((unsigned long)&fcChip->SEST->DataHDR[ *fcExchangeIndex ] -
-			(unsigned long)fcChip->SEST);
-	
-      pTRE->RSP_Len = 64L; // hdr+data (TL assisted RSP frame)
-      pTRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
-      pTRE->RSP_Addr = // bus address of rspHDR
-		fcChip->SEST->base + 
-			((unsigned long)&fcChip->SEST->RspHDR[ *fcExchangeIndex ] -
-				(unsigned long)fcChip->SEST);
-
-                   // Do we need local or extended gather list?
-                   // depends on size - we can handle 3 len/addr pairs
-                   // locally.
-
-      fcp_dl = build_SEST_sgList( 
-	cpqfcHBAdata->PciDev,
-        &pTRE->GLen1, 
-        Cmnd,       // S/G list
-        &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
-        &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
-      
-      
-      if( !fcp_dl ) // error building S/G list?
-      {
-        ulStatus = MEMPOOL_FAIL;
-        break;      // give up
-      }
-
-      // no payload or command to build -- READ doesn't need XRDY
-
-      
-      if( sgPairs > 3 )  // need extended s/g list
-        pTRE->Buff_Off = 0x78000000L; // extended data | (no offset)
-      else               // local data pointers (in SEST)
-        pTRE->Buff_Off = 0xf8000000L; // local data | (no offset)
-
-                                            // ULONG 5
-      pTRE->Buff_Index = 0L;   // Buff_Index | reserved
-      pTRE->reserved = 0x0L;   // DWord 6
-
-                                     // DWord 7: NOTE: zero length will
-                                     // hang TachLite!
-      pTRE->Data_Len = fcp_dl; // e.g. sum of scatter buffers
-
-      pTRE->reserved_ = 0L;     // DWord 8
-      pTRE->reserved__ = 0L;    // DWord 9
-
-      break;
+	// we can build an Exchange for later Queuing (on the TL chip)
+	// if an empty slot is available in the DevExt for this controller
+	// look for available Exchange slot...
 
+	if (type != FCP_RESPONSE && type != BLS_ABTS && type != BLS_ABTS_ACC)	// already have Exchange slot!
+		*fcExchangeIndex = FindFreeExchange(fcChip, type);
 
+	if (*fcExchangeIndex != -1)	// Exchange is available?
+	{
+		// assign tmp ptr (shorthand)
+		CMDfchs = &Exchanges->fcExchange[*fcExchangeIndex].fchs;
 
+		if (Cmnd != NULL)	// (necessary for ABTS cases)
+		{
+			Exchanges->fcExchange[*fcExchangeIndex].Cmnd = Cmnd;	// Linux Scsi
+			Exchanges->fcExchange[*fcExchangeIndex].pLoggedInPort = fcFindLoggedInPort(fcChip, Exchanges->fcExchange[*fcExchangeIndex].Cmnd,	// find Scsi Nexus
+												   0,	// DON'T search linked list for FC port id
+												   NULL,	// DON'T search linked list for FC WWN
+												   NULL);	// DON'T care about end of list
+		}
 
+		// Build the command frame header (& data) according
+		// to command type
 
-    
-
-    case FCP_RESPONSE: 
-                  // Target response frame: this sequence uses an OX/RX ID
-                  // pair from a completed SEST exchange.  We built most
-                  // of the response frame when we created the TWE/TRE.
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (RSP)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += sizeof(TachFCHDR_RSP);// add SFS len (header & RSP payload)
-      
-
-      Exchanges->fcExchange[ *fcExchangeIndex].type = 
-        FCP_RESPONSE; // change Exchange type to "response" phase
-
-      // take advantage of prior knowledge of OX/RX_ID pair from
-      // previous XFER outbound frame (still in fchs of exchange)
-      fcChip->SEST->RspHDR[ *fcExchangeIndex ].ox_rx_id = 
-        CMDfchs->ox_rx_id;
-
-      // Check the status of the DATA phase of the exchange so we can report
-      // status to the initiator
-      buildFCPstatus( fcChip, *fcExchangeIndex); // set RSP payload fields
-
-      memcpy(
-        CMDfchs,  // re-use same XFER fchs for Response frame
-        &fcChip->SEST->RspHDR[ *fcExchangeIndex ],
-        sizeof( TachFCHDR_RSP ));
-      
-        
-      break;
+		// fields common for all SFS frame types
+		CMDfchs->reserved = 0L;	// must clear
+		CMDfchs->sof_eof = 0x75000000L;	// SOFi3:EOFn  no UAM; LCr=0, no TS
+
+		// get the destination port_id from incoming FCHS
+		// (initialized before calling if we're Originator)
+		// Frame goes to port it was from - the source_id
+
+		CMDfchs->d_id = InFCHS->s_id & 0xFFFFFF;	// destination (add R_CTL later)
+		CMDfchs->s_id = fcChip->Registers.my_al_pa;	// CS_CTL = 0
+
+		// now enter command-specific fields
+		switch (type) {
+		case BLS_NOP:	// FC defined basic link service command NO-OP
+			// ensure unique X_IDs! (use tracking function)
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += 32L;	// add len to LSB (header only - no payload)
+
+			// TYPE[31-24] 00 Basic Link Service
+			// f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+			CMDfchs->d_id |= 0x80000000L;	// R_CTL = 80 for NOP (Basic Link Ser.)
+			CMDfchs->f_ctl = 0x00310000L;	// xchng originator, 1st seq,....
+			CMDfchs->seq_cnt = 0x0L;
+			CMDfchs->ox_rx_id = 0xFFFF;	// RX_ID for now; OX_ID on start
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+			CMDfchs->pl[0] = 0xaabbccddL;	// words 8-15 frame data payload (n/a)
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 1;	// seconds
+			// (NOP should complete ~instantly)
+			break;
+
+		case BLS_ABTS_ACC:	// Abort Sequence ACCept
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += 32 + 12;	// add len to LSB (header + 3 DWORD payload)
+
+			CMDfchs->d_id |= 0x84000000L;	// R_CTL = 84 for BASIC ACCept
+			// TYPE[31-24] 00 Basic Link Service
+			// f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
+			CMDfchs->f_ctl = 0x00910000L;	// xchnge responder, last seq, xfer SI
+			// CMDfchs->seq_id & count might be set from DataHdr?
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 5;	// seconds
+			// (Timeout in case of weird error)
+
+			// now set the ACCept payload...
+			ba_acc = (BA_ACC_PAYLOAD *) & CMDfchs->pl[0];
+			memset(ba_acc, 0, sizeof(BA_ACC_PAYLOAD));
+			// Since PLDA requires (only) entire Exchange aborts, we don't need
+			// to worry about what the last sequence was.
+
+			// We expect that a "target" task is accepting the abort, so we
+			// can use the OX/RX ID pair 
+			ba_acc->ox_rx_id = CMDfchs->ox_rx_id;
+
+			// source, dest, #bytes
+			BigEndianSwap((u8 *) & CMDfchs->ox_rx_id, (u8 *) & ba_acc->ox_rx_id, 4);
+
+			ba_acc->low_seq_cnt = 0;
+			ba_acc->high_seq_cnt = 0xFFFF;
+			break;
+
+		case BLS_ABTS_RJT:	// Abort Sequence ACCept
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += 32 + 12;	// add len to LSB (header + 3 DWORD payload)
+
+			CMDfchs->d_id |= 0x85000000L;	// R_CTL = 85 for BASIC ReJecT
+			// f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
+			// TYPE[31-24] 00 Basic Link Service
+			CMDfchs->f_ctl = 0x00910000L;	// xchnge responder, last seq, xfer SI
+			// CMDfchs->seq_id & count might be set from DataHdr?
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 5;	// seconds
+			// (Timeout in case of weird error)
+
+			CMDfchs->ox_rx_id = InFCHS->ox_rx_id;	// copy from sender!
+
+			// now set the ReJecT payload...
+			ba_rjt = (BA_RJT_PAYLOAD *) & CMDfchs->pl[0];
+			memset(ba_rjt, 0, sizeof(BA_RJT_PAYLOAD));
+
+			// We expect that a "target" task couldn't find the Exhange in the
+			// array of active exchanges, so we use a new LinkService X_ID.
+			// See Reject payload description in FC-PH (Rev 4.3), pg. 140
+			ba_rjt->reason_code = 0x09;	// "unable to perform command request"
+			ba_rjt->reason_explain = 0x03;	// invalid OX/RX ID pair
+			break;
+
+		case BLS_ABTS:	// FC defined basic link service command ABTS 
+			// Abort Sequence
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += 32L;	// add len to LSB (header only - no payload)
+
+			// TYPE[31-24] 00 Basic Link Service
+			// f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
+			CMDfchs->d_id |= 0x81000000L;	// R_CTL = 81 for ABTS
+			CMDfchs->f_ctl = 0x00110000L;	// xchnge originator, last seq, xfer SI
+			// CMDfchs->seq_id & count might be set from DataHdr?
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 2;	// seconds
+			// (ABTS must timeout when responder is gone)
+			break;
+
+		case FCS_NSR:	// Fabric Name Service Request
+			Exchanges->fcExchange[*fcExchangeIndex].reTries = 2;
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 2;	// seconds
+			// OX_ID, linked to Driver Transaction ID
+			// (fix-up at Queing time)
+			CMDfchs->ox_rx_id = 0xFFFF;	// RX_ID - Responder (target) to modify
+			// OX_ID set at ERQueing time
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += (32L + sizeof(NSR_PL));	// add len (header & NSR payload)
+			CMDfchs->d_id |= 0x02000000L;	// R_CTL = 02 for -
+			// Name Service Request: Unsolicited 
+			// TYPE[31-24] 01 Extended Link Service
+			// f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+			CMDfchs->f_ctl = 0x20210000L;
+			// OX_ID will be fixed-up at Tachyon enqueing time
+			CMDfchs->seq_cnt = 0;	// seq ID, DF_ctl, seq cnt
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+			BuildLinkServicePayload(fcChip, type, &CMDfchs->pl[0]);
+			break;
+
+		case ELS_PLOGI:	// FC-PH extended link service command Port Login
+			// (May, 2000)
+			// NOTE! This special case facilitates SANMark testing.  The SANMark
+			// test script for initialization-timeout.fcal.SANMark-1.fc
+			// "eats" the OPN() primitive without issuing an R_RDY, causing
+			// Tachyon to report LST (loop state timeout), which causes a
+			// LIP.  To avoid this, simply send out the frame (i.e. assuming a
+			// buffer credit of 1) without waiting for R_RDY.  Many FC devices
+			// (other than Tachyon) have been doing this for years.  We don't
+			// ever want to do this for non-Link Service frames unless the
+			// other device really did report non-zero login BB credit (i.e.
+			// in the PLOGI ACCept frame).
+//			CMDfchs->sof_eof |= 0x00000400L;  // LCr=1
+
+		case ELS_FDISC:	// Fabric Discovery (Login)
+		case ELS_FLOGI:	// Fabric Login
+		case ELS_SCR:	// Fabric State Change Registration
+		case ELS_LOGO:	// FC-PH extended link service command Port Logout
+		case ELS_PDISC:	// FC-PH extended link service cmnd Port Discovery
+		case ELS_PRLI:	// FC-PH extended link service cmnd Process Login
+			Exchanges->fcExchange[*fcExchangeIndex].reTries = 2;
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 2;	// seconds
+			// OX_ID, linked to Driver Transaction ID
+			// (fix-up at Queing time)
+			CMDfchs->ox_rx_id = 0xFFFF;	// RX_ID - Responder (target) to modify
+			// OX_ID set at ERQueing time
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+			SfsLen <<= 24;	// shift flags to MSB
+			if (type == ELS_LOGO)
+				SfsLen += (32L + 16L);	//  add len (header & PLOGI payload)
+			else if (type == ELS_PRLI)
+				SfsLen += (32L + 20L);	//  add len (header & PRLI payload)
+			else if (type == ELS_SCR)
+				SfsLen += (32L + sizeof(SCR_PL));	//  add len (header & SCR payload)
+			else
+				SfsLen += (32L + 116L);	//  add len (header & PLOGI payload)
+
+			CMDfchs->d_id |= 0x22000000L;	// R_CTL = 22 for -
+			// Extended Link_Data: Unsolicited Control
+			// TYPE[31-24] 01 Extended Link Service
+			// f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+			CMDfchs->f_ctl = 0x01210000L;
+			// OX_ID will be fixed-up at Tachyon enqueing time
+			CMDfchs->seq_cnt = 0;	// seq ID, DF_ctl, seq cnt
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+
+			BuildLinkServicePayload(fcChip, type, &CMDfchs->pl[0]);
+			break;
+
+		case ELS_LOGO_ACC:	// FC-PH extended link service logout accept
+		case ELS_RJT:	// extended link service reject (add reason)
+		case ELS_ACC:	// ext. link service generic accept
+		case ELS_PLOGI_ACC:	// ext. link service login accept (PLOGI or PDISC)
+		case ELS_PRLI_ACC:	// ext. link service process login accept
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 1;	// assume done
+			// ensure unique X_IDs! (use tracking function)
+			// OX_ID from initiator cmd
+			ox_ID = (u16) (InFCHS->ox_rx_id >> 16);
+			rx_ID = 0xFFFF;	// RX_ID, linked to Driver Exchange ID
+
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			if (type == ELS_RJT) {
+				SfsLen += (32L + 8L);	//  add len (header + payload)
+
+				// ELS_RJT reason codes (utilize unused "reserved" field)
+				CMDfchs->pl[0] = 1;
+				CMDfchs->pl[1] = InFCHS->reserved;
+
+			} else if ((type == ELS_LOGO_ACC) || (type == ELS_ACC))
+				SfsLen += (32L + 4L);	//  add len (header + payload)
+			else if (type == ELS_PLOGI_ACC)
+				SfsLen += (32L + 116L);	//  add len (header + payload)
+			else if (type == ELS_PRLI_ACC)
+				SfsLen += (32L + 20L);	//  add len (header + payload)
+
+			CMDfchs->d_id |= 0x23000000L;	// R_CTL = 23 for -
+			// Extended Link_Data: Control Reply
+			// TYPE[31-24] 01 Extended Link Service
+			// f_ctl[23:0] exchg responder, last seq, e_s, tsi
+			CMDfchs->f_ctl = 0x01990000L;
+			CMDfchs->seq_cnt = 0x0L;
+			CMDfchs->ox_rx_id = 0L;	// clear
+			CMDfchs->ox_rx_id = ox_ID;	// load upper 16 bits
+			CMDfchs->ox_rx_id <<= 16;	// shift them
+
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+
+			BuildLinkServicePayload(fcChip, type, &CMDfchs->pl[0]);
+			break;
+
+			// Fibre Channel SCSI 'originator' sequences...
+			// (originator means 'initiator' in FCP-SCSI)
+		case SCSI_IWE:	// TachLite Initiator Write Entry
+			{
+				PFC_LOGGEDIN_PORT pLoggedInPort = Exchanges->fcExchange[*fcExchangeIndex].pLoggedInPort;
+
+				Exchanges->fcExchange[*fcExchangeIndex].reTries = 1;
+				Exchanges->fcExchange[*fcExchangeIndex].timeOut = 7;	// FC2 timeout
+
+				// first, build FCP_CMND
+				// unique X_ID fix-ups in StartExchange 
+
+				*pIRB_flags = 0;	// clear IRB flags
+				IRB_flags.SFA = 1;	// send SFS FCP-CMND (not SEST index)
+
+				// NOTE: unlike FC LinkService login frames, normal
+				// SCSI commands are sent without outgoing verification
+				IRB_flags.DCM = 1;	// Disable completion message for Cmnd frame
+				SfsLen = *pIRB_flags;
+
+				SfsLen <<= 24;	// shift flags to MSB
+				SfsLen += 64L;	// add len to LSB (header & CMND payload)
+
+				CMDfchs->d_id |= (0x06000000L);	// R_CTL = 6 for command
+
+				// TYPE[31-24] 8 for FCP SCSI
+				// f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+				//             valid RO
+				CMDfchs->f_ctl = 0x08210008L;
+				CMDfchs->seq_cnt = 0x0L;
+				CMDfchs->ox_rx_id = 0L;	// clear for now (-or- in later)
+				CMDfchs->ro = 0x0L;	// relative offset (n/a)
+
+				// now, fill out FCP-DATA header
+				// (use buffer inside SEST object)
+				dataHDR = &fcChip->SEST->DataHDR[*fcExchangeIndex];
+				dataHDR->reserved = 0L;	// must clear
+				dataHDR->sof_eof = 0x75002000L;	// SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
+				dataHDR->d_id = (InFCHS->s_id | 0x01000000L);	// R_CTL= FCP_DATA
+				dataHDR->s_id = fcChip->Registers.my_al_pa;	// CS_CTL = 0
+				// TYPE[31-24] 8 for FCP SCSI
+				// f_ctl[23:0] xfer S.I.| valid RO
+				dataHDR->f_ctl = 0x08010008L;
+				dataHDR->seq_cnt = 0x02000000L;	// sequence ID: df_ctl : seqence count
+				dataHDR->ox_rx_id = 0L;	// clear; fix-up dataHDR fields later
+				dataHDR->ro = 0x0L;	// relative offset (n/a)
+
+				// Now setup the SEST entry
+				pIWE = &fcChip->SEST->u[*fcExchangeIndex].IWE;
+
+				// fill out the IWE:
+
+				// VALid entry:Dir outbound:DCM:enable CM:enal INT: FC frame len
+				pIWE->Hdr_Len = 0x8e000020L;	// data frame Len always 32 bytes
+
+
+				// from login parameters with other port, what's the largest frame
+				// we can send? 
+				if (pLoggedInPort == NULL) {
+					ulStatus = INVALID_ARGS;	// failed! give up
+					break;
+				}
+				if (pLoggedInPort->rx_data_size >= 2048)
+					fl = 0x00020000;	// 2048 code (only support 1024!)
+				else if (pLoggedInPort->rx_data_size >= 1024)
+					fl = 0x00020000;	// 1024 code
+				else if (pLoggedInPort->rx_data_size >= 512)
+					fl = 0x00010000;	// 512 code
+				else
+					fl = 0;	// 128 bytes -- should never happen
+
+
+				pIWE->Hdr_Len |= fl;	// add xmit FC frame len for data phase
+				pIWE->Hdr_Addr = fcChip->SEST->base + ((unsigned long) &fcChip->SEST->DataHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
+
+				pIWE->RSP_Len = sizeof(TachFCHDR_RSP);	// hdr+data (recv'd RSP frame)
+				pIWE->RSP_Len |= (InFCHS->s_id << 8);	// MS 24 bits Remote_ID
+
+				memset(&fcChip->SEST->RspHDR[*fcExchangeIndex].pl, 0, sizeof(FCP_STATUS_RESPONSE));	// clear out previous status
+
+				pIWE->RSP_Addr = fcChip->SEST->base + ((unsigned long) &fcChip->SEST->RspHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
+
+				// Do we need local or extended gather list?
+				// depends on size - we can handle 3 len/addr pairs
+				// locally.
+
+				fcp_dl = build_SEST_sgList(dev->PciDev, &pIWE->GLen1, Cmnd,	// S/G list
+							   &sgPairs,	// return # of pairs in S/G list (from "Data" descriptor)
+							   &fcChip->SEST->sgPages[*fcExchangeIndex]);	// (for Freeing later)
+
+				if (!fcp_dl)	// error building S/G list?
+				{
+					ulStatus = MEMPOOL_FAIL;
+					break;	// give up
+				}
+				// Now that we know total data length in
+				// the passed S/G buffer, set FCP CMND frame
+				build_FCP_payload(Cmnd, (u8 *) & CMDfchs->pl[0], type, fcp_dl);
+
+
+
+				if (sgPairs > 3)	// need extended s/g list
+					pIWE->Buff_Off = 0x78000000L;	// extended data | (no offset)
+				else	// local data pointers (in SEST)
+					pIWE->Buff_Off = 0xf8000000L;	// local data | (no offset)
+
+				// u32 5
+				pIWE->Link = 0x0000ffffL;	// Buff_Index | Link
+
+				pIWE->RX_ID = 0x0L;	// DWord 6: RX_ID set by target XFER_RDY
+
+				// DWord 7
+				pIWE->Data_Len = 0L;	// TL enters rcv'd XFER_RDY BURST_LEN
+				pIWE->Exp_RO = 0L;	// DWord 8
+				// DWord 9
+				pIWE->Exp_Byte_Cnt = fcp_dl;	// sum of gather buffers
+			}
+			break;
 
-    default:
-      printk("cpqfcTS: don't know how to build FC type: %Xh(%d)\n", type,type);
-      break;
+		case SCSI_IRE:	// TachLite Initiator Read Entry
+			if (Cmnd->timeout != 0) {
+//      printk("Cmnd->timeout %d\n", Cmnd->timeout);
+				// per Linux Scsi
+				Exchanges->fcExchange[*fcExchangeIndex].timeOut = Cmnd->timeout;
+			} else	// use our best guess, based on FC & device
+			{
+
+				if (Cmnd->SCp.Message == 1)	// Tape device? (from INQUIRY)     
+				{
+					// turn off our timeouts (for now...)
+					Exchanges->fcExchange[*fcExchangeIndex].timeOut = 0xFFFFFFFF;
+				} else {
+					Exchanges->fcExchange[*fcExchangeIndex].reTries = 1;
+					Exchanges->fcExchange[*fcExchangeIndex].timeOut = 7;	// per SCSI req.
+				}
+			}
+			// first, build FCP_CMND
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS FCP-CMND (not SEST index)
+			// NOTE: unlike FC LinkService login frames,
+			// normal SCSI commands are sent "open loop"
+			IRB_flags.DCM = 1;	// Disable completion message for Cmnd frame
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += 64L;	// add len to LSB (header & CMND payload)
+
+			CMDfchs->d_id |= (0x06000000L);	// R_CTL = 6 for command
+
+			// TYPE[31-24] 8 for FCP SCSI
+			// f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+			//             valid RO
+			CMDfchs->f_ctl = 0x08210008L;
+			CMDfchs->seq_cnt = 0x0L;
+			// x_ID & data direction bit set later
+			CMDfchs->ox_rx_id = 0xFFFF;	// clear
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+			// Now setup the SEST entry
+			pIRE = &fcChip->SEST->u[*fcExchangeIndex].IRE;
+			// fill out the IRE:
+			// VALid entry:Dir outbound:enable CM:enal INT:
+			pIRE->Seq_Accum = 0xCE000000L;	// VAL,DIR inbound,DCM| INI,DAT,RSP
+
+			pIRE->reserved = 0L;
+			pIRE->RSP_Len = sizeof(TachFCHDR_RSP);	// hdr+data (recv'd RSP frame)
+			pIRE->RSP_Len |= (InFCHS->s_id << 8);	// MS 24 bits Remote_ID
+
+			pIRE->RSP_Addr = fcChip->SEST->base + ((unsigned long) &fcChip->SEST->RspHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
+
+			// Do we need local or extended gather list?
+			// depends on size - we can handle 3 len/addr pairs
+			// locally.
+
+			fcp_dl = build_SEST_sgList(dev->PciDev, &pIRE->SLen1, Cmnd,	// SCSI command Data desc. with S/G list
+						   &sgPairs,	// return # of pairs in S/G list (from "Data" descriptor)
+						   &fcChip->SEST->sgPages[*fcExchangeIndex]);	// (for Freeing later)
+
+
+			if (!fcp_dl)	// error building S/G list?
+			{
+				// It is permissible to have a ZERO LENGTH Read command.
+				// If there is the case, simply set fcp_dl (and Exp_Byte_Cnt)
+				// to 0 and continue.
+				if (Cmnd->request_bufflen == 0) {
+					fcp_dl = 0;	// no FC DATA frames expected
+
+				} else {
+					ulStatus = MEMPOOL_FAIL;
+					break;	// give up
+				}
+			}
+			// now that we know the S/G length, build CMND payload
+			build_FCP_payload(Cmnd, (u8 *) & CMDfchs->pl[0], type, fcp_dl);
 
-    }
 
-    
-    
-    if( !ulStatus)  // no errors above?
-    {
-      // FCHS is built; now build IRB
+			if (sgPairs > 3)	// need extended s/g list
+				pIRE->Buff_Off = 0x00000000;	// DWord 4: extended s/g list, no offset
+			else
+				pIRE->Buff_Off = 0x80000000;	// local data, no offset
+
+			pIRE->Buff_Index = 0x0L;	// DWord 5: Buff_Index | Reserved
+
+			pIRE->Exp_RO = 0x0L;	// DWord 6: Expected Rel. Offset
+
+			pIRE->Byte_Count = 0;	// DWord 7: filled in by TL on err
+			pIRE->reserved_ = 0;	// DWord 8: reserved
+			// NOTE: 0 length READ is OK.
+			pIRE->Exp_Byte_Cnt = fcp_dl;	// DWord 9: sum of scatter buffers
+			break;
+
+			// Fibre Channel SCSI 'responder' sequences...
+			// (originator means 'target' in FCP-SCSI)
+		case SCSI_TWE:	// TachLite Target Write Entry
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 10;	// per SCSI req.
+			// first, build FCP_CMND
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (XFER_RDY)
+			SfsLen = *pIRB_flags;
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += (32L + 12L);	// add SFS len (header & XFER_RDY payload)
+
+			CMDfchs->d_id |= (0x05000000L);	// R_CTL = 5 for XFER_RDY
+
+			// TYPE[31-24] 8 for FCP SCSI
+			// f_ctl[23:0] exchg responder, 1st seq, xfer S.I.
+			//             valid RO
+			CMDfchs->f_ctl = 0x08810008L;
+			CMDfchs->seq_cnt = 0x01000000;	// sequence ID: df_ctl: sequence count
+			// use originator (other port's) OX_ID
+			CMDfchs->ox_rx_id = InFCHS->ox_rx_id;	// we want upper 16 bits
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+
+			// now, fill out FCP-RSP header
+			// (use buffer inside SEST object)
+
+			rspHDR = &fcChip->SEST->RspHDR[*fcExchangeIndex];
+			rspHDR->reserved = 0L;	// must clear
+			rspHDR->sof_eof = 0x75000000L;	// SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
+			rspHDR->d_id = (InFCHS->s_id | 0x07000000L);	// R_CTL= FCP_RSP
+			rspHDR->s_id = fcChip->Registers.my_al_pa;	// CS_CTL = 0
+			// TYPE[31-24] 8 for FCP SCSI
+			// f_ctl[23:0] responder|last seq| xfer S.I.
+			rspHDR->f_ctl = 0x08910000L;
+			rspHDR->seq_cnt = 0x03000000;	// sequence ID
+			rspHDR->ox_rx_id = InFCHS->ox_rx_id;	// gives us OX_ID
+			rspHDR->ro = 0x0L;	// relative offset (n/a)
+			// Now setup the SEST entry
+
+			pTWE = &fcChip->SEST->u[*fcExchangeIndex].TWE;
+			// fill out the TWE:
+
+			// VALid entry:Dir outbound:enable CM:enal INT:
+			pTWE->Seq_Accum = 0xC4000000L;	// upper word flags
+			pTWE->reserved = 0L;
+			pTWE->Remote_Node_ID = 0L;	// no more auto RSP frame! (TL/TS change)
+			pTWE->Remote_Node_ID |= (InFCHS->s_id << 8);	// MS 24 bits Remote_ID
+
+			// Do we need local or extended gather list?
+			// depends on size - we can handle 3 len/addr pairs
+			// locally.
+
+			fcp_dl = build_SEST_sgList(dev->PciDev, &pTWE->SLen1, Cmnd,	// S/G list
+						   &sgPairs,	// return # of pairs in S/G list (from "Data" descriptor)
+						   &fcChip->SEST->sgPages[*fcExchangeIndex]);	// (for Freeing later)
+
+			if (!fcp_dl)	// error building S/G list?
+			{
+				ulStatus = MEMPOOL_FAIL;
+				break;	// give up
+			}
+			// now that we know the S/G length, build CMND payload
+			build_FCP_payload(Cmnd, (u8 *) & CMDfchs->pl[0], type, fcp_dl);
 
-      // link the just built FCHS (the "command") to the IRB entry 
-      // for this Exchange.
-      pIRB = &Exchanges->fcExchange[ *fcExchangeIndex].IRB; 
-    
-                          // len & flags according to command type above
-      pIRB->Req_A_SFS_Len = SfsLen;  // includes IRB flags & len
-      pIRB->Req_A_SFS_Addr = // TL needs physical addr of frame to send
-		fcChip->exch_dma_handle + (unsigned long)CMDfchs - 
-			(unsigned long)Exchanges;
-
-      pIRB->Req_A_SFS_D_ID = CMDfchs->d_id << 8; // Dest_ID must be consistent!
-
-    // Exchange is complete except for "fix-up" fields to be set
-    // at Tachyon Queuing time:
-    //    IRB->Req_A_Trans_ID (OX_ID/ RX_ID):  
-    //        for SEST entry, lower bits correspond to actual FC Exchange ID
-    //    fchs->OX_ID or RX_ID
-    }
-    else
-    {
-#ifdef DBG     
-      printk( "FC Error: SEST build Pool Allocation failed\n");
+			if (sgPairs > 3)	// need extended s/g list
+				pTWE->Buff_Off = 0x00000000;	// extended s/g list, no offset
+			else
+				pTWE->Buff_Off = 0x80000000;	// local data, no offset
+
+			pTWE->Buff_Index = 0;	// Buff_Index | Link
+			pTWE->Exp_RO = 0;
+			pTWE->Byte_Count = 0;	// filled in by TL on err
+			pTWE->reserved_ = 0;
+			pTWE->Exp_Byte_Cnt = fcp_dl;	// sum of scatter buffers
+			break;
+
+		case SCSI_TRE:	// TachLite Target Read Entry
+			// It doesn't make much sense for us to "time-out" a READ,
+			// but we'll use it for design consistency and internal error recovery.
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 10;	// per SCSI req.
+			// I/O request block settings...
+			*pIRB_flags = 0;	// clear IRB flags
+			// check PRLI (process login) info
+			// to see if Initiator Requires XFER_RDY
+			// if not, don't send one!
+			// { PRLI check...}
+			IRB_flags.SFA = 0;	// don't send XFER_RDY - start data
+			SfsLen = *pIRB_flags;
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += (32L + 12L);	// add SFS len (header & XFER_RDY payload)
+
+			// now, fill out FCP-DATA header
+			// (use buffer inside SEST object)
+			dataHDR = &fcChip->SEST->DataHDR[*fcExchangeIndex];
+
+			dataHDR->reserved = 0L;	// must clear
+			dataHDR->sof_eof = 0x75000000L;	// SOFi3:EOFn no UAM; no CLS,noLCr,no TS
+			dataHDR->d_id = (InFCHS->s_id | 0x01000000L);	// R_CTL= FCP_DATA
+			dataHDR->s_id = fcChip->Registers.my_al_pa;	// CS_CTL = 0
+
+			// TYPE[31-24] 8 for FCP SCSI
+			// f_ctl[23:0] exchg responder, not 1st seq, xfer S.I.
+			//             valid RO
+			dataHDR->f_ctl = 0x08810008L;
+			dataHDR->seq_cnt = 0x01000000;	// sequence ID (no XRDY)
+			dataHDR->ox_rx_id = InFCHS->ox_rx_id & 0xFFFF0000;	// we want upper 16 bits
+			dataHDR->ro = 0x0L;	// relative offset (n/a)
+
+			// now, fill out FCP-RSP header
+			// (use buffer inside SEST object)
+			rspHDR = &fcChip->SEST->RspHDR[*fcExchangeIndex];
+
+			rspHDR->reserved = 0L;	// must clear
+			rspHDR->sof_eof = 0x75000000L;	// SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
+			rspHDR->d_id = (InFCHS->s_id | 0x07000000L);	// R_CTL= FCP_RSP
+			rspHDR->s_id = fcChip->Registers.my_al_pa;	// CS_CTL = 0
+			// TYPE[31-24] 8 for FCP SCSI
+			// f_ctl[23:0] responder|last seq| xfer S.I.
+			rspHDR->f_ctl = 0x08910000L;
+			rspHDR->seq_cnt = 0x02000000;	// sequence ID: df_ctl: sequence count
+			rspHDR->ro = 0x0L;	// relative offset (n/a)
+
+			// Now setup the SEST entry
+			pTRE = &fcChip->SEST->u[*fcExchangeIndex].TRE;
+
+			// VALid entry:Dir outbound:enable CM:enal INT:
+			pTRE->Hdr_Len = 0x86010020L;	// data frame Len always 32 bytes
+			pTRE->Hdr_Addr =	// bus address of dataHDR;
+			    fcChip->SEST->base + ((unsigned long) &fcChip->SEST->DataHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
+
+			pTRE->RSP_Len = 64L;	// hdr+data (TL assisted RSP frame)
+			pTRE->RSP_Len |= (InFCHS->s_id << 8);	// MS 24 bits Remote_ID
+			pTRE->RSP_Addr =	// bus address of rspHDR
+			    fcChip->SEST->base + ((unsigned long) &fcChip->SEST->RspHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
+
+			// Do we need local or extended gather list?
+			// depends on size - we can handle 3 len/addr pairs
+			// locally.
+
+			fcp_dl = build_SEST_sgList(dev->PciDev, &pTRE->GLen1, Cmnd,	// S/G list
+						   &sgPairs,	// return # of pairs in S/G list (from "Data" descriptor)
+						   &fcChip->SEST->sgPages[*fcExchangeIndex]);	// (for Freeing later)
+
+			if (!fcp_dl)	// error building S/G list?
+			{
+				ulStatus = MEMPOOL_FAIL;
+				break;	// give up
+			}
+			// no payload or command to build -- READ doesn't need XRDY
+			if (sgPairs > 3)	// need extended s/g list
+				pTRE->Buff_Off = 0x78000000L;	// extended data | (no offset)
+			else	// local data pointers (in SEST)
+				pTRE->Buff_Off = 0xf8000000L;	// local data | (no offset)
+
+			// u32 5
+			pTRE->Buff_Index = 0L;	// Buff_Index | reserved
+			pTRE->reserved = 0x0L;	// DWord 6
+
+			// DWord 7: NOTE: zero length will
+			// hang TachLite!
+			pTRE->Data_Len = fcp_dl;	// e.g. sum of scatter buffers
+
+			pTRE->reserved_ = 0L;	// DWord 8
+			pTRE->reserved__ = 0L;	// DWord 9
+
+			break;
+
+		case FCP_RESPONSE:
+			// Target response frame: this sequence uses an OX/RX ID
+			// pair from a completed SEST exchange.  We built most
+			// of the response frame when we created the TWE/TRE.
+
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (RSP)
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += sizeof(TachFCHDR_RSP);	// add SFS len (header & RSP payload)
+			Exchanges->fcExchange[*fcExchangeIndex].type = FCP_RESPONSE;	// change Exchange type to "response" phase
+
+			// take advantage of prior knowledge of OX/RX_ID pair from
+			// previous XFER outbound frame (still in fchs of exchange)
+			fcChip->SEST->RspHDR[*fcExchangeIndex].ox_rx_id = CMDfchs->ox_rx_id;
+
+			// Check the status of the DATA phase of the exchange so we can report
+			// status to the initiator
+			buildFCPstatus(fcChip, *fcExchangeIndex);	// set RSP payload fields
+
+			memcpy(CMDfchs,	// re-use same XFER fchs for Response frame
+			       &fcChip->SEST->RspHDR[*fcExchangeIndex], sizeof(TachFCHDR_RSP));
+			break;
+
+		default:
+			printk("cpqfcTS: don't know how to build FC type: %Xh(%d)\n", type, type);
+			break;
+		}
+		if (!ulStatus)	// no errors above?
+		{
+			// FCHS is built; now build IRB
+
+			// link the just built FCHS (the "command") to the IRB entry 
+			// for this Exchange.
+			pIRB = &Exchanges->fcExchange[*fcExchangeIndex].IRB;
+
+			// len & flags according to command type above
+			pIRB->Req_A_SFS_Len = SfsLen;	// includes IRB flags & len
+			pIRB->Req_A_SFS_Addr =	// TL needs physical addr of frame to send
+			    fcChip->exch_dma_handle + (unsigned long) CMDfchs - (unsigned long) Exchanges;
+
+			pIRB->Req_A_SFS_D_ID = CMDfchs->d_id << 8;	// Dest_ID must be consistent!
+
+			// Exchange is complete except for "fix-up" fields to be set
+			// at Tachyon Queuing time:
+			//    IRB->Req_A_Trans_ID (OX_ID/ RX_ID):  
+			//        for SEST entry, lower bits correspond to actual FC Exchange ID
+			//    fchs->OX_ID or RX_ID
+		} else {
+#ifdef DBG
+			printk("FC Error: SEST build Pool Allocation failed\n");
 #endif
-      // return resources...
-      cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, *fcExchangeIndex);  // SEST build failed
-    }
-  }
-  else  // no Exchanges available
-  {
-    ulStatus = SEST_FULL;
-    printk( "FC Error: no fcExchanges available\n");
-  }
-  return ulStatus;
+			// return resources...
+			cpqfcTSCompleteExchange(dev->PciDev, fcChip, *fcExchangeIndex);	// SEST build failed
+		}
+	} else			// no Exchanges available
+	{
+		ulStatus = SEST_FULL;
+		printk("FC Error: no fcExchanges available\n");
+	}
+	return ulStatus;
 }
 
-
-
-
-
-
 // set RSP payload fields
-static void  buildFCPstatus( PTACHYON fcChip, ULONG ExchangeID) 
+static void buildFCPstatus(PTACHYON fcChip, u32 ExchangeID)
 {
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID];  // shorthand
-  PFCP_STATUS_RESPONSE pFcpStatus;
-  
-  memset( &fcChip->SEST->RspHDR[ ExchangeID ].pl, 0,
-    sizeof( FCP_STATUS_RESPONSE) );
-  if( pExchange->status ) // something wrong?
-  {
-    pFcpStatus = (PFCP_STATUS_RESPONSE)  // cast RSP buffer for this xchng
-      &fcChip->SEST->RspHDR[ ExchangeID ].pl;
-    if( pExchange->status & COUNT_ERROR )
-    {
-      
-      // set FCP response len valid (so we can report count error)
-      pFcpStatus->fcp_status |= FCP_RSP_LEN_VALID;
-      pFcpStatus->fcp_rsp_len = 0x04000000;  // 4 byte len (BIG Endian)
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID];	// shorthand
+	PFCP_STATUS_RESPONSE pFcpStatus;
 
-      pFcpStatus->fcp_rsp_info = FCP_DATA_LEN_NOT_BURST_LEN; // RSP_CODE
-    }
-  }
+	memset(&fcChip->SEST->RspHDR[ExchangeID].pl, 0, sizeof(FCP_STATUS_RESPONSE));
+	if (pExchange->status)	// something wrong?
+	{
+		pFcpStatus = (PFCP_STATUS_RESPONSE)	// cast RSP buffer for this xchng
+		    & fcChip->SEST->RspHDR[ExchangeID].pl;
+		if (pExchange->status & COUNT_ERROR) {
+
+			// set FCP response len valid (so we can report count error)
+			pFcpStatus->fcp_status |= FCP_RSP_LEN_VALID;
+			pFcpStatus->fcp_rsp_len = 0x04000000;	// 4 byte len (BIG Endian)
+
+			pFcpStatus->fcp_rsp_info = FCP_DATA_LEN_NOT_BURST_LEN;	// RSP_CODE
+		}
+	}
 }
 
 
-static dma_addr_t 
-cpqfc_pci_map_sg_page(
-    		struct pci_dev *pcidev,
-		ULONG *hw_paddr, 	// where to put phys addr for HW use
-		void *sgp_vaddr,	// the virtual address of the sg page 
-	 	dma_addr_t *umap_paddr,	// where to put phys addr for unmap
-		unsigned int *maplen,	// where to store sg entry length
-		int PairCount)		// number of sg pairs used in the page.	
+static dma_addr_t cpqfc_pci_map_sg_page(struct pci_dev *pcidev, u32 * hw_paddr,	// where to put phys addr for HW use
+					void *sgp_vaddr,	// the virtual address of the sg page 
+					dma_addr_t * umap_paddr,	// where to put phys addr for unmap
+					unsigned int *maplen,	// where to store sg entry length
+					int PairCount)	// number of sg pairs used in the page. 
 {
 	unsigned long aligned_addr = (unsigned long) sgp_vaddr;
 
 	*maplen = PairCount * 8;
-        aligned_addr += TL_EXT_SG_PAGE_BYTELEN;
-        aligned_addr &= ~(TL_EXT_SG_PAGE_BYTELEN -1);
-	
-	*umap_paddr = pci_map_single(pcidev, (void *) aligned_addr, 
-				*maplen, PCI_DMA_TODEVICE);
-	*hw_paddr = (ULONG) *umap_paddr;
+	aligned_addr += TL_EXT_SG_PAGE_BYTELEN;
+	aligned_addr &= ~(TL_EXT_SG_PAGE_BYTELEN - 1);
+
+	*umap_paddr = pci_map_single(pcidev, (void *) aligned_addr, *maplen, PCI_DMA_TODEVICE);
+	*hw_paddr = (u32) * umap_paddr;
 
 #       if BITS_PER_LONG > 32
-       		if( *umap_paddr >>32 ) {
-       	  		printk("cqpfcTS:Tach SG DMA addr %p>32 bits\n", 
-	  			(void*)umap_paddr);
-       			return 0;
-       		}
+	if (*umap_paddr >> 32) {
+		printk("cqpfcTS:Tach SG DMA addr %p>32 bits\n", (void *) umap_paddr);
+		return 0;
+	}
 #       endif
 	return *umap_paddr;
 }
 
-static void
-cpqfc_undo_SEST_mappings(struct pci_dev *pcidev,
-			unsigned long contigaddr, int len, int dir,
-  			struct scatterlist *sgl, int use_sg,
-    			PSGPAGES *sgPages_head,
-			int allocated_pages)
+static void cpqfc_undo_SEST_mappings(struct pci_dev *pcidev, unsigned long contigaddr, int len, int dir, struct scatterlist *sgl, int use_sg, PSGPAGES * sgPages_head, int allocated_pages)
 {
 	PSGPAGES i, next;
 
@@ -5136,14 +4141,12 @@
 	if (sgl != NULL)
 		pci_unmap_sg(pcidev, sgl, use_sg, dir);
 
-	for (i=*sgPages_head; i != NULL ;i = next)
-	{
-		pci_unmap_single(pcidev, i->busaddr, i->maplen, 
-			scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
-		i->busaddr = (dma_addr_t) NULL; 
-		i->maplen = 0L; 
+	for (i = *sgPages_head; i != NULL; i = next) {
+		pci_unmap_single(pcidev, i->busaddr, i->maplen, scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
+		i->busaddr = (dma_addr_t) NULL;
+		i->maplen = 0L;
 		next = i->next;
-		kfree(i); 
+		kfree(i);
 	}
 	*sgPages_head = NULL;
 }
@@ -5166,380 +4169,331 @@
 
 static int ap_hi_water = TL_DANGER_SGPAGES;
 
-static ULONG build_SEST_sgList( 
-    struct pci_dev *pcidev,
-    ULONG *SESTalPairStart,  // the 3 len/address buffers in SEST
-    Scsi_Cmnd *Cmnd,
-    ULONG *sgPairs, 
-    PSGPAGES *sgPages_head)  // link list of TL Ext. S/G pages from O/S Pool
-    
+static u32 build_SEST_sgList(struct pci_dev *pcidev, u32 * SESTalPairStart,	// the 3 len/address buffers in SEST
+			       Scsi_Cmnd * Cmnd, u32 * sgPairs, PSGPAGES * sgPages_head)	// link list of TL Ext. S/G pages from O/S Pool
 {
-  ULONG i, AllocatedPages=0; // Tach Ext. S/G page allocations
-  ULONG* alPair = SESTalPairStart;
-  ULONG* ext_sg_page_phys_addr_place = NULL;
-  int PairCount;
-  unsigned long ulBuff, contigaddr;
-  ULONG total_data_len=0; // (in bytes)
-  ULONG bytes_to_go = Cmnd->request_bufflen; // total xfer (S/G sum)
-  ULONG thisMappingLen;
-  struct scatterlist *sgl = NULL;  // S/G list (Linux format)
-  int sg_count, totalsgs; 
-  dma_addr_t busaddr;
-  unsigned long thislen, offset;
-  PSGPAGES *sgpage = sgPages_head;
-  PSGPAGES prev_page = NULL;
-
-# define WE_HAVE_SG_LIST (sgl != (unsigned long) NULL)
-  contigaddr = (unsigned long) NULL;
-
-  if( !Cmnd->use_sg )  // no S/G list?
-  {
-	if (bytes_to_go <= TL_MAX_SG_ELEM_LEN)
-	{
-    		*sgPairs = 1;	// use "local" S/G pair in SEST entry
-				// (for now, ignore address bits above #31)
+	u32 i, AllocatedPages = 0;	// Tach Ext. S/G page allocations
+	u32 *alPair = SESTalPairStart;
+	u32 *ext_sg_page_phys_addr_place = NULL;
+	int PairCount;
+	unsigned long ulBuff, contigaddr;
+	u32 total_data_len = 0;	// (in bytes)
+	u32 bytes_to_go = Cmnd->request_bufflen;	// total xfer (S/G sum)
+	u32 thisMappingLen;
+	struct scatterlist *sgl = NULL;	// S/G list (Linux format)
+	int sg_count, totalsgs;
+	dma_addr_t busaddr;
+	unsigned long thislen, offset;
+	PSGPAGES *sgpage = sgPages_head;
+	PSGPAGES prev_page = NULL;
 
-		*alPair++ = bytes_to_go; // bits 18-0, length
+# define WE_HAVE_SG_LIST (sgl != (unsigned long) NULL)
+	contigaddr = (unsigned long) NULL;
 
-		if (bytes_to_go != 0) {
-			contigaddr = ulBuff = pci_map_single(pcidev, 
-				Cmnd->request_buffer, 
-				Cmnd->request_bufflen,
-				scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
-			// printk("ms %p ", ulBuff);
-		}
-		else {
-			// No data transfer, (e.g.: Test Unit Ready)
-			// printk("btg=0 ");
-			*sgPairs = 0;
-			memset(alPair, 0, sizeof(*alPair));
-			return 0;
-		}
+	if (!Cmnd->use_sg)	// no S/G list?
+	{
+		if (bytes_to_go <= TL_MAX_SG_ELEM_LEN) {
+			*sgPairs = 1;	// use "local" S/G pair in SEST entry
+			// (for now, ignore address bits above #31)
+
+			*alPair++ = bytes_to_go;	// bits 18-0, length
+
+			if (bytes_to_go != 0) {
+				contigaddr = ulBuff = pci_map_single(pcidev, Cmnd->request_buffer, Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+				// printk("ms %p ", ulBuff);
+			} else {
+				// No data transfer, (e.g.: Test Unit Ready)
+				// printk("btg=0 ");
+				*sgPairs = 0;
+				memset(alPair, 0, sizeof(*alPair));
+				return 0;
+			}
 
 #		if BITS_PER_LONG > 32
-    			if( ulBuff >>32 ) {
-      				printk("FATAL! Tachyon DMA address %p "
-					"exceeds 32 bits\n", (void*)ulBuff );
-      				return 0;
-    			}
+			if (ulBuff >> 32) {
+				printk("FATAL! Tachyon DMA address %p " "exceeds 32 bits\n", (void *) ulBuff);
+				return 0;
+			}
 #		endif
-    		*alPair = (ULONG)ulBuff;      
-    		return bytes_to_go;
-	} 
-	else	// We have a single large (too big) contiguous buffer.
-	{	// We will have to break it up.  We'll use the scatter
-		// gather code way below, but use contigaddr instead
-		// of sg_dma_addr(). (this is a very rare case).
-
-		unsigned long btg;
-		contigaddr = pci_map_single(pcidev, Cmnd->request_buffer, 
-				Cmnd->request_bufflen,
-				scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
-
-		// printk("contigaddr = %p, len = %d\n", 
-		//	(void *) contigaddr, bytes_to_go);
-		totalsgs = 0;
-		for (btg = bytes_to_go; btg > 0; ) {
-			btg -= ( btg > TL_MAX_SG_ELEM_LEN ? 
-				TL_MAX_SG_ELEM_LEN : btg );
-			totalsgs++;
-		}
-		sgl = NULL;
-		*sgPairs = totalsgs;
-	}
-  }
-  else  // we do have a scatter gather list
-  {
-	// [TBD - update for Linux to support > 32 bits addressing]
-	// since the format for local & extended S/G lists is different,
-	// check if S/G pairs exceeds 3.
-	// *sgPairs = Cmnd->use_sg; Nope, that's wrong.
- 
-	sgl = (struct scatterlist*)Cmnd->request_buffer;  
-	sg_count = pci_map_sg(pcidev, sgl, Cmnd->use_sg, 
-		scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
-        // printk("sgl = %p, sg_count = %d\n", (void *) sgl, sg_count);
-  	if( sg_count <= 3 ) {
-
-	// we need to be careful here that no individual mapping
-	// is too large, and if any is, that breaking it up
-	// doesn't push us over 3 sgs, or, if it does, that we
-	// handle that case.  Tachyon can take 0x7FFFF bits for length,
-	// but sg structure uses "unsigned int", on the face of it, 
-	// up to 0xFFFFFFFF or even more.
-
-		int i;
-		unsigned long thislen;
-
-		totalsgs = 0;
-		for (i=0;i<sg_count;i++) {
-      			thislen = sg_dma_len(&sgl[i]);
-			while (thislen >= TL_MAX_SG_ELEM_LEN) {
+			*alPair = (u32) ulBuff;
+			return bytes_to_go;
+		} else		// We have a single large (too big) contiguous buffer.
+		{		// We will have to break it up.  We'll use the scatter
+			// gather code way below, but use contigaddr instead
+			// of sg_dma_addr(). (this is a very rare case).
+
+			unsigned long btg;
+			contigaddr = pci_map_single(pcidev, Cmnd->request_buffer, Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+
+			// printk("contigaddr = %p, len = %d\n", 
+			//      (void *) contigaddr, bytes_to_go);
+			totalsgs = 0;
+			for (btg = bytes_to_go; btg > 0;) {
+				btg -= (btg > TL_MAX_SG_ELEM_LEN ? TL_MAX_SG_ELEM_LEN : btg);
 				totalsgs++;
-				thislen -= TL_MAX_SG_ELEM_LEN;
 			}
-			if (thislen > 0) totalsgs++;
+			sgl = NULL;
+			*sgPairs = totalsgs;
 		}
-		*sgPairs = totalsgs;
-  	} else totalsgs = 999; // as a first estimate, definitely >3, 
-			      
-	// if (totalsgs != sg_count) 
-	//	printk("totalsgs = %d, sgcount=%d\n",totalsgs,sg_count);
-  }
+	} else			// we do have a scatter gather list
+	{
+		// [TBD - update for Linux to support > 32 bits addressing]
+		// since the format for local & extended S/G lists is different,
+		// check if S/G pairs exceeds 3.
+		// *sgPairs = Cmnd->use_sg; Nope, that's wrong.
+
+		sgl = (struct scatterlist *) Cmnd->request_buffer;
+		sg_count = pci_map_sg(pcidev, sgl, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+		// printk("sgl = %p, sg_count = %d\n", (void *) sgl, sg_count);
+		if (sg_count <= 3) {
+
+			// we need to be careful here that no individual mapping
+			// is too large, and if any is, that breaking it up
+			// doesn't push us over 3 sgs, or, if it does, that we
+			// handle that case.  Tachyon can take 0x7FFFF bits for length,
+			// but sg structure uses "unsigned int", on the face of it, 
+			// up to 0xFFFFFFFF or even more.
+
+			int i;
+			unsigned long thislen;
+
+			totalsgs = 0;
+			for (i = 0; i < sg_count; i++) {
+				thislen = sg_dma_len(&sgl[i]);
+				while (thislen >= TL_MAX_SG_ELEM_LEN) {
+					totalsgs++;
+					thislen -= TL_MAX_SG_ELEM_LEN;
+				}
+				if (thislen > 0)
+					totalsgs++;
+			}
+			*sgPairs = totalsgs;
+		} else
+			totalsgs = 999;	// as a first estimate, definitely >3, 
 
-  // printk("totalsgs = %d, sgcount=%d\n", totalsgs, sg_count);
-  if( totalsgs <= 3 ) // can (must) use "local" SEST list
-  {
-    while( bytes_to_go)
-    {
-      offset = 0L;
+		// if (totalsgs != sg_count) 
+		//      printk("totalsgs = %d, sgcount=%d\n",totalsgs,sg_count);
+	}
 
-      if ( WE_HAVE_SG_LIST ) 
-	thisMappingLen = sg_dma_len(sgl);
-      else					// or contiguous buffer?
-	thisMappingLen = bytes_to_go;
+	// printk("totalsgs = %d, sgcount=%d\n", totalsgs, sg_count);
+	if (totalsgs <= 3)	// can (must) use "local" SEST list
+	{
+		while (bytes_to_go) {
+			offset = 0L;
 
-      while (thisMappingLen > 0)
-      {  
-	thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ? 
-		TL_MAX_SG_ELEM_LEN : thisMappingLen;
-	bytes_to_go = bytes_to_go - thislen;
+			if (WE_HAVE_SG_LIST)
+				thisMappingLen = sg_dma_len(sgl);
+			else	// or contiguous buffer?
+				thisMappingLen = bytes_to_go;
 
-	// we have L/A pair; L = thislen, A = physicalAddress
-	// load into SEST...
+			while (thisMappingLen > 0) {
+				thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ? TL_MAX_SG_ELEM_LEN : thisMappingLen;
+				bytes_to_go = bytes_to_go - thislen;
 
-	total_data_len += thislen;
-	*alPair = thislen; // bits 18-0, length
+				// we have L/A pair; L = thislen, A = physicalAddress
+				// load into SEST...
 
-	alPair++;
+				total_data_len += thislen;
+				*alPair = thislen;	// bits 18-0, length
 
-	if ( WE_HAVE_SG_LIST ) 
-		ulBuff = sg_dma_address(sgl) + offset;
-	else
-		ulBuff = contigaddr + offset;
+				alPair++;
 
-	offset += thislen;
+				if (WE_HAVE_SG_LIST)
+					ulBuff = sg_dma_address(sgl) + offset;
+				else
+					ulBuff = contigaddr + offset;
+
+				offset += thislen;
 
 #	if BITS_PER_LONG > 32
-		if( ulBuff >>32 ) {
-        		printk("cqpfcTS: 2Tach DMA address %p > 32 bits\n", 
-				(void*)ulBuff );
-		    printk("%s = %p, offset = %ld\n", 
-			WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr",
-			WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr,
-				offset);
-        		return 0;
-      		}
+				if (ulBuff >> 32) {
+					printk("cqpfcTS: 2Tach DMA address %p > 32 bits\n", (void *) ulBuff);
+					printk("%s = %p, offset = %ld\n", WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr", WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr, offset);
+					return 0;
+				}
 #	endif
-        *alPair++ = (ULONG)ulBuff; // lower 32 bits (31-0)
-	thisMappingLen -= thislen;
-      }
+				*alPair++ = (u32) ulBuff;	// lower 32 bits (31-0)
+				thisMappingLen -= thislen;
+			}
 
-      if ( WE_HAVE_SG_LIST ) ++sgl;  // next S/G pair
-	else if (bytes_to_go != 0) printk("BTG not zero!\n");
+			if (WE_HAVE_SG_LIST)
+				++sgl;	// next S/G pair
+			else if (bytes_to_go != 0)
+				printk("BTG not zero!\n");
 
 #     ifdef DBG_SEST_SGLIST
-	printk("L=%d ", thisMappingLen);
-	printk("btg=%d ", bytes_to_go);
+			printk("L=%d ", thisMappingLen);
+			printk("btg=%d ", bytes_to_go);
 #     endif
 
-    }
-    // printk("i:%d\n", *sgPairs);
-  }
-  else    // more than 3 pairs requires Extended S/G page (Pool Allocation)
-  {
-    // clear out SEST DWORDs (local S/G addr) C-F (A-B set in following logic)
-    for( i=2; i<6; i++)
-      alPair[i] = 0;
-
-    PairCount = TL_EXT_SG_PAGE_COUNT;    // forces initial page allocation
-    totalsgs = 0;
-    while( bytes_to_go )
-    {
-      // Per SEST format, we can support 524287 byte lengths per
-      // S/G pair.  Typical user buffers are 4k, and very rarely
-      // exceed 12k due to fragmentation of physical memory pages.
-      // However, on certain O/S system (not "user") buffers (on platforms 
-      // with huge memories), it's possible to exceed this
-      // length in a single S/G address/len mapping, so we have to handle
-      // that.
-
-      offset = 0L;
-      if ( WE_HAVE_SG_LIST ) 
-	thisMappingLen = sg_dma_len(sgl);
-      else
-	thisMappingLen = bytes_to_go;
-
-      while (thisMappingLen > 0)
-      {
-	thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ? 
-		TL_MAX_SG_ELEM_LEN : thisMappingLen;
-	// printk("%d/%d/%d\n", thislen, thisMappingLen, bytes_to_go);
-      
-  	// should we load into "this" extended S/G page, or allocate
-	// new page?
-
-	if( PairCount >= TL_EXT_SG_PAGE_COUNT )
+		}
+		// printk("i:%d\n", *sgPairs);
+	} else			// more than 3 pairs requires Extended S/G page (Pool Allocation)
 	{
-	  // Now, we have to map the previous page, (triggering buffer bounce)
-	  // The first time thru the loop, there won't be a previous page.
-	  if (prev_page != NULL) // is there a prev page? 
-	  {
-		// this code is normally kind of hard to trigger, 
-		// you have to use up more than 256 scatter gather 
-		// elements to get here.  Cranking down TL_MAX_SG_ELEM_LEN
-		// to an absurdly low value (128 bytes or so) to artificially
-		// break i/o's into a zillion pieces is how I tested it. 
-		busaddr = cpqfc_pci_map_sg_page(pcidev,
-				ext_sg_page_phys_addr_place,
-				prev_page->page,
-        			&prev_page->busaddr,
-        			&prev_page->maplen,
-				PairCount);
-          } 
-          // Allocate the TL Extended S/G list page.  We have
-          // to allocate twice what we want to ensure required TL alignment
-          // (Tachlite TL/TS User Man. Rev 6.0, p 168)
-          // We store the original allocated PVOID so we can free later
-	  *sgpage = kmalloc( sizeof(SGPAGES), GFP_ATOMIC);
-	  if ( ! *sgpage )
-          {
-		printk("cpqfc: Allocation failed @ %d S/G page allocations\n",
-			AllocatedPages);
-		total_data_len = 0;  // failure!! Ext. S/G is All-or-none affair
-
-	        // unmap the previous mappings, if any.
-
-	        cpqfc_undo_SEST_mappings(pcidev, contigaddr, 
-			Cmnd->request_bufflen,
-			scsi_to_pci_dma_dir(Cmnd->sc_data_direction),
-  			sgl, Cmnd->use_sg, sgPages_head, AllocatedPages+1);
-
-		// FIXME: testing shows that if we get here, 
-		// it's bad news.  (this has been this way for a long 
-		// time though, AFAIK.  Not that that excuses it.)
-
-		return 0; // give up (and probably hang the system)
-          }
-                               // clear out memory we just allocated
-	  memset( (*sgpage)->page,0,TL_EXT_SG_PAGE_BYTELEN*2);
-	  (*sgpage)->next = NULL;
-	  (*sgpage)->busaddr = (dma_addr_t) NULL;
-	  (*sgpage)->maplen = 0L;
-      
-	  // align the memory - TL requires sizeof() Ext. S/G page alignment.
-	  // We doubled the actual required size so we could mask off LSBs 
-	  // to get desired offset 
-
-	  ulBuff = (unsigned long) (*sgpage)->page;
-	  ulBuff += TL_EXT_SG_PAGE_BYTELEN;
-	  ulBuff &= ~(TL_EXT_SG_PAGE_BYTELEN -1);
-
-	  // set pointer, in SEST if first Ext. S/G page, or in last pair
-	  // of linked Ext. S/G pages... (Only 32-bit PVOIDs, so just 
-	  // load lower 32 bits)
-	  // NOTE: the Len field must be '0' if this is the first Ext. S/G
-	  // pointer in SEST, and not 0 otherwise (we know thislen != 0).
+		// clear out SEST DWORDs (local S/G addr) C-F (A-B set in following logic)
+		for (i = 2; i < 6; i++)
+			alPair[i] = 0;
 
-	  *alPair = (alPair != SESTalPairStart) ? thislen : 0;
+		PairCount = TL_EXT_SG_PAGE_COUNT;	// forces initial page allocation
+		totalsgs = 0;
+		while (bytes_to_go) {
+			// Per SEST format, we can support 524287 byte lengths per
+			// S/G pair.  Typical user buffers are 4k, and very rarely
+			// exceed 12k due to fragmentation of physical memory pages.
+			// However, on certain O/S system (not "user") buffers (on platforms 
+			// with huge memories), it's possible to exceed this
+			// length in a single S/G address/len mapping, so we have to handle
+			// that.
+
+			offset = 0L;
+			if (WE_HAVE_SG_LIST)
+				thisMappingLen = sg_dma_len(sgl);
+			else
+				thisMappingLen = bytes_to_go;
+
+			while (thisMappingLen > 0) {
+				thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ? TL_MAX_SG_ELEM_LEN : thisMappingLen;
+				// printk("%d/%d/%d\n", thislen, thisMappingLen, bytes_to_go);
+
+				// should we load into "this" extended S/G page, or allocate
+				// new page?
+
+				if (PairCount >= TL_EXT_SG_PAGE_COUNT) {
+					// Now, we have to map the previous page, (triggering buffer bounce)
+					// The first time thru the loop, there won't be a previous page.
+					if (prev_page != NULL)	// is there a prev page? 
+					{
+						// this code is normally kind of hard to trigger, 
+						// you have to use up more than 256 scatter gather 
+						// elements to get here.  Cranking down TL_MAX_SG_ELEM_LEN
+						// to an absurdly low value (128 bytes or so) to artificially
+						// break i/o's into a zillion pieces is how I tested it. 
+						busaddr = cpqfc_pci_map_sg_page(pcidev, ext_sg_page_phys_addr_place, prev_page->page, &prev_page->busaddr, &prev_page->maplen, PairCount);
+					}
+					// Allocate the TL Extended S/G list page.  We have
+					// to allocate twice what we want to ensure required TL alignment
+					// (Tachlite TL/TS User Man. Rev 6.0, p 168)
+					// We store the original allocated PVOID so we can free later
+					*sgpage = kmalloc(sizeof(SGPAGES), GFP_ATOMIC);
+					if (!*sgpage) {
+						printk("cpqfc: Allocation failed @ %d S/G page allocations\n", AllocatedPages);
+						total_data_len = 0;	// failure!! Ext. S/G is All-or-none affair
+
+						// unmap the previous mappings, if any.
+
+						cpqfc_undo_SEST_mappings(pcidev, contigaddr, Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction), sgl, Cmnd->use_sg, sgPages_head, AllocatedPages + 1);
+
+						// FIXME: testing shows that if we get here, 
+						// it's bad news.  (this has been this way for a long 
+						// time though, AFAIK.  Not that that excuses it.)
+
+						return 0;	// give up (and probably hang the system)
+					}
+					// clear out memory we just allocated
+					memset((*sgpage)->page, 0, TL_EXT_SG_PAGE_BYTELEN * 2);
+					(*sgpage)->next = NULL;
+					(*sgpage)->busaddr = (dma_addr_t) NULL;
+					(*sgpage)->maplen = 0L;
+
+					// align the memory - TL requires sizeof() Ext. S/G page alignment.
+					// We doubled the actual required size so we could mask off LSBs 
+					// to get desired offset 
+
+					ulBuff = (unsigned long) (*sgpage)->page;
+					ulBuff += TL_EXT_SG_PAGE_BYTELEN;
+					ulBuff &= ~(TL_EXT_SG_PAGE_BYTELEN - 1);
+
+					// set pointer, in SEST if first Ext. S/G page, or in last pair
+					// of linked Ext. S/G pages... (Only 32-bit PVOIDs, so just 
+					// load lower 32 bits)
+					// NOTE: the Len field must be '0' if this is the first Ext. S/G
+					// pointer in SEST, and not 0 otherwise (we know thislen != 0).
+
+					*alPair = (alPair != SESTalPairStart) ? thislen : 0;
 
 #	  ifdef DBG_SEST_SGLIST
-        	printk("PairCount %d @%p even %Xh, ", 
-			PairCount, alPair, *alPair);
+					printk("PairCount %d @%p even %Xh, ", PairCount, alPair, *alPair);
 #	  endif
 
-	  // Save the place where we need to store the physical
-	  // address of this scatter gather page which we get when we map it
-	  // (and mapping we can do only after we fill it in.)
-	  alPair++;  // next DWORD, will contain phys addr of the ext page
-	  ext_sg_page_phys_addr_place = alPair;
-
-	  // Now, set alPair = the virtual addr of the (Extended) S/G page
-	  // which will accept the Len/ PhysicalAddress pairs
-	  alPair = (ULONG *) ulBuff;
-
-	  AllocatedPages++;
-	  if (AllocatedPages >= ap_hi_water)
-	  {
-		// This message should rarely, if ever, come out.
-		// Previously (cpqfc version <= 2.0.5) the driver would
-		// just puke if more than 4 SG pages were used, and nobody
-		// ever complained about that.  This only comes out if 
-		// more than 8 pages are used.
-
-		printk(KERN_WARNING
-		"cpqfc: Possible danger.  %d scatter gather pages used.\n"
-			"cpqfc: detected seemingly extreme memory "
-			"fragmentation or huge data transfers.\n", 
-			AllocatedPages);
-		ap_hi_water = AllocatedPages+1;
-	  }
-		
-	  PairCount = 1;  // starting new Ext. S/G page
-	  prev_page = (*sgpage);  // remember this page, for next time thru
-	  sgpage = &((*sgpage)->next);
-	}  // end of new TL Ext. S/G page allocation
+					// Save the place where we need to store the physical
+					// address of this scatter gather page which we get when we map it
+					// (and mapping we can do only after we fill it in.)
+					alPair++;	// next DWORD, will contain phys addr of the ext page
+					ext_sg_page_phys_addr_place = alPair;
+
+					// Now, set alPair = the virtual addr of the (Extended) S/G page
+					// which will accept the Len/ PhysicalAddress pairs
+					alPair = (u32 *) ulBuff;
+
+					AllocatedPages++;
+					if (AllocatedPages >= ap_hi_water) {
+						// This message should rarely, if ever, come out.
+						// Previously (cpqfc version <= 2.0.5) the driver would
+						// just puke if more than 4 SG pages were used, and nobody
+						// ever complained about that.  This only comes out if 
+						// more than 8 pages are used.
+
+						printk(KERN_WARNING "cpqfc: Possible danger.  %d scatter gather pages used.\n" "cpqfc: detected seemingly extreme memory " "fragmentation or huge data transfers.\n", AllocatedPages);
+						ap_hi_water = AllocatedPages + 1;
+					}
+
+					PairCount = 1;	// starting new Ext. S/G page
+					prev_page = (*sgpage);	// remember this page, for next time thru
+					sgpage = &((*sgpage)->next);
+				}	// end of new TL Ext. S/G page allocation
+
+				*alPair = thislen;	// bits 18-0, length (range check above)
 
-	*alPair = thislen; // bits 18-0, length (range check above)
-      
 #	ifdef DBG_SEST_SGLIST
-	  printk("PairCount %d @%p, even %Xh, ", PairCount, alPair, *alPair);
+				printk("PairCount %d @%p, even %Xh, ", PairCount, alPair, *alPair);
 #	endif
 
-	alPair++;    // next DWORD, physical address 
+				alPair++;	// next DWORD, physical address 
 
-	if ( WE_HAVE_SG_LIST ) 
-		ulBuff = sg_dma_address(sgl) + offset;
-	else
-		ulBuff = contigaddr + offset;
-	offset += thislen;
+				if (WE_HAVE_SG_LIST)
+					ulBuff = sg_dma_address(sgl) + offset;
+				else
+					ulBuff = contigaddr + offset;
+				offset += thislen;
 
 #	if BITS_PER_LONG > 32
-          if( ulBuff >>32 )
-	  {
-	    printk("cqpfcTS: 1Tach DMA address %p > 32 bits\n", (void*)ulBuff );
-	    printk("%s = %p, offset = %ld\n", 
-		WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr",
-		WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr,
-			offset);
-	    return 0;
-	  }
+				if (ulBuff >> 32) {
+					printk("cqpfcTS: 1Tach DMA address %p > 32 bits\n", (void *) ulBuff);
+					printk("%s = %p, offset = %ld\n", WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr", WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr, offset);
+					return 0;
+				}
 #	endif
 
-	*alPair = (ULONG) ulBuff; // lower 32 bits (31-0)
+				*alPair = (u32) ulBuff;	// lower 32 bits (31-0)
 
 #       ifdef DBG_SEST_SGLIST
-        printk("odd %Xh\n", *alPair);
+				printk("odd %Xh\n", *alPair);
 #       endif
-	alPair++;    // next DWORD, next address/length pair
-                                           
-	PairCount++; // next Length/Address pair
-
-	// if (PairCount > pc_hi_water)
-	// {
-		// printk("pc hi = %d ", PairCount);
-		// pc_hi_water = PairCount;
-	// }
-	bytes_to_go -= thislen;
-	total_data_len += thislen;  
-	thisMappingLen -= thislen;
-	totalsgs++;
-      } // while (thisMappingLen > 0)
-      if ( WE_HAVE_SG_LIST ) sgl++;  // next S/G pair
-    } // while (bytes_to_go)
-
-    // printk("Totalsgs=%d\n", totalsgs);
-    *sgPairs = totalsgs;
-
-    // PCI map (and bounce) the last (and usually only) extended SG page
-    busaddr = cpqfc_pci_map_sg_page(pcidev,
-		ext_sg_page_phys_addr_place,
-		prev_page->page, 
-		&prev_page->busaddr, 
-		&prev_page->maplen,
-		PairCount);
-  }
-  return total_data_len;
+				alPair++;	// next DWORD, next address/length pair
+
+				PairCount++;	// next Length/Address pair
+
+				// if (PairCount > pc_hi_water)
+				// {
+				// printk("pc hi = %d ", PairCount);
+				// pc_hi_water = PairCount;
+				// }
+				bytes_to_go -= thislen;
+				total_data_len += thislen;
+				thisMappingLen -= thislen;
+				totalsgs++;
+			}	// while (thisMappingLen > 0)
+			if (WE_HAVE_SG_LIST)
+				sgl++;	// next S/G pair
+		}		// while (bytes_to_go)
+
+		// printk("Totalsgs=%d\n", totalsgs);
+		*sgPairs = totalsgs;
+
+		// PCI map (and bounce) the last (and usually only) extended SG page
+		busaddr = cpqfc_pci_map_sg_page(pcidev, ext_sg_page_phys_addr_place, prev_page->page, &prev_page->busaddr, &prev_page->maplen, PairCount);
+	}
+	return total_data_len;
 }
 
 
@@ -5554,268 +4508,249 @@
 // 0 if successful
 // non-zero on error
 //sstartex
-ULONG cpqfcTSStartExchange( 
-  CPQFCHBA *cpqfcHBAdata,                      
-  LONG ExchangeID )
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ ExchangeID ]; // shorthand
-  USHORT producer, consumer;
-  ULONG ulStatus=0;
-  short int ErqIndex;
-  BOOLEAN CompleteExchange = FALSE;  // e.g. ACC replies are complete
-  BOOLEAN SestType=FALSE;
-  ULONG InboundData=0;
 
-  // We will manipulate Tachlite chip registers here to successfully
-  // start exchanges. 
+u32 cpqfcTSStartExchange(CPQFCHBA * dev, s32 ExchangeID)
+{
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID];	// shorthand
+	u16 producer, consumer;
+	u32 ulStatus = 0;
+	short int ErqIndex;
+	u8 CompleteExchange = 0;	// e.g. ACC replies are complete
+	u8 SestType = 0;
+	u32 InboundData = 0;
 
-  // Check that link is not down -- we can't start an exchange on a
-  // down link!
+	// We will manipulate Tachlite chip registers here to successfully
+	// start exchanges. 
 
-  if( fcChip->Registers.FMstatus.value & 0x80) // LPSM offline?
-  {
-printk("fcStartExchange: PSM offline (%Xh), x_ID %Xh, type %Xh, port_id %Xh\n",
-         fcChip->Registers.FMstatus.value & 0xFF,
-         ExchangeID,
-         pExchange->type,
-         pExchange->fchs.d_id);
+	// Check that link is not down -- we can't start an exchange on a
+	// down link!
 
-    if( ExchangeID >= TACH_SEST_LEN )  // Link Service Outbound frame?
-    {
-      // Our most popular LinkService commands are port discovery types
-      // (PLOGI/ PDISC...), which are implicitly nullified by Link Down
-      // events, so it makes no sense to Que them.  However, ABTS should
-      // be queued, since exchange sequences are likely destroyed by
-      // Link Down events, and we want to notify other ports of broken
-      // sequences by aborting the corresponding exchanges.
-      if( pExchange->type != BLS_ABTS )
-      {
-	ulStatus = LNKDWN_OSLS;
-	goto Done;
-        // don't Que most LinkServ exchanges on LINK DOWN
-      }
-    }
+	if (fcChip->Registers.FMstatus.value & 0x80)	// LPSM offline?
+	{
+		printk("fcStartExchange: PSM offline (%Xh), x_ID %Xh, type %Xh, port_id %Xh\n", fcChip->Registers.FMstatus.value & 0xFF, ExchangeID, pExchange->type, pExchange->fchs.d_id);
 
-    printk("fcStartExchange: Que x_ID %Xh, type %Xh\n", 
-      ExchangeID, pExchange->type);
-    pExchange->status |= EXCHANGE_QUEUED;
-    ulStatus = EXCHANGE_QUEUED;
-    goto Done;
-  }
+		if (ExchangeID >= TACH_SEST_LEN)	// Link Service Outbound frame?
+		{
+			// Our most popular LinkService commands are port discovery types
+			// (PLOGI/ PDISC...), which are implicitly nullified by Link Down
+			// events, so it makes no sense to Que them.  However, ABTS should
+			// be queued, since exchange sequences are likely destroyed by
+			// Link Down events, and we want to notify other ports of broken
+			// sequences by aborting the corresponding exchanges.
+			if (pExchange->type != BLS_ABTS) {
+				ulStatus = LNKDWN_OSLS;
+				goto Done;
+				// don't Que most LinkServ exchanges on LINK DOWN
+			}
+		}
 
-  // Make sure ERQ has available space.
-  
-  producer = (USHORT)fcChip->ERQ->producerIndex; // copies for logical arith.
-  consumer = (USHORT)fcChip->ERQ->consumerIndex;
-  producer++;  // We are testing for full que by incrementing
-  
-  if( producer >= ERQ_LEN )  // rollover condition?
-    producer = 0;
-  if( consumer != producer ) // ERQ not full?
-  {
-    // ****************** Need Atomic access to chip registers!!********
-    
-    // remember ERQ PI for copying IRB
-    ErqIndex = (USHORT)fcChip->ERQ->producerIndex; 
-    fcChip->ERQ->producerIndex = producer; // this is written to Tachyon
-               // we have an ERQ slot! If SCSI command, need SEST slot
-               // otherwise we are done.
-
-    // Note that Tachyon requires that bit 15 of the OX_ID or RX_ID be
-    // set according to direction of data to/from Tachyon for SEST assists.
-    // For consistency, enforce this rule for Link Service (non-SEST)
-    // exchanges as well.
-
-    // fix-up the X_ID field in IRB
-    pExchange->IRB.Req_A_Trans_ID = ExchangeID & 0x7FFF; // 15-bit field
-
-    // fix-up the X_ID field in fchs -- depends on Originator or Responder,
-    // outgoing or incoming data?
-    switch( pExchange->type )
-    {
-               // ORIGINATOR types...  we're setting our OX_ID and
-               // defaulting the responder's RX_ID to 0xFFFF
-    
-    case SCSI_IRE:
-      // Requirement: set MSB of x_ID for Incoming TL data
-      // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
-      InboundData = 0x8000;
-
-    case SCSI_IWE:   
-      SestType = TRUE;
-      pExchange->fchs.ox_rx_id = (ExchangeID | InboundData);
-      pExchange->fchs.ox_rx_id <<= 16;     // MSW shift
-      pExchange->fchs.ox_rx_id |= 0xffff;  // add default RX_ID
-      
-      // now fix-up the Data HDR OX_ID (TL automatically does rx_id)
-      // (not necessary for IRE -- data buffer unused)
-      if( pExchange->type == SCSI_IWE)
-      {
-        fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id = 
-          pExchange->fchs.ox_rx_id;
-
-      }
-
-      break;
-
-
-    case FCS_NSR:  // ext. link service Name Service Request
-    case ELS_SCR:  // ext. link service State Change Registration
-    case ELS_FDISC:// ext. link service login
-    case ELS_FLOGI:// ext. link service login
-    case ELS_LOGO: // FC-PH extended link service logout
-    case BLS_NOP:  // Basic link service No OPeration
-    case ELS_PLOGI:// ext. link service login (PLOGI)
-    case ELS_PDISC:// ext. link service login (PDISC)
-    case ELS_PRLI: // ext. link service process login
-
-      pExchange->fchs.ox_rx_id = ExchangeID;
-      pExchange->fchs.ox_rx_id <<= 16;  // MSW shift
-      pExchange->fchs.ox_rx_id |= 0xffff;  // and RX_ID
+		printk("fcStartExchange: Que x_ID %Xh, type %Xh\n", ExchangeID, pExchange->type);
+		pExchange->status |= EXCHANGE_QUEUED;
+		ulStatus = EXCHANGE_QUEUED;
+		goto Done;
+	}
+	// Make sure ERQ has available space.
 
-      break;
-      
+	producer = (u16) fcChip->ERQ->producerIndex;	// copies for logical arith.
+	consumer = (u16) fcChip->ERQ->consumerIndex;
+	producer++;		// We are testing for full que by incrementing
+
+	if (producer >= ERQ_LEN)	// rollover condition?
+		producer = 0;
+	if (consumer != producer)	// ERQ not full?
+	{
+		// ****************** Need Atomic access to chip registers!!********
 
+		// remember ERQ PI for copying IRB
+		ErqIndex = (u16) fcChip->ERQ->producerIndex;
+		fcChip->ERQ->producerIndex = producer;	// this is written to Tachyon
+		// we have an ERQ slot! If SCSI command, need SEST slot
+		// otherwise we are done.
+
+		// Note that Tachyon requires that bit 15 of the OX_ID or RX_ID be
+		// set according to direction of data to/from Tachyon for SEST assists.
+		// For consistency, enforce this rule for Link Service (non-SEST)
+		// exchanges as well.
+
+		// fix-up the X_ID field in IRB
+		pExchange->IRB.Req_A_Trans_ID = ExchangeID & 0x7FFF;	// 15-bit field
+
+		// fix-up the X_ID field in fchs -- depends on Originator or Responder,
+		// outgoing or incoming data?
+		switch (pExchange->type) {
+			// ORIGINATOR types...  we're setting our OX_ID and
+			// defaulting the responder's RX_ID to 0xFFFF
+
+		case SCSI_IRE:
+			// Requirement: set MSB of x_ID for Incoming TL data
+			// (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
+			InboundData = 0x8000;
+
+		case SCSI_IWE:
+			SestType = 1;
+			pExchange->fchs.ox_rx_id = (ExchangeID | InboundData);
+			pExchange->fchs.ox_rx_id <<= 16;	// MSW shift
+			pExchange->fchs.ox_rx_id |= 0xffff;	// add default RX_ID
+
+			// now fix-up the Data HDR OX_ID (TL automatically does rx_id)
+			// (not necessary for IRE -- data buffer unused)
+			if (pExchange->type == SCSI_IWE) {
+				fcChip->SEST->DataHDR[ExchangeID].ox_rx_id = pExchange->fchs.ox_rx_id;
 
+			}
 
-               // RESPONDER types... we must set our RX_ID while preserving
-               // sender's OX_ID
-               // outgoing (or no) data
-    case ELS_RJT:       // extended link service reject 
-    case ELS_LOGO_ACC: // FC-PH extended link service logout accept
-    case ELS_ACC:      // ext. generic link service accept
-    case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
-    case ELS_PRLI_ACC: // ext. link service process login accept
-
-      CompleteExchange = TRUE;   // Reply (ACC or RJT) is end of exchange
-      pExchange->fchs.ox_rx_id |= (ExchangeID & 0xFFFF);
-
-      break;
-
-
-      // since we are a Responder, OX_ID should already be set by
-      // cpqfcTSBuildExchange().  We need to -OR- in RX_ID
-    case SCSI_TWE:
-      SestType = TRUE;
-      // Requirement: set MSB of x_ID for Incoming TL data
-      // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
-
-      pExchange->fchs.ox_rx_id &= 0xFFFF0000;  // clear RX_ID
-      // Requirement: set MSB of RX_ID for Incoming TL data
-      // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
-      pExchange->fchs.ox_rx_id |= (ExchangeID | 0x8000);
-      break;
-          
-    
-    case SCSI_TRE:
-      SestType = TRUE;
-      
-      // there is no XRDY for SEST target read; the data
-      // header needs to be updated. Also update the RSP
-      // exchange IDs for the status frame, in case it is sent automatically
-      fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id |= ExchangeID;
-      fcChip->SEST->RspHDR[ ExchangeID ].ox_rx_id = 
-        fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
-      
-      // for easier FCP response logic (works for TWE and TRE), 
-      // copy exchange IDs.  (Not needed if TRE 'RSP' bit set)
-      pExchange->fchs.ox_rx_id =
-        fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
-
-      break;
+			break;
 
 
-    case FCP_RESPONSE:  // using existing OX_ID/ RX_ID pair,
-                        // start SFS FCP-RESPONSE frame
-      // OX/RX_ID should already be set! (See "fcBuild" above)
-      CompleteExchange = TRUE;   // RSP is end of FCP-SCSI exchange
+		case FCS_NSR:	// ext. link service Name Service Request
+		case ELS_SCR:	// ext. link service State Change Registration
+		case ELS_FDISC:	// ext. link service login
+		case ELS_FLOGI:	// ext. link service login
+		case ELS_LOGO:	// FC-PH extended link service logout
+		case BLS_NOP:	// Basic link service No OPeration
+		case ELS_PLOGI:	// ext. link service login (PLOGI)
+		case ELS_PDISC:	// ext. link service login (PDISC)
+		case ELS_PRLI:	// ext. link service process login
 
-      
-      break;
+			pExchange->fchs.ox_rx_id = ExchangeID;
+			pExchange->fchs.ox_rx_id <<= 16;	// MSW shift
+			pExchange->fchs.ox_rx_id |= 0xffff;	// and RX_ID
 
+			break;
 
-    case BLS_ABTS_RJT:  // uses new RX_ID, since SEST x_ID non-existent
-    case BLS_ABTS_ACC:  // using existing OX_ID/ RX_ID pair from SEST entry
-      CompleteExchange = TRUE;   // ACC or RJT marks end of FCP-SCSI exchange
-    case BLS_ABTS:  // using existing OX_ID/ RX_ID pair from SEST entry
 
 
-      break;
 
+			// RESPONDER types... we must set our RX_ID while preserving
+			// sender's OX_ID
+			// outgoing (or no) data
+		case ELS_RJT:	// extended link service reject 
+		case ELS_LOGO_ACC:	// FC-PH extended link service logout accept
+		case ELS_ACC:	// ext. generic link service accept
+		case ELS_PLOGI_ACC:	// ext. link service login accept (PLOGI or PDISC)
+		case ELS_PRLI_ACC:	// ext. link service process login accept
 
-    default:
-      printk("Error on fcStartExchange: undefined type %Xh(%d)\n",
-        pExchange->type, pExchange->type);
-      return INVALID_ARGS;
-    }
-    
-    
-      // X_ID fields are entered -- copy IRB to Tachyon's ERQ
-    
+			CompleteExchange = 1;	// Reply (ACC or RJT) is end of exchange
+			pExchange->fchs.ox_rx_id |= (ExchangeID & 0xFFFF);
 
-    memcpy(
-        &fcChip->ERQ->QEntry[ ErqIndex ],  // dest.
-        &pExchange->IRB,
-        32);  // fixed (hardware) length!
-
-    PCI_TRACEO( ExchangeID, 0xA0)
-
-    // ACTION!  May generate INT and IMQ entry
-    writel( fcChip->ERQ->producerIndex,
-          fcChip->Registers.ERQproducerIndex.address);
+			break;
 
-  
-    if( ExchangeID >= TACH_SEST_LEN )  // Link Service Outbound frame?
-    {
-    
-      // wait for completion! (TDB -- timeout and chip reset)
-      
 
-  PCI_TRACEO( ExchangeID, 0xA4)
-  
-      enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Sem.
-      
-      down_interruptible( cpqfcHBAdata->TYOBcomplete); 
-  
-      disable_irq( cpqfcHBAdata->HostAdapter->irq);
-  PCI_TRACE( 0xA4)
-
-      // On login exchanges, BAD_ALPA (non-existent port_id) results in 
-      // FTO (Frame Time Out) on the Outbound Completion message.
-      // If we got an FTO status, complete the exchange (free up slot)
-      if( CompleteExchange ||   // flag from Reply frames
-          pExchange->status )   // typically, can get FRAME_TO
-      {
-    	cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);  
-      }
-    }
+			// since we are a Responder, OX_ID should already be set by
+			// cpqfcTSBuildExchange().  We need to -OR- in RX_ID
+		case SCSI_TWE:
+			SestType = 1;
+			// Requirement: set MSB of x_ID for Incoming TL data
+			// (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
 
-    else                         // SEST Exchange
-    {
-      ulStatus = 0;   // ship & pray success (e.g. FCP-SCSI)
-      
-      if( CompleteExchange )   // by Type of exchange (e.g. end-of-xchng)
-      {
-    	cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);  
-      }
-       
-      else
-        pExchange->status &= ~EXCHANGE_QUEUED;  // clear ExchangeQueued flag 
+			pExchange->fchs.ox_rx_id &= 0xFFFF0000;	// clear RX_ID
+			// Requirement: set MSB of RX_ID for Incoming TL data
+			// (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
+			pExchange->fchs.ox_rx_id |= (ExchangeID | 0x8000);
+			break;
 
-    }
-  }
 
-  
-  else                // ERQ 'producer' = 'consumer' and QUE is full
-  {
-    ulStatus = OUTQUE_FULL; // Outbound (ERQ) Que full
-  }
- 
-Done: 
-  PCI_TRACE( 0xA0)
-  return ulStatus; 
+		case SCSI_TRE:
+			SestType = 1;
+
+			// there is no XRDY for SEST target read; the data
+			// header needs to be updated. Also update the RSP
+			// exchange IDs for the status frame, in case it is sent automatically
+			fcChip->SEST->DataHDR[ExchangeID].ox_rx_id |= ExchangeID;
+			fcChip->SEST->RspHDR[ExchangeID].ox_rx_id = fcChip->SEST->DataHDR[ExchangeID].ox_rx_id;
+
+			// for easier FCP response logic (works for TWE and TRE), 
+			// copy exchange IDs.  (Not needed if TRE 'RSP' bit set)
+			pExchange->fchs.ox_rx_id = fcChip->SEST->DataHDR[ExchangeID].ox_rx_id;
+
+			break;
+
+
+		case FCP_RESPONSE:	// using existing OX_ID/ RX_ID pair,
+			// start SFS FCP-RESPONSE frame
+			// OX/RX_ID should already be set! (See "fcBuild" above)
+			CompleteExchange = 1;	// RSP is end of FCP-SCSI exchange
+
+
+			break;
+
+
+		case BLS_ABTS_RJT:	// uses new RX_ID, since SEST x_ID non-existent
+		case BLS_ABTS_ACC:	// using existing OX_ID/ RX_ID pair from SEST entry
+			CompleteExchange = 1;	// ACC or RJT marks end of FCP-SCSI exchange
+		case BLS_ABTS:	// using existing OX_ID/ RX_ID pair from SEST entry
+
+
+			break;
+
+
+		default:
+			printk("Error on fcStartExchange: undefined type %Xh(%d)\n", pExchange->type, pExchange->type);
+			return INVALID_ARGS;
+		}
+
+
+		// X_ID fields are entered -- copy IRB to Tachyon's ERQ
+
+
+		memcpy(&fcChip->ERQ->QEntry[ErqIndex],	// dest.
+		       &pExchange->IRB, 32);	// fixed (hardware) length!
+
+		PCI_TRACEO(ExchangeID, 0xA0)
+		    // ACTION!  May generate INT and IMQ entry
+		    writel(fcChip->ERQ->producerIndex, fcChip->Registers.ERQproducerIndex.address);
+
+
+		if (ExchangeID >= TACH_SEST_LEN)	// Link Service Outbound frame?
+		{
+
+			// wait for completion! (TDB -- timeout and chip reset)
+
+
+			PCI_TRACEO(ExchangeID, 0xA4)
+
+			    enable_irq(dev->HostAdapter->irq);	// only way to get Sem.
+
+			down_interruptible(dev->TYOBcomplete);
+
+			disable_irq(dev->HostAdapter->irq);
+			PCI_TRACE(0xA4)
+			    // On login exchanges, BAD_ALPA (non-existent port_id) results in 
+			    // FTO (Frame Time Out) on the Outbound Completion message.
+			    // If we got an FTO status, complete the exchange (free up slot)
+			    if (CompleteExchange ||	// flag from Reply frames
+				pExchange->status)	// typically, can get FRAME_TO
+			{
+				cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+			}
+		}
+
+		else		// SEST Exchange
+		{
+			ulStatus = 0;	// ship & pray success (e.g. FCP-SCSI)
+
+			if (CompleteExchange)	// by Type of exchange (e.g. end-of-xchng)
+			{
+				cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+			}
+
+			else
+				pExchange->status &= ~EXCHANGE_QUEUED;	// clear ExchangeQueued flag 
+
+		}
+	}
+
+
+	else			// ERQ 'producer' = 'consumer' and QUE is full
+	{
+		ulStatus = OUTQUE_FULL;	// Outbound (ERQ) Que full
+	}
+
+      Done:
+	PCI_TRACE(0xA0)
+	    return ulStatus;
 }
 
 
@@ -5839,408 +4774,364 @@
 // (Least Recently Used) scheme.
 
 
-static LONG FindFreeExchange( PTACHYON fcChip, ULONG type )
+static s32 FindFreeExchange(PTACHYON fcChip, u32 type)
 {
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG i;
-  ULONG ulStatus=-1;  // assume failure
-
-
-  if( type == SCSI_IRE ||
-      type == SCSI_TRE ||
-      type == SCSI_IWE ||
-      type == SCSI_TWE)
-  {
-        // SCSI type - X_IDs should be from 0 to TACH_SEST_LEN-1
-    if( fcChip->fcSestExchangeLRU >= TACH_SEST_LEN) // rollover?
-      fcChip->fcSestExchangeLRU = 0;
-    i = fcChip->fcSestExchangeLRU; // typically it's already free!
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 i;
+	u32 ulStatus = -1;	// assume failure
+
+
+	if (type == SCSI_IRE || type == SCSI_TRE || type == SCSI_IWE || type == SCSI_TWE) {
+		// SCSI type - X_IDs should be from 0 to TACH_SEST_LEN-1
+		if (fcChip->fcSestExchangeLRU >= TACH_SEST_LEN)	// rollover?
+			fcChip->fcSestExchangeLRU = 0;
+		i = fcChip->fcSestExchangeLRU;	// typically it's already free!
+
+		if (Exchanges->fcExchange[i].type == 0)	// check for "free" element
+		{
+			ulStatus = 0;	// success!
+		}
 
-    if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
-    {
-      ulStatus = 0; // success!
-    }
-    
-    else
-    {         // YUK! we need to do a linear search for free element.
-              // Fragmentation of the fcExchange array is due to excessively
-              // long completions or timeouts.
-      
-      while( TRUE )
-      {
-        if( ++i >= TACH_SEST_LEN ) // rollover check
-          i = 0;  // beginning of SEST X_IDs
-
-//        printk( "looping for SCSI xchng ID: i=%d, type=%Xh\n", 
-//         i, Exchanges->fcExchange[i].type);
-
-        if( Exchanges->fcExchange[i].type == 0 ) // "free"?
-        {
-          ulStatus = 0; // success!
-          break;
-        }
-        if( i == fcChip->fcSestExchangeLRU ) // wrapped-around array?
-        {
-          printk( "SEST X_ID space full\n");
-          break;       // failed - prevent inf. loop
-        }
-      }
-    }
-    fcChip->fcSestExchangeLRU = i + 1; // next! (rollover check next pass)
-  }
+		else {		// YUK! we need to do a linear search for free element.
+			// Fragmentation of the fcExchange array is due to excessively
+			// long completions or timeouts.
+
+			while (1) {
+				if (++i >= TACH_SEST_LEN)	// rollover check
+					i = 0;	// beginning of SEST X_IDs
+
+//					printk( "looping for SCSI xchng ID: i=%d, type=%Xh\n", 
+//						i, Exchanges->fcExchange[i].type);
+
+				if (Exchanges->fcExchange[i].type == 0)	// "free"?
+				{
+					ulStatus = 0;	// success!
+					break;
+				}
+				if (i == fcChip->fcSestExchangeLRU)	// wrapped-around array?
+				{
+					printk("SEST X_ID space full\n");
+					break;	// failed - prevent inf. loop
+				}
+			}
+		}
+		fcChip->fcSestExchangeLRU = i + 1;	// next! (rollover check next pass)
+	}
+	else			// Link Service type - X_IDs should be from TACH_SEST_LEN 
+				// to TACH_MAX_XID
+	{
+		if (fcChip->fcLsExchangeLRU >= TACH_MAX_XID ||	// range check
+		    fcChip->fcLsExchangeLRU < TACH_SEST_LEN)	// (e.g. startup)
+			fcChip->fcLsExchangeLRU = TACH_SEST_LEN;
+
+		i = fcChip->fcLsExchangeLRU;	// typically it's already free!
+		if (Exchanges->fcExchange[i].type == 0)	// check for "free" element
+		{
+			ulStatus = 0;	// success!
+		}
 
-  
-  
-  else  // Link Service type - X_IDs should be from TACH_SEST_LEN 
-        // to TACH_MAX_XID
-  {
-    if( fcChip->fcLsExchangeLRU >= TACH_MAX_XID || // range check
-        fcChip->fcLsExchangeLRU < TACH_SEST_LEN ) // (e.g. startup)
-      fcChip->fcLsExchangeLRU = TACH_SEST_LEN;
+		else {		// YUK! we need to do a linear search for free element
+			// Fragmentation of the fcExchange array is due to excessively
+			// long completions or timeouts.
+
+			while (1) {
+				if (++i >= TACH_MAX_XID)	// rollover check
+					i = TACH_SEST_LEN;	// beginning of Link Service X_IDs
+
+//				printk( "looping for xchng ID: i=%d, type=%Xh\n", 
+//					i, Exchanges->fcExchange[i].type);
+
+				if (Exchanges->fcExchange[i].type == 0)	// "free"?
+				{
+					ulStatus = 0;	// success!
+					break;
+				}
+				if (i == fcChip->fcLsExchangeLRU)	// wrapped-around array?
+				{
+					printk("LinkService X_ID space full\n");
+					break;	// failed - prevent inf. loop
+				}
+			}
+		}
+		fcChip->fcLsExchangeLRU = i + 1;	// next! (rollover check next pass)
 
-    i = fcChip->fcLsExchangeLRU; // typically it's already free!
-    if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
-    {
-      ulStatus = 0; // success!
-    }
-    
-    else
-    {         // YUK! we need to do a linear search for free element
-              // Fragmentation of the fcExchange array is due to excessively
-              // long completions or timeouts.
-      
-      while( TRUE )
-      {
-        if( ++i >= TACH_MAX_XID ) // rollover check
-          i = TACH_SEST_LEN;// beginning of Link Service X_IDs
-
-//        printk( "looping for xchng ID: i=%d, type=%Xh\n", 
-//         i, Exchanges->fcExchange[i].type);
-
-        if( Exchanges->fcExchange[i].type == 0 ) // "free"?
-        {
-          ulStatus = 0; // success!
-          break;
-        }
-        if( i == fcChip->fcLsExchangeLRU ) // wrapped-around array?
-        {
-          printk( "LinkService X_ID space full\n");
-          break;       // failed - prevent inf. loop
-        }
-      }
-    }
-    fcChip->fcLsExchangeLRU = i + 1; // next! (rollover check next pass)
+	}
 
-  }
+	if (!ulStatus)		// success?
+		Exchanges->fcExchange[i].type = type;	// allocate it.
 
-  if( !ulStatus )  // success?
-    Exchanges->fcExchange[i].type = type; // allocate it.
-  
-  else
-    i = -1;  // error - all exchanges "open"
+	else
+		i = -1;		// error - all exchanges "open"
 
-  return i;  
+	return i;
 }
 
-static void
-cpqfc_pci_unmap_extended_sg(struct pci_dev *pcidev,
-	PTACHYON fcChip,
-	ULONG x_ID)
+static void cpqfc_pci_unmap_extended_sg(struct pci_dev *pcidev, PTACHYON fcChip, u32 x_ID)
 {
 	// Unmaps the memory regions used to hold the scatter gather lists
 
 	PSGPAGES i;
 
 	// Were there any such regions needing unmapping?
-	if (! USES_EXTENDED_SGLIST(fcChip->SEST, x_ID))
-		return;	// No such regions, we're outta here.
+	if (!USES_EXTENDED_SGLIST(fcChip->SEST, x_ID))
+		return;		// No such regions, we're outta here.
 
 	// for each extended scatter gather region needing unmapping... 
-	for (i=fcChip->SEST->sgPages[x_ID] ; i != NULL ; i = i->next)
-		pci_unmap_single(pcidev, i->busaddr, i->maplen,
-			scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
+	for (i = fcChip->SEST->sgPages[x_ID]; i != NULL; i = i->next)
+		pci_unmap_single(pcidev, i->busaddr, i->maplen, scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
 }
 
 // Called also from cpqfcTScontrol.o, so can't be static
-void
-cpqfc_pci_unmap(struct pci_dev *pcidev, 
-	Scsi_Cmnd *cmd, 
-	PTACHYON fcChip, 
-	ULONG x_ID)
+void cpqfc_pci_unmap(struct pci_dev *pcidev, Scsi_Cmnd * cmd, PTACHYON fcChip, u32 x_ID)
 {
 	// Undo the DMA mappings
 	if (cmd->use_sg) {	// Used scatter gather list for data buffer?
 		cpqfc_pci_unmap_extended_sg(pcidev, fcChip, x_ID);
-		pci_unmap_sg(pcidev, cmd->buffer, cmd->use_sg,
-			scsi_to_pci_dma_dir(cmd->sc_data_direction));
+		pci_unmap_sg(pcidev, cmd->buffer, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction));
 		// printk("umsg %d\n", cmd->use_sg);
-	}
-	else if (cmd->request_bufflen) {
+	} else if (cmd->request_bufflen) {
 		// printk("ums %p ", fcChip->SEST->u[ x_ID ].IWE.GAddr1);
-		pci_unmap_single(pcidev, fcChip->SEST->u[ x_ID ].IWE.GAddr1,
-			cmd->request_bufflen,
-			scsi_to_pci_dma_dir(cmd->sc_data_direction));
-	}	 
+		pci_unmap_single(pcidev, fcChip->SEST->u[x_ID].IWE.GAddr1, cmd->request_bufflen, scsi_to_pci_dma_dir(cmd->sc_data_direction));
+	}
 }
 
 // We call this routine to free an Exchange for any reason:
 // completed successfully, completed with error, aborted, etc.
 
-// returns FALSE if Exchange failed and "retry" is acceptable
-// returns TRUE if Exchange was successful, or retry is impossible
+// returns 0 if Exchange failed and "retry" is acceptable
+// returns 1 if Exchange was successful, or retry is impossible
 // (e.g. port/device gone).
 //scompleteexchange
 
-void cpqfcTSCompleteExchange( 
-       struct pci_dev *pcidev,
-       PTACHYON fcChip, 
-       ULONG x_ID)
-{
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  int already_unmapped = 0;
-  
-  if( x_ID < TACH_SEST_LEN ) // SEST-based (or LinkServ for FCP exchange)
-  {
-    if( Exchanges->fcExchange[ x_ID ].Cmnd == NULL ) // what#@!
-    {
-//      TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
-      printk(" x_ID %Xh, type %Xh, NULL ptr!\n", x_ID,
-			Exchanges->fcExchange[ x_ID ].type);
+void cpqfcTSCompleteExchange(struct pci_dev *pcidev, PTACHYON fcChip, u32 x_ID)
+{
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	int already_unmapped = 0;
 
-      goto CleanUpSestResources;  // this path should be very rare.
-    }
+	if (x_ID < TACH_SEST_LEN)	// SEST-based (or LinkServ for FCP exchange)
+	{
+		if (Exchanges->fcExchange[x_ID].Cmnd == NULL)	// what#@!
+		{
+//			TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
+			printk(" x_ID %Xh, type %Xh, NULL ptr!\n", x_ID, Exchanges->fcExchange[x_ID].type);
 
-    // we have Linux Scsi Cmnd ptr..., now check our Exchange status
-    // to decide how to complete this SEST FCP exchange
+			goto CleanUpSestResources;	// this path should be very rare.
+		}
+		// we have Linux Scsi Cmnd ptr..., now check our Exchange status
+		// to decide how to complete this SEST FCP exchange
 
-    if( Exchanges->fcExchange[ x_ID ].status ) // perhaps a Tach indicated problem,
-                                             // or abnormal exchange completion
-    {
-      // set FCP Link statistics
-     
-      if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT)
-        fcChip->fcStats.timeouts++;
-      if( Exchanges->fcExchange[ x_ID ].status & INITIATOR_ABORT)
-        fcChip->fcStats.FC4aborted++;
-      if( Exchanges->fcExchange[ x_ID ].status & COUNT_ERROR)
-        fcChip->fcStats.CntErrors++;
-      if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX)
-        fcChip->fcStats.linkFailTX++;
-      if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_RX)
-        fcChip->fcStats.linkFailRX++;
-      if( Exchanges->fcExchange[ x_ID ].status & OVERFLOW)
-        fcChip->fcStats.CntErrors++;
-
-      // First, see if the Scsi upper level initiated an ABORT on this
-      // exchange...
-      if( Exchanges->fcExchange[ x_ID ].status == INITIATOR_ABORT )
-      {
-        printk(" DID_ABORT, x_ID %Xh, Cmnd %p ", 
-            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
-        goto CleanUpSestResources;  // (we don't expect Linux _aborts)
-      }
-
-      // Did our driver timeout the Exchange, or did Tachyon indicate
-      // a failure during transmission?  Ask for retry with "SOFT_ERROR"
-      else if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT) 
-      {
-//        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
-//            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
-        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
-      }
-      
-      // Did frame(s) for an open exchange arrive in the SFQ,
-      // meaning the SEST was unable to process them?
-      else if( Exchanges->fcExchange[ x_ID ].status & SFQ_FRAME) 
-      {
-//        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
-//            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
-        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
-      }
-      
-      // Did our driver timeout the Exchange, or did Tachyon indicate
-      // a failure during transmission?  Ask for retry with "SOFT_ERROR"
-      else if( 
-               (Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX) ||
-               (Exchanges->fcExchange[ x_ID ].status & PORTID_CHANGED) ||
-	       (Exchanges->fcExchange[ x_ID ].status & FRAME_TO)    ||
-	       (Exchanges->fcExchange[ x_ID ].status & INV_ENTRY)    ||
-	       (Exchanges->fcExchange[ x_ID ].status & ABORTSEQ_NOTIFY)    )
-
-
-      {
-//        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
-//            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
-        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
-
-
-      }
-
-      // e.g., a LOGOut happened, or device never logged back in.
-      else if( Exchanges->fcExchange[ x_ID ].status & DEVICE_REMOVED) 
-      {
-//	printk(" *LOGOut or timeout on login!* ");
-	// trigger?
-//        TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
-
-        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_BAD_TARGET <<16);
-      }      
-		
-		      
-      // Did Tachyon indicate a CNT error?  We need further analysis
-      // to determine if the exchange is acceptable
-      else if( Exchanges->fcExchange[ x_ID ].status == COUNT_ERROR)
-      {
-        UCHAR ScsiStatus;
-        FCP_STATUS_RESPONSE *pFcpStatus = 
-	  (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
-
-      	ScsiStatus = pFcpStatus->fcp_status >>24;
-  
-	// If the command is a SCSI Read/Write type, we don't tolerate
-	// count errors of any kind; assume the count error is due to
-	// a dropped frame and ask for retry...
-	
-	if(( (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x8) ||
-	    (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x28) ||		
-            (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0xA) ||
-            (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x2A) )
-	                   &&
-                     ScsiStatus == 0 )
-	{
-          // ask for retry
-/*          printk("COUNT_ERROR retry, x_ID %Xh, status %Xh, Cmnd %p\n", 
-            x_ID, Exchanges->fcExchange[ x_ID ].status,
-            Exchanges->fcExchange[ x_ID ].Cmnd);*/
-          Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
-	}
-	
-	else  // need more analysis
-	{
-	  cpqfcTSCheckandSnoopFCP(fcChip, x_ID);  // (will set ->result)
-	}
-      }
-      
-      // default: NOTE! We don't ever want to get here.  Getting here
-      // implies something new is happening that we've never had a test
-      // case for.  Need code maintenance!  Return "ERROR"
-      else
-      {
-	unsigned int stat = Exchanges->fcExchange[ x_ID ].status;
-        printk("DEFAULT result %Xh, x_ID %Xh, Cmnd %p", 
-          Exchanges->fcExchange[ x_ID ].status, x_ID, 
-	  Exchanges->fcExchange[ x_ID ].Cmnd);
-
-	if (stat & INVALID_ARGS)	printk(" INVALID_ARGS ");
-	if (stat & LNKDWN_OSLS)		printk(" LNKDWN_OSLS ");
-	if (stat & LNKDWN_LASER)	printk(" LNKDWN_LASER ");
-	if (stat & OUTQUE_FULL)		printk(" OUTQUE_FULL ");
-	if (stat & DRIVERQ_FULL)	printk(" DRIVERQ_FULL ");
-	if (stat & SEST_FULL)		printk(" SEST_FULL ");
-	if (stat & BAD_ALPA)		printk(" BAD_ALPA ");
-	if (stat & OVERFLOW)		printk(" OVERFLOW ");
-	if (stat & COUNT_ERROR)		printk(" COUNT_ERROR ");
-	if (stat & LINKFAIL_RX)		printk(" LINKFAIL_RX ");
-	if (stat & ABORTSEQ_NOTIFY)	printk(" ABORTSEQ_NOTIFY ");
-	if (stat & LINKFAIL_TX)		printk(" LINKFAIL_TX ");
-	if (stat & HOSTPROG_ERR)	printk(" HOSTPROG_ERR ");
-	if (stat & FRAME_TO)		printk(" FRAME_TO ");
-	if (stat & INV_ENTRY)		printk(" INV_ENTRY ");
-	if (stat & SESTPROG_ERR)	printk(" SESTPROG_ERR ");
-	if (stat & OUTBOUND_TIMEOUT)	printk(" OUTBOUND_TIMEOUT ");
-	if (stat & INITIATOR_ABORT)	printk(" INITIATOR_ABORT ");
-	if (stat & MEMPOOL_FAIL)	printk(" MEMPOOL_FAIL ");
-	if (stat & FC2_TIMEOUT)		printk(" FC2_TIMEOUT ");
-	if (stat & TARGET_ABORT)	printk(" TARGET_ABORT ");
-	if (stat & EXCHANGE_QUEUED)	printk(" EXCHANGE_QUEUED ");
-	if (stat & PORTID_CHANGED)	printk(" PORTID_CHANGED ");
-	if (stat & DEVICE_REMOVED)	printk(" DEVICE_REMOVED ");
-	if (stat & SFQ_FRAME)		printk(" SFQ_FRAME ");
-	printk("\n");
+		if (Exchanges->fcExchange[x_ID].status)	// perhaps a Tach indicated problem,
+			// or abnormal exchange completion
+		{
+			// set FCP Link statistics
+
+			if (Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT)
+				fcChip->fcStats.timeouts++;
+			if (Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)
+				fcChip->fcStats.FC4aborted++;
+			if (Exchanges->fcExchange[x_ID].status & COUNT_ERROR)
+				fcChip->fcStats.CntErrors++;
+			if (Exchanges->fcExchange[x_ID].status & LINKFAIL_TX)
+				fcChip->fcStats.linkFailTX++;
+			if (Exchanges->fcExchange[x_ID].status & LINKFAIL_RX)
+				fcChip->fcStats.linkFailRX++;
+			if (Exchanges->fcExchange[x_ID].status & OVERFLOW)
+				fcChip->fcStats.CntErrors++;
+
+			// First, see if the Scsi upper level initiated an ABORT on this
+			// exchange...
+			if (Exchanges->fcExchange[x_ID].status == INITIATOR_ABORT) {
+				printk(" DID_ABORT, x_ID %Xh, Cmnd %p ", x_ID, Exchanges->fcExchange[x_ID].Cmnd);
+				goto CleanUpSestResources;	// (we don't expect Linux _aborts)
+			}
+			// Did our driver timeout the Exchange, or did Tachyon indicate
+			// a failure during transmission?  Ask for retry with "SOFT_ERROR"
+			else if (Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT) {
+//				printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
+//					x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+				Exchanges->fcExchange[x_ID].Cmnd->result = (DID_SOFT_ERROR << 16);
+			}
+			// Did frame(s) for an open exchange arrive in the SFQ,
+			// meaning the SEST was unable to process them?
+			else if (Exchanges->fcExchange[x_ID].status & SFQ_FRAME) {
+//				printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
+//					x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+				Exchanges->fcExchange[x_ID].Cmnd->result = (DID_SOFT_ERROR << 16);
+			}
+			// Did our driver timeout the Exchange, or did Tachyon indicate
+			// a failure during transmission?  Ask for retry with "SOFT_ERROR"
+			else if ((Exchanges->fcExchange[x_ID].status & LINKFAIL_TX) ||
+				 (Exchanges->fcExchange[x_ID].status & PORTID_CHANGED) || (Exchanges->fcExchange[x_ID].status & FRAME_TO) || (Exchanges->fcExchange[x_ID].status & INV_ENTRY) || (Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY))
+
+			{
+//				printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
+//					x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+				Exchanges->fcExchange[x_ID].Cmnd->result = (DID_SOFT_ERROR << 16);
 
-        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_ERROR <<16);
-      }
-    }
-    else    // definitely no Tach problem, but perhaps an FCP problem
-    {
-      // set FCP Link statistic
-      fcChip->fcStats.ok++;
-      cpqfcTSCheckandSnoopFCP( fcChip, x_ID);  // (will set ->result)    
-    }
 
-    cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd, 
-			fcChip, x_ID); // undo DMA mappings.
-    already_unmapped = 1;
-
-    // OK, we've set the Scsi "->result" field, so proceed with calling
-    // Linux Scsi "done" (if not NULL), and free any kernel memory we
-    // may have allocated for the exchange.
-
-  PCI_TRACEO( (ULONG)Exchanges->fcExchange[x_ID].Cmnd, 0xAC);
-    // complete the command back to upper Scsi drivers
-    if( Exchanges->fcExchange[ x_ID ].Cmnd->scsi_done != NULL)
-    {
-      // Calling "done" on an Linux _abort() aborted
-      // Cmnd causes a kernel panic trying to re-free mem.
-      // Actually, we shouldn't do anything with an _abort CMND
-      if( Exchanges->fcExchange[ x_ID ].Cmnd->result != (DID_ABORT<<16) )
-      {
-        PCI_TRACE(0xAC)
-	call_scsi_done(Exchanges->fcExchange[ x_ID ].Cmnd);
-      }
-      else
-      {
-	Exchanges->fcExchange[ x_ID ].Cmnd->SCp.sent_command = 0;
-//	printk(" not calling scsi_done on x_ID %Xh, Cmnd %p\n",
-//			x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
-      }
-    }
-    else{
-	Exchanges->fcExchange[ x_ID ].Cmnd->SCp.sent_command = 0;
-      printk(" x_ID %Xh, type %Xh, Cdb0 %Xh\n", x_ID,
-	Exchanges->fcExchange[ x_ID ].type, 
-	Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0]);	      
-      printk(" cpqfcTS: Null scsi_done function pointer!\n");
-    }
+			}
+			// e.g., a LOGOut happened, or device never logged back in.
+			else if (Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) {
+//				printk(" *LOGOut or timeout on login!* ");
+//				trigger?
+//				TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
+				Exchanges->fcExchange[x_ID].Cmnd->result = (DID_BAD_TARGET << 16);
+			}
+
+			// Did Tachyon indicate a CNT error?  We need further analysis
+			// to determine if the exchange is acceptable
+			else if (Exchanges->fcExchange[x_ID].status == COUNT_ERROR) {
+				u8 ScsiStatus;
+				FCP_STATUS_RESPONSE *pFcpStatus = (PFCP_STATUS_RESPONSE) & fcChip->SEST->RspHDR[x_ID].pl;
+
+				ScsiStatus = pFcpStatus->fcp_status >> 24;
+
+				// If the command is a SCSI Read/Write type, we don't tolerate
+				// count errors of any kind; assume the count error is due to
+				// a dropped frame and ask for retry...
+
+				if (((Exchanges->fcExchange[x_ID].Cmnd->cmnd[0] == 0x8) || (Exchanges->fcExchange[x_ID].Cmnd->cmnd[0] == 0x28) || (Exchanges->fcExchange[x_ID].Cmnd->cmnd[0] == 0xA) || (Exchanges->fcExchange[x_ID].Cmnd->cmnd[0] == 0x2A))
+				    && ScsiStatus == 0) {
+					// ask for retry
+//					printk("COUNT_ERROR retry, x_ID %Xh, status %Xh, Cmnd %p\n", 
+//						x_ID, Exchanges->fcExchange[ x_ID ].status,
+//						Exchanges->fcExchange[ x_ID ].Cmnd);
+					Exchanges->fcExchange[x_ID].Cmnd->result = (DID_SOFT_ERROR << 16);
+				}
+
+				else	// need more analysis
+				{
+					cpqfcTSCheckandSnoopFCP(fcChip, x_ID);	// (will set ->result)
+				}
+			}
+			// default: NOTE! We don't ever want to get here.  Getting here
+			// implies something new is happening that we've never had a test
+			// case for.  Need code maintenance!  Return "ERROR"
+			else {
+				unsigned int stat = Exchanges->fcExchange[x_ID].status;
+				printk("DEFAULT result %Xh, x_ID %Xh, Cmnd %p", Exchanges->fcExchange[x_ID].status, x_ID, Exchanges->fcExchange[x_ID].Cmnd);
+
+				if (stat & INVALID_ARGS)
+					printk(" INVALID_ARGS ");
+				if (stat & LNKDWN_OSLS)
+					printk(" LNKDWN_OSLS ");
+				if (stat & LNKDWN_LASER)
+					printk(" LNKDWN_LASER ");
+				if (stat & OUTQUE_FULL)
+					printk(" OUTQUE_FULL ");
+				if (stat & DRIVERQ_FULL)
+					printk(" DRIVERQ_FULL ");
+				if (stat & SEST_FULL)
+					printk(" SEST_FULL ");
+				if (stat & BAD_ALPA)
+					printk(" BAD_ALPA ");
+				if (stat & OVERFLOW)
+					printk(" OVERFLOW ");
+				if (stat & COUNT_ERROR)
+					printk(" COUNT_ERROR ");
+				if (stat & LINKFAIL_RX)
+					printk(" LINKFAIL_RX ");
+				if (stat & ABORTSEQ_NOTIFY)
+					printk(" ABORTSEQ_NOTIFY ");
+				if (stat & LINKFAIL_TX)
+					printk(" LINKFAIL_TX ");
+				if (stat & HOSTPROG_ERR)
+					printk(" HOSTPROG_ERR ");
+				if (stat & FRAME_TO)
+					printk(" FRAME_TO ");
+				if (stat & INV_ENTRY)
+					printk(" INV_ENTRY ");
+				if (stat & SESTPROG_ERR)
+					printk(" SESTPROG_ERR ");
+				if (stat & OUTBOUND_TIMEOUT)
+					printk(" OUTBOUND_TIMEOUT ");
+				if (stat & INITIATOR_ABORT)
+					printk(" INITIATOR_ABORT ");
+				if (stat & MEMPOOL_FAIL)
+					printk(" MEMPOOL_FAIL ");
+				if (stat & FC2_TIMEOUT)
+					printk(" FC2_TIMEOUT ");
+				if (stat & TARGET_ABORT)
+					printk(" TARGET_ABORT ");
+				if (stat & EXCHANGE_QUEUED)
+					printk(" EXCHANGE_QUEUED ");
+				if (stat & PORTID_CHANGED)
+					printk(" PORTID_CHANGED ");
+				if (stat & DEVICE_REMOVED)
+					printk(" DEVICE_REMOVED ");
+				if (stat & SFQ_FRAME)
+					printk(" SFQ_FRAME ");
+				printk("\n");
+
+				Exchanges->fcExchange[x_ID].Cmnd->result = (DID_ERROR << 16);
+			}
+		} else		// definitely no Tach problem, but perhaps an FCP problem
+		{
+			// set FCP Link statistic
+			fcChip->fcStats.ok++;
+			cpqfcTSCheckandSnoopFCP(fcChip, x_ID);	// (will set ->result)    
+		}
+
+		cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd, fcChip, x_ID);	// undo DMA mappings.
+		already_unmapped = 1;
+
+		// OK, we've set the Scsi "->result" field, so proceed with calling
+		// Linux Scsi "done" (if not NULL), and free any kernel memory we
+		// may have allocated for the exchange.
+
+		PCI_TRACEO((u32) Exchanges->fcExchange[x_ID].Cmnd, 0xAC);
+		// complete the command back to upper Scsi drivers
+		if (Exchanges->fcExchange[x_ID].Cmnd->scsi_done != NULL) {
+			// Calling "done" on an Linux _abort() aborted
+			// Cmnd causes a kernel panic trying to re-free mem.
+			// Actually, we shouldn't do anything with an _abort CMND
+			if (Exchanges->fcExchange[x_ID].Cmnd->result != (DID_ABORT << 16)) {
+				PCI_TRACE(0xAC)
+				    call_scsi_done(Exchanges->fcExchange[x_ID].Cmnd);
+			} else {
+				Exchanges->fcExchange[x_ID].Cmnd->SCp.sent_command = 0;
+//				printk(" not calling scsi_done on x_ID %Xh, Cmnd %p\n",
+//					x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+			}
+		} else {
+			Exchanges->fcExchange[x_ID].Cmnd->SCp.sent_command = 0;
+			printk(" x_ID %Xh, type %Xh, Cdb0 %Xh\n", x_ID, Exchanges->fcExchange[x_ID].type, Exchanges->fcExchange[x_ID].Cmnd->cmnd[0]);
+			printk(" cpqfcTS: Null scsi_done function pointer!\n");
+		}
 
 
-    // Now, clean up non-Scsi_Cmnd items...
+		// Now, clean up non-Scsi_Cmnd items...
 CleanUpSestResources:
-   
-    if (!already_unmapped) 
-	cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd, 
-			fcChip, x_ID); // undo DMA mappings.
-
-    // Was an Extended Scatter/Gather page allocated?  We know
-    // this by checking DWORD 4, bit 31 ("LOC") of SEST entry
-    if( !(fcChip->SEST->u[ x_ID ].IWE.Buff_Off & 0x80000000))
-    {
-      PSGPAGES p, next;
 
-      // extended S/G list was used -- Free the allocated ext. S/G pages
-      for (p = fcChip->SEST->sgPages[x_ID]; p != NULL; p = next) {
-	 next = p->next;
-	 kfree(p);
-      }
-      fcChip->SEST->sgPages[x_ID] = NULL;
-    }
-  
-    Exchanges->fcExchange[ x_ID ].Cmnd = NULL; 
-  }  // Done with FCP (SEST) exchanges
-
-
-  // the remaining logic is common to ALL Exchanges: 
-  // FCP(SEST) and LinkServ.
-
-  Exchanges->fcExchange[ x_ID ].type = 0; // there -- FREE!  
-  Exchanges->fcExchange[ x_ID ].status = 0; 
-
-  PCI_TRACEO( x_ID, 0xAC)
-     
-  
-  return;
-}   // (END of CompleteExchange function)
- 
+		if (!already_unmapped)
+			cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd, fcChip, x_ID);	// undo DMA mappings.
+
+		// Was an Extended Scatter/Gather page allocated?  We know
+		// this by checking DWORD 4, bit 31 ("LOC") of SEST entry
+		if (!(fcChip->SEST->u[x_ID].IWE.Buff_Off & 0x80000000)) {
+			PSGPAGES p, next;
+
+			// extended S/G list was used -- Free the allocated ext. S/G pages
+			for (p = fcChip->SEST->sgPages[x_ID]; p != NULL; p = next) {
+				next = p->next;
+				kfree(p);
+			}
+			fcChip->SEST->sgPages[x_ID] = NULL;
+		}
+
+		Exchanges->fcExchange[x_ID].Cmnd = NULL;
+	}			// Done with FCP (SEST) exchanges
+
+
+	// the remaining logic is common to ALL Exchanges: 
+	// FCP(SEST) and LinkServ.
+
+	Exchanges->fcExchange[x_ID].type = 0;	// there -- FREE!  
+	Exchanges->fcExchange[x_ID].status = 0;
+
+	PCI_TRACEO(x_ID, 0xAC)
+}				// (END of CompleteExchange function)
+
 
 
 
@@ -6249,161 +5140,137 @@
 // device types, etc., to facilitate the Fibre-Channel to SCSI
 // "mapping".  
 // (Watch for BIG Endian confusion on some payload fields)
-void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID)
+void cpqfcTSCheckandSnoopFCP(PTACHYON fcChip, u32 x_ID)
 {
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  Scsi_Cmnd *Cmnd = Exchanges->fcExchange[ x_ID].Cmnd;
-  FCP_STATUS_RESPONSE *pFcpStatus = 
-    (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
-  UCHAR ScsiStatus;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	Scsi_Cmnd *Cmnd = Exchanges->fcExchange[x_ID].Cmnd;
+	FCP_STATUS_RESPONSE *pFcpStatus = (PFCP_STATUS_RESPONSE) & fcChip->SEST->RspHDR[x_ID].pl;
+	u8 ScsiStatus;
 
-  ScsiStatus = pFcpStatus->fcp_status >>24;
+	ScsiStatus = pFcpStatus->fcp_status >> 24;
 
 #ifdef FCP_COMPLETION_DBG
-  printk("ScsiStatus = 0x%X\n", ScsiStatus);
-#endif	
+	printk("ScsiStatus = 0x%X\n", ScsiStatus);
+#endif
 
-  // First, check FCP status
-  if( pFcpStatus->fcp_status & FCP_RSP_LEN_VALID )
-  {
-    // check response code (RSP_CODE) -- most popular is bad len
-    // 1st 4 bytes of rsp info -- only byte 3 interesting
-    if( pFcpStatus->fcp_rsp_info & FCP_DATA_LEN_NOT_BURST_LEN )
-    { 
+	// First, check FCP status
+	if (pFcpStatus->fcp_status & FCP_RSP_LEN_VALID) {
+		// check response code (RSP_CODE) -- most popular is bad len
+		// 1st 4 bytes of rsp info -- only byte 3 interesting
+		if (pFcpStatus->fcp_rsp_info & FCP_DATA_LEN_NOT_BURST_LEN) {
 
-      // do we EVER get here?
-      printk("cpqfcTS: FCP data len not burst len, x_ID %Xh\n", x_ID);
-    }
-  }
+			// do we EVER get here?
+			printk("cpqfcTS: FCP data len not burst len, x_ID %Xh\n", x_ID);
+		}
+	}
+	// for now, go by the ScsiStatus, and manipulate certain
+	// commands when necessary...
+	if (ScsiStatus == 0)	// SCSI status byte "good"?
+	{
+		Cmnd->result = 0;	// everything's OK
 
-  // for now, go by the ScsiStatus, and manipulate certain
-  // commands when necessary...
-  if( ScsiStatus == 0) // SCSI status byte "good"?
-  {
-    Cmnd->result = 0; // everything's OK
+		if ((Cmnd->cmnd[0] == INQUIRY)) {
+			u8 *InquiryData = Cmnd->request_buffer;
+			PFC_LOGGEDIN_PORT pLoggedInPort;
+
+			// We need to manipulate INQUIRY
+			// strings for COMPAQ RAID controllers to force
+			// Linux to scan additional LUNs.  Namely, set
+			// the Inquiry string byte 2 (ANSI-approved version)
+			// to 2.
+
+			if (!memcmp(&InquiryData[8], "COMPAQ", 6)) {
+				InquiryData[2] = 0x2;	// claim SCSI-2 compliance,
+				// so multiple LUNs may be scanned.
+				// (no SCSI-2 problems known in CPQ)
+			}
+			// snoop the Inquiry to detect Disk, Tape, etc. type
+			// (search linked list for the port_id we sent INQUIRY to)
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// DON'T search Scsi Nexus (we will set it)
+							   Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF, NULL,	// DON'T search linked list for FC WWN
+							   NULL);	// DON'T care about end of list
+
+			if (pLoggedInPort) {
+				pLoggedInPort->ScsiNexus.InqDeviceType = InquiryData[0];
+			} else {
+				printk("cpqfcTS: can't find LoggedIn FC port %06X for INQUIRY\n", Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF);
+			}
+		}
+	}
 
-    if( (Cmnd->cmnd[0] == INQUIRY)) 
-    {
-      UCHAR *InquiryData = Cmnd->request_buffer;
-      PFC_LOGGEDIN_PORT pLoggedInPort;
+	// Scsi Status not good -- pass it back to caller 
 
-      // We need to manipulate INQUIRY
-      // strings for COMPAQ RAID controllers to force
-      // Linux to scan additional LUNs.  Namely, set
-      // the Inquiry string byte 2 (ANSI-approved version)
-      // to 2.
-
-      if( !memcmp( &InquiryData[8], "COMPAQ", 6 ))
-      {
-        InquiryData[2] = 0x2;  // claim SCSI-2 compliance,
-                               // so multiple LUNs may be scanned.
-                               // (no SCSI-2 problems known in CPQ)
-      }
-        
-      // snoop the Inquiry to detect Disk, Tape, etc. type
-      // (search linked list for the port_id we sent INQUIRY to)
-      pLoggedInPort = fcFindLoggedInPort( fcChip,
-        NULL,     // DON'T search Scsi Nexus (we will set it)
-        Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,        
-        NULL,     // DON'T search linked list for FC WWN
-        NULL);    // DON'T care about end of list
- 
-      if( pLoggedInPort )
-      {
-        pLoggedInPort->ScsiNexus.InqDeviceType = InquiryData[0];
-      }
-      else
-      {
-	printk("cpqfcTS: can't find LoggedIn FC port %06X for INQUIRY\n",
-          Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
-      }
-    }
-  }
+	else {
+		Cmnd->result = ScsiStatus;	// SCSI status byte is 1st
 
+		// check for valid "sense" data
 
-  // Scsi Status not good -- pass it back to caller 
+		if (pFcpStatus->fcp_status & FCP_SNS_LEN_VALID) {	// limit Scsi Sense field length!
+			int SenseLen = pFcpStatus->fcp_sns_len >> 24;	// (BigEndian) lower byte
 
-  else
-  {
-    Cmnd->result = ScsiStatus; // SCSI status byte is 1st
-    
-    // check for valid "sense" data
+			SenseLen = SenseLen > sizeof(Cmnd->sense_buffer) ? sizeof(Cmnd->sense_buffer) : SenseLen;
 
-    if( pFcpStatus->fcp_status & FCP_SNS_LEN_VALID ) 
-    {            // limit Scsi Sense field length!
-      int SenseLen = pFcpStatus->fcp_sns_len >>24; // (BigEndian) lower byte
-      
-      SenseLen = SenseLen > sizeof( Cmnd->sense_buffer) ? 
-        sizeof( Cmnd->sense_buffer) : SenseLen;
-	   
-
-#ifdef FCP_COMPLETION_DBG	    
-      printk("copy sense_buffer %p, len %d, result %Xh\n",
-        Cmnd->sense_buffer, SenseLen, Cmnd->result);
-#endif	  
-
-      // NOTE: There is some dispute over the FCP response
-      // format.  Most FC devices assume that FCP_RSP_INFO
-      // is 8 bytes long, in spite of the fact that FCP_RSP_LEN
-      // is (virtually) always 0 and the field is "invalid".  
-      // Some other devices assume that
-      // the FCP_SNS_INFO begins after FCP_RSP_LEN bytes (i.e. 0)
-      // when the FCP_RSP is invalid (this almost appears to be
-      // one of those "religious" issues).
-      // Consequently, we test the usual position of FCP_SNS_INFO
-      // for 7Xh, since the SCSI sense format says the first
-      // byte ("error code") should be 0x70 or 0x71.  In practice,
-      // we find that every device does in fact have 0x70 or 0x71
-      // in the first byte position, so this test works for all
-      // FC devices.  
-      // (This logic is especially effective for the CPQ/DEC HSG80
-      // & HSG60 controllers).
-
-      if( (pFcpStatus->fcp_sns_info[0] & 0x70) == 0x70 )
-        memcpy( Cmnd->sense_buffer, 
-          &pFcpStatus->fcp_sns_info[0], SenseLen);
-      else
-      {
-        unsigned char *sbPtr = 
-		(unsigned char *)&pFcpStatus->fcp_sns_info[0];
-        sbPtr -= 8;  // back up 8 bytes hoping to find the
-	             // start of the sense buffer
-        memcpy( Cmnd->sense_buffer, sbPtr, SenseLen);
-      }
-
-      // in the special case of Device Reset, tell upper layer
-      // to immediately retry (with SOFT_ERROR status)
-      // look for Sense Key Unit Attention (0x6) with ASC Device
-      // Reset (0x29)
-      //	    printk("SenseLen %d, Key = 0x%X, ASC = 0x%X\n",
-      //		    SenseLen, Cmnd->sense_buffer[2], 
-      //                   Cmnd->sense_buffer[12]);
-      if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
-	        (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
-      {
-        Cmnd->result |= (DID_SOFT_ERROR << 16); // "Host" status byte 3rd
-      }
- 
-      // check for SenseKey "HARDWARE ERROR", ASC InternalTargetFailure
-      else if(  ((Cmnd->sense_buffer[2] & 0xF) == 0x4) &&  // "hardware error"
-      	        (Cmnd->sense_buffer[12] == 0x44) ) // Addtl. Sense Code 
-      {
+
+#ifdef FCP_COMPLETION_DBG
+			printk("copy sense_buffer %p, len %d, result %Xh\n", Cmnd->sense_buffer, SenseLen, Cmnd->result);
+#endif
+
+			// NOTE: There is some dispute over the FCP response
+			// format.  Most FC devices assume that FCP_RSP_INFO
+			// is 8 bytes long, in spite of the fact that FCP_RSP_LEN
+			// is (virtually) always 0 and the field is "invalid".  
+			// Some other devices assume that
+			// the FCP_SNS_INFO begins after FCP_RSP_LEN bytes (i.e. 0)
+			// when the FCP_RSP is invalid (this almost appears to be
+			// one of those "religious" issues).
+			// Consequently, we test the usual position of FCP_SNS_INFO
+			// for 7Xh, since the SCSI sense format says the first
+			// byte ("error code") should be 0x70 or 0x71.  In practice,
+			// we find that every device does in fact have 0x70 or 0x71
+			// in the first byte position, so this test works for all
+			// FC devices.  
+			// (This logic is especially effective for the CPQ/DEC HSG80
+			// & HSG60 controllers).
+
+			if ((pFcpStatus->fcp_sns_info[0] & 0x70) == 0x70)
+				memcpy(Cmnd->sense_buffer, &pFcpStatus->fcp_sns_info[0], SenseLen);
+			else {
+				unsigned char *sbPtr = (unsigned char *) &pFcpStatus->fcp_sns_info[0];
+				sbPtr -= 8;	// back up 8 bytes hoping to find the
+				// start of the sense buffer
+				memcpy(Cmnd->sense_buffer, sbPtr, SenseLen);
+			}
+
+			// in the special case of Device Reset, tell upper layer
+			// to immediately retry (with SOFT_ERROR status)
+			// look for Sense Key Unit Attention (0x6) with ASC Device
+			// Reset (0x29)
+			//            printk("SenseLen %d, Key = 0x%X, ASC = 0x%X\n",
+			//                    SenseLen, Cmnd->sense_buffer[2], 
+			//                   Cmnd->sense_buffer[12]);
+			if (((Cmnd->sense_buffer[2] & 0xF) == 0x6) && (Cmnd->sense_buffer[12] == 0x29))	// Sense Code "reset"
+			{
+				Cmnd->result |= (DID_SOFT_ERROR << 16);	// "Host" status byte 3rd
+			}
+			// check for SenseKey "HARDWARE ERROR", ASC InternalTargetFailure
+			else if (((Cmnd->sense_buffer[2] & 0xF) == 0x4) &&	// "hardware error"
+				 (Cmnd->sense_buffer[12] == 0x44))	// Addtl. Sense Code 
+			{
 //        printk("HARDWARE_ERROR, Channel/Target/Lun %d/%d/%d\n",
-//		Cmnd->channel, Cmnd->target, Cmnd->lun);
-      	Cmnd->result |= (DID_ERROR << 16); // "Host" status byte 3rd
-      }
-      
-    }  // (end of sense len valid)
+//              Cmnd->channel, Cmnd->target, Cmnd->lun);
+				Cmnd->result |= (DID_ERROR << 16);	// "Host" status byte 3rd
+			}
 
-    // there is no sense data to help out Linux's Scsi layers...
-    // We'll just return the Scsi status and hope he will "do the 
-    // right thing"
-    else
-    {
-      // as far as we know, the Scsi status is sufficient
-      Cmnd->result |= (DID_OK << 16); // "Host" status byte 3rd
-    }
-  }
+		}		// (end of sense len valid)
+
+		// there is no sense data to help out Linux's Scsi layers...
+		// We'll just return the Scsi status and hope he will "do the 
+		// right thing"
+		else {
+			// as far as we know, the Scsi status is sufficient
+			Cmnd->result |= (DID_OK << 16);	// "Host" status byte 3rd
+		}
+	}
 }
 
 
@@ -6413,118 +5280,108 @@
 // remember BIG ENDIAN payload - DWord values must be byte-reversed
 // (hence the affinity for byte pointer building).
 
-static int build_FCP_payload( Scsi_Cmnd *Cmnd, 
-      UCHAR* payload, ULONG type, ULONG fcp_dl )
+static int build_FCP_payload(Scsi_Cmnd * Cmnd, u8 * payload, u32 type, u32 fcp_dl)
 {
-  int i;
+	int i;
 
-  
-  switch( type)
-  {
-		  
-    case SCSI_IWE: 
-    case SCSI_IRE:        
-      // 8 bytes FCP_LUN
-      // Peripheral Device or Volume Set addressing, and LUN mapping
-      // When the FC port was looked up, we copied address mode
-      // and any LUN mask to the scratch pad SCp.phase & .mode
-
-      *payload++ = (UCHAR)Cmnd->SCp.phase;
-
-      // Now, because of "lun masking" 
-      // (aka selective storage presentation),
-      // the contiguous Linux Scsi lun number may not match the
-      // device's lun number, so we may have to "map".  
-      
-      *payload++ = (UCHAR)Cmnd->SCp.have_data_in;
-      
-      // We don't know of anyone in the FC business using these 
-      // extra "levels" of addressing.  In fact, confusion still exists
-      // just using the FIRST level... ;-)
-      
-      *payload++ = 0;  // 2nd level addressing
-      *payload++ = 0;
-      *payload++ = 0;  // 3rd level addressing
-      *payload++ = 0;
-      *payload++ = 0;  // 4th level addressing
-      *payload++ = 0;
-
-      // 4 bytes Control Field FCP_CNTL
-      *payload++ = 0;    // byte 0: (MSB) reserved
-      *payload++ = 0;    // byte 1: task codes
-
-                         // byte 2: task management flags
-      // another "use" of the spare field to accomplish TDR
-      // note combination needed
-      if( (Cmnd->cmnd[0] == RELEASE) &&
-          (Cmnd->SCp.buffers_residual == FCP_TARGET_RESET) )
-      {
-        Cmnd->cmnd[0] = 0;    // issue "Test Unit Ready" for TDR
-        *payload++ = 0x20;    // target device reset bit
-      }
-      else
-        *payload++ = 0;    // no TDR
-		      // byte 3: (LSB) execution management codes
-		      // bit 0 write, bit 1 read (don't set together)
-      
-      if( fcp_dl != 0 )
-      {
-        if( type == SCSI_IWE )         // WRITE
-          *payload++ = 1;
-        else                           // READ
-          *payload++ = 2;
-      }
-      else
-      {
-	// On some devices, if RD or WR bits are set,
-	// and fcp_dl is 0, they will generate an error on the command.
-	// (i.e., if direction is specified, they insist on a length).
-	*payload++ = 0;                // no data (necessary for CPQ)
-      }
-
-
-      // NOTE: clean this up if/when MAX_COMMAND_SIZE is increased to 16
-      // FCP_CDB allows 16 byte SCSI command descriptor blk;
-      // Linux SCSI CDB array is MAX_COMMAND_SIZE (12 at this time...)
-      for( i=0; (i < Cmnd->cmd_len) && i < MAX_COMMAND_SIZE; i++)
-	*payload++ = Cmnd->cmnd[i];
-
-      if( Cmnd->cmd_len == 16 )
-      {
-        memcpy( payload, &Cmnd->SCp.buffers_residual, 4);
-      }
-      payload+= (16 - i);  
-
-		      // FCP_DL is largest number of expected data bytes
-		      // per CDB (i.e. read/write command)
-      *payload++ = (UCHAR)(fcp_dl >>24);  // (MSB) 8 bytes data len FCP_DL
-      *payload++ = (UCHAR)(fcp_dl >>16);
-      *payload++ = (UCHAR)(fcp_dl >>8);
-      *payload++ = (UCHAR)fcp_dl;    // (LSB)
-      break;
-
-    case SCSI_TWE:          // need FCP_XFER_RDY
-      *payload++ = 0;     // (4 bytes) DATA_RO (MSB byte 0)
-      *payload++ = 0;
-      *payload++ = 0;
-      *payload++ = 0;     // LSB (byte 3)
-			     // (4 bytes) BURST_LEN
-			     // size of following FCP_DATA payload
-      *payload++ = (UCHAR)(fcp_dl >>24);  // (MSB) 8 bytes data len FCP_DL
-      *payload++ = (UCHAR)(fcp_dl >>16);
-      *payload++ = (UCHAR)(fcp_dl >>8);
-      *payload++ = (UCHAR)fcp_dl;    // (LSB)
-		       // 4 bytes RESERVED
-      *payload++ = 0;
-      *payload++ = 0;
-      *payload++ = 0;
-      *payload++ = 0;
-      break;
 
-    default:
-      break;
-  }
+	switch (type) {
 
-  return 0;
-}
+	case SCSI_IWE:
+	case SCSI_IRE:
+		// 8 bytes FCP_LUN
+		// Peripheral Device or Volume Set addressing, and LUN mapping
+		// When the FC port was looked up, we copied address mode
+		// and any LUN mask to the scratch pad SCp.phase & .mode
+
+		*payload++ = (u8) Cmnd->SCp.phase;
+
+		// Now, because of "lun masking" 
+		// (aka selective storage presentation),
+		// the contiguous Linux Scsi lun number may not match the
+		// device's lun number, so we may have to "map".  
+
+		*payload++ = (u8) Cmnd->SCp.have_data_in;
+
+		// We don't know of anyone in the FC business using these 
+		// extra "levels" of addressing.  In fact, confusion still exists
+		// just using the FIRST level... ;-)
+
+		*payload++ = 0;	// 2nd level addressing
+		*payload++ = 0;
+		*payload++ = 0;	// 3rd level addressing
+		*payload++ = 0;
+		*payload++ = 0;	// 4th level addressing
+		*payload++ = 0;
+
+		// 4 bytes Control Field FCP_CNTL
+		*payload++ = 0;	// byte 0: (MSB) reserved
+		*payload++ = 0;	// byte 1: task codes
+
+		// byte 2: task management flags
+		// another "use" of the spare field to accomplish TDR
+		// note combination needed
+		if ((Cmnd->cmnd[0] == RELEASE) && (Cmnd->SCp.buffers_residual == FCP_TARGET_RESET)) {
+			Cmnd->cmnd[0] = 0;	// issue "Test Unit Ready" for TDR
+			*payload++ = 0x20;	// target device reset bit
+		} else
+			*payload++ = 0;	// no TDR
+		// byte 3: (LSB) execution management codes
+		// bit 0 write, bit 1 read (don't set together)
+
+		if (fcp_dl != 0) {
+			if (type == SCSI_IWE)	// WRITE
+				*payload++ = 1;
+			else	// READ
+				*payload++ = 2;
+		} else {
+			// On some devices, if RD or WR bits are set,
+			// and fcp_dl is 0, they will generate an error on the command.
+			// (i.e., if direction is specified, they insist on a length).
+			*payload++ = 0;	// no data (necessary for CPQ)
+		}
+
+
+		// NOTE: clean this up if/when MAX_COMMAND_SIZE is increased to 16
+		// FCP_CDB allows 16 byte SCSI command descriptor blk;
+		// Linux SCSI CDB array is MAX_COMMAND_SIZE (12 at this time...)
+		for (i = 0; (i < Cmnd->cmd_len) && i < MAX_COMMAND_SIZE; i++)
+			*payload++ = Cmnd->cmnd[i];
+
+		if (Cmnd->cmd_len == 16) {
+			memcpy(payload, &Cmnd->SCp.buffers_residual, 4);
+		}
+		payload += (16 - i);
 
+		// FCP_DL is largest number of expected data bytes
+		// per CDB (i.e. read/write command)
+		*payload++ = (u8) (fcp_dl >> 24);	// (MSB) 8 bytes data len FCP_DL
+		*payload++ = (u8) (fcp_dl >> 16);
+		*payload++ = (u8) (fcp_dl >> 8);
+		*payload++ = (u8) fcp_dl;	// (LSB)
+		break;
+
+	case SCSI_TWE:		// need FCP_XFER_RDY
+		*payload++ = 0;	// (4 bytes) DATA_RO (MSB byte 0)
+		*payload++ = 0;
+		*payload++ = 0;
+		*payload++ = 0;	// LSB (byte 3)
+		// (4 bytes) BURST_LEN
+		// size of following FCP_DATA payload
+		*payload++ = (u8) (fcp_dl >> 24);	// (MSB) 8 bytes data len FCP_DL
+		*payload++ = (u8) (fcp_dl >> 16);
+		*payload++ = (u8) (fcp_dl >> 8);
+		*payload++ = (u8) fcp_dl;	// (LSB)
+		// 4 bytes RESERVED
+		*payload++ = 0;
+		*payload++ = 0;
+		*payload++ = 0;
+		*payload++ = 0;
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/gdth.c linux-2.4.21/drivers/scsi/gdth.c
--- linux-2.4.20/drivers/scsi/gdth.c	2001-11-09 22:05:06.000000000 +0000
+++ linux-2.4.21/drivers/scsi/gdth.c	2002-12-18 18:58:10.000000000 +0000
@@ -4,9 +4,11 @@
  * Intel Corporation:  Storage RAID Controllers                         *
  *                                                                      *
  * gdth.c                                                               *
- * Copyright (C) 1995-01 ICP vortex, an Intel company,  Achim Leubner   *
+ * Copyright (C) 1995-02 ICP vortex, an Intel company,  Achim Leubner   *
+ * <achim.leubner@intel.com>                                            *
  *                                                                      *
- * <achim@vortex.de>                                                    *
+ * Additions/Fixes: Boji Tony Kannanthanam                              *
+ * <boji.t.kannanthanam@intel.com>                                      *
  *                                                                      *
  * This program is free software; you can redistribute it and/or modify *
  * it under the terms of the GNU General Public License as published    *
@@ -22,9 +24,23 @@
  * along with this kernel; if not, write to the Free Software           *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
  *                                                                      *
- * Tested with Linux 1.2.13, ..., 2.2.19, ..., 2.4.7                    *
+ * Tested with Linux 1.2.13, ..., 2.2.20, ..., 2.4.18                   *
  *                                                                      *
  * $Log: gdth.c,v $
+ * Revision 1.61  2002/10/03 09:35:22  boji
+ * Fixed SCREENSERVICE intialisation in SMP cases.
+ * Added checks for gdth_polling before GDTH_HA_LOCK
+ *
+ * Revision 1.60  2002/02/05 09:35:22  achim
+ * MODULE_LICENSE only if kernel >= 2.4.11
+ *
+ * Revision 1.59  2002/01/30 09:46:33  achim
+ * Small changes
+ *
+ * Revision 1.58  2002/01/29 15:30:02  achim
+ * Set default value of shared_access to Y
+ * New status S_CACHE_RESERV for clustering added
+ *
  * Revision 1.57  2001/08/21 11:16:35  achim
  * Bugfix free_irq()
  *
@@ -232,7 +248,7 @@
  * Initial revision
  *
  ************************************************************************/
-#ident "$Id: gdth.c,v 1.57 2001/08/21 11:16:35 achim Exp $" 
+#ident "$Id: gdth.c,v 1.60 2002/02/05 09:35:22 achim Exp $" 
 
 /* All GDT Disk Array Controllers are fully supported by this driver.
  * This includes the PCI/EISA/ISA SCSI Disk Array Controllers and the
@@ -269,7 +285,7 @@
  *
  * The default values are: "gdth=disable:N,reserve_mode:1,reverse_scan:N,
  *                          max_ids:127,rescan:N,virt_ctr:N,hdr_channel:0,
- *                          shared_access:N".
+ *                          shared_access:Y".
  * Here is another example: "gdth=reserve_list:0,1,2,0,0,1,3,0,rescan:Y".
  * 
  * When loading the gdth driver as a module, the same options are available. 
@@ -669,7 +685,7 @@
 /* map channels to virtual controllers */
 static int virt_ctr = 0;
 /* shared access */
-static int shared_access = 0;
+static int shared_access = 1;
 
 #ifdef MODULE
 #if LINUX_VERSION_CODE >= 0x02011A
@@ -685,6 +701,8 @@
 MODULE_PARM(virt_ctr, "i");
 MODULE_PARM(shared_access, "i");
 MODULE_AUTHOR("Achim Leubner");
+#endif
+#if LINUX_VERSION_CODE >= 0x02040B
 MODULE_LICENSE("GPL");
 #endif
 #endif
@@ -2342,12 +2360,13 @@
     register Scsi_Cmnd *nscp;
     unchar b, t, firsttime;
     unchar this_cmd, next_cmd;
-    ulong flags;
+    ulong flags = 0;
     int cmd_index;
 
     TRACE(("gdth_next() hanum %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
-    GDTH_LOCK_HA(ha, flags);
+    if (!gdth_polling) 
+    	GDTH_LOCK_HA(ha, flags);
 
     ha->cmd_cnt = ha->cmd_offs_dpmem = 0;
     this_cmd = firsttime = TRUE;
@@ -2442,10 +2461,12 @@
                 if (!nscp->SCp.have_data_in)
                     nscp->SCp.have_data_in++;
                 else {
-                    GDTH_UNLOCK_HA(ha,flags);
+                    if (!gdth_polling) 
+                        GDTH_UNLOCK_HA(ha,flags);
                     /* io_request_lock already active ! */
                     nscp->scsi_done(nscp);
-                    GDTH_LOCK_HA(ha,flags);
+                    if (!gdth_polling) 
+                    	GDTH_LOCK_HA(ha,flags);
                 }
             }
         } else
@@ -2470,10 +2491,12 @@
             if (!nscp->SCp.have_data_in)
                 nscp->SCp.have_data_in++;
             else {
-                GDTH_UNLOCK_HA(ha,flags);
+                if (!gdth_polling) 
+                	GDTH_UNLOCK_HA(ha,flags);
                 /* io_request_lock already active ! */      
                 nscp->scsi_done(nscp);
-                GDTH_LOCK_HA(ha,flags);
+                if (!gdth_polling) 
+                	GDTH_LOCK_HA(ha,flags);
             }
         } else {
             switch (nscp->cmnd[0]) {
@@ -2499,16 +2522,20 @@
                     if (!nscp->SCp.have_data_in)
                         nscp->SCp.have_data_in++;
                     else {
-                        GDTH_UNLOCK_HA(ha,flags);
+                	if (!gdth_polling) 
+                        	GDTH_UNLOCK_HA(ha,flags);
                         /* io_request_lock already active ! */      
                         nscp->scsi_done(nscp);
-                        GDTH_LOCK_HA(ha,flags);
+                	if (!gdth_polling) 
+                        	GDTH_LOCK_HA(ha,flags);
                     }
                 } else if (gdth_internal_cache_cmd(hanum,nscp)) {
-                    GDTH_UNLOCK_HA(ha,flags);
+                    if (!gdth_polling) 
+                    	GDTH_UNLOCK_HA(ha,flags);
                     /* io_request_lock already active ! */      
                     nscp->scsi_done(nscp);
-                    GDTH_LOCK_HA(ha,flags);
+                    if (!gdth_polling) 
+                    	GDTH_LOCK_HA(ha,flags);
                 }
                 break;
 
@@ -2523,10 +2550,12 @@
                     if (!nscp->SCp.have_data_in)
                         nscp->SCp.have_data_in++;
                     else {
-                        GDTH_UNLOCK_HA(ha,flags);
+                    	if (!gdth_polling) 
+                        	GDTH_UNLOCK_HA(ha,flags);
                         /* io_request_lock already active ! */      
                         nscp->scsi_done(nscp);
-                        GDTH_LOCK_HA(ha,flags);
+                    	if (!gdth_polling) 
+                        	GDTH_LOCK_HA(ha,flags);
                     }
                 } else {
                     nscp->cmnd[3] = (ha->hdr[t].devtype&1) ? 1:0;
@@ -2561,10 +2590,12 @@
                     if (!nscp->SCp.have_data_in)
                         nscp->SCp.have_data_in++;
                     else {
-                        GDTH_UNLOCK_HA(ha,flags);
+                    	if (!gdth_polling) 
+                        	GDTH_UNLOCK_HA(ha,flags);
                         /* io_request_lock already active ! */      
                         nscp->scsi_done(nscp);
-                        GDTH_LOCK_HA(ha,flags);
+                    	if (!gdth_polling) 
+                        	GDTH_LOCK_HA(ha,flags);
                     }
                 } else if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
                     this_cmd = FALSE;
@@ -2580,10 +2611,12 @@
                 if (!nscp->SCp.have_data_in)
                     nscp->SCp.have_data_in++;
                 else {
-                    GDTH_UNLOCK_HA(ha,flags);
+                    if (!gdth_polling) 
+                    	GDTH_UNLOCK_HA(ha,flags);
                     /* io_request_lock already active ! */  
                     nscp->scsi_done(nscp);
-                    GDTH_LOCK_HA(ha,flags);
+                    if (!gdth_polling) 
+                    	GDTH_LOCK_HA(ha,flags);
                 }
                 break;
             }
@@ -2603,7 +2636,8 @@
         gdth_release_event(hanum);
     }
 
-    GDTH_UNLOCK_HA(ha, flags);
+    if (!gdth_polling) 
+    	GDTH_UNLOCK_HA(ha, flags);
 
     if (gdth_polling && ha->cmd_cnt > 0) {
         if (!gdth_wait(hanum,cmd_index,POLL_TIMEOUT))
@@ -3511,9 +3545,13 @@
                     ha->hdr[scp->target].cluster_type &= ~CLUSTER_RESERVED;
                 }
                 memset((char*)scp->sense_buffer,0,16);
-                scp->sense_buffer[0] = 0x70;
-                scp->sense_buffer[2] = NOT_READY;
-                scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+                if (ha->status == (ushort)S_CACHE_RESERV) {
+                    scp->result = (DID_OK << 16) | (RESERVATION_CONFLICT << 1);
+                } else {
+                    scp->sense_buffer[0] = 0x70;
+                    scp->sense_buffer[2] = NOT_READY;
+                    scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+                }
 #if LINUX_VERSION_CODE >= 0x010300
                 if (scp->done != gdth_scsi_done)
 #endif  
@@ -3980,6 +4018,7 @@
         return 0;
     }
 
+    printk("GDT: Storage RAID Controller Driver. Version: %s \n",GDTH_VERSION_STR);
     /* initializations */
     gdth_polling = TRUE; b = 0;
     gdth_clear_events();
@@ -4104,6 +4143,9 @@
             break;
         if (gdth_search_eisa(eisa_slot)) {      /* controller found */
             shp = scsi_register(shtp,sizeof(gdth_ext_str));
+	    if(shp == NULL)
+		    continue;
+
             ha = HADATA(shp);
             if (!gdth_init_eisa(eisa_slot,ha)) {
                 scsi_unregister(shp);
@@ -4208,6 +4250,7 @@
         gdth_pci_str pcistr[MAXHA];
 
         cnt = gdth_search_pci(pcistr);
+	printk("GDT: Found %d PCI Storage RAID Controllers\n",cnt);
         gdth_sort_pci(pcistr,cnt);
         for (ctr = 0; ctr < cnt; ++ctr) {
             if (gdth_ctr_count >= MAXHA)
@@ -4219,8 +4262,8 @@
                 continue;
             }
             /* controller found and initialized */
-            printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n",
-                   pcistr[ctr].bus,PCI_SLOT(pcistr[ctr].device_fn),ha->irq);
+            printk("GDT CTR%d: Configuring GDT-PCI HA at %d/%d IRQ %u\n",
+                   ctr,pcistr[ctr].bus,PCI_SLOT(pcistr[ctr].device_fn),ha->irq);
 
 #if LINUX_VERSION_CODE >= 0x010346 
             if (request_irq(ha->irq, gdth_interrupt,
@@ -4696,9 +4739,7 @@
     del_timer(&gdth_timer);
 #endif
 #if LINUX_VERSION_CODE >= 0x020100
-#if LINUX_VERSION_CODE < 0x020322
     unregister_reboot_notifier(&gdth_notifier);
-#endif
     return NOTIFY_OK;
 #endif
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/gdth.h linux-2.4.21/drivers/scsi/gdth.h
--- linux-2.4.20/drivers/scsi/gdth.h	2001-09-07 16:28:37.000000000 +0000
+++ linux-2.4.21/drivers/scsi/gdth.h	2002-12-18 18:58:06.000000000 +0000
@@ -2,15 +2,15 @@
 #define _GDTH_H
 
 /*
- * Header file for the GDT ISA/EISA/PCI Disk Array Controller driver for Linux
+ * Header file for the GDT Disk Array/Storage RAID controllers driver for Linux
  * 
- * gdth.h Copyright (C) 1995-01 ICP vortex Computersysteme GmbH, Achim Leubner
+ * gdth.h Copyright (C) 1995-02 ICP vortex, an Intel company, Achim Leubner
  * See gdth.c for further informations and 
  * below for supported controller types
  *
- * <achim@vortex.de>
+ * <achim.leubner@intel.com>
  *
- * $Id: gdth.h,v 1.44 2001/08/21 11:19:05 achim Exp $
+ * $Id: gdth.h,v 1.46 2002/02/05 09:39:53 achim Exp $
  */
 
 #include <linux/version.h>
@@ -29,9 +29,9 @@
 /* defines, macros */
 
 /* driver version */
-#define GDTH_VERSION_STR        "2.03"
+#define GDTH_VERSION_STR        "2.05"
 #define GDTH_VERSION            2
-#define GDTH_SUBVERSION         3
+#define GDTH_SUBVERSION         5
 
 /* protocol version */
 #define PROTOCOL_VERSION        1
@@ -265,6 +265,7 @@
 #define S_CACHE_UNKNOWN 12                      /* cache serv.: drive unknown */
 #define S_RAW_SCSI      12                      /* raw serv.: target error */
 #define S_RAW_ILL       0xff                    /* raw serv.: illegal */
+#define S_CACHE_RESERV	-24			/* cache: reserv. conflict */	
 
 /* timeout values */
 #define INIT_RETRIES    100000                  /* 100000 * 1ms = 100s */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/gdth_proc.c linux-2.4.21/drivers/scsi/gdth_proc.c
--- linux-2.4.20/drivers/scsi/gdth_proc.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/scsi/gdth_proc.c	2002-12-18 18:58:08.000000000 +0000
@@ -1464,7 +1464,7 @@
             timer_table[SCSI_TIMER].expires = jiffies + timeout;
             timer_active |= 1 << SCSI_TIMER;
         } else {
-            if (time_before(jiffies + timeout, timer_table[SCSI_TIMER].expires))
+            if (time_before(jiffies + timeout < timer_table[SCSI_TIMER].expires))
                 timer_table[SCSI_TIMER].expires = jiffies + timeout;
         }
     }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/ide-scsi.c linux-2.4.21/drivers/scsi/ide-scsi.c
--- linux-2.4.20/drivers/scsi/ide-scsi.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/scsi/ide-scsi.c	2002-12-18 18:58:02.000000000 +0000
@@ -1,7 +1,8 @@
 /*
- * linux/drivers/scsi/ide-scsi.c	Version 0.9		Jul   4, 1999
+ * linux/drivers/scsi/ide-scsi.c	Version 0.93    June 10, 2002
  *
  * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il>
+ * Copyright (C) 2001 - 2002 Andre Hedrick <andre@linux-ide.org>
  */
 
 /*
@@ -27,11 +28,19 @@
  *                        detection of devices with CONFIG_SCSI_MULTI_LUN
  * Ver 0.8   Feb 05 99   Optical media need translation too. Reverse 0.7.
  * Ver 0.9   Jul 04 99   Fix a bug in SG_SET_TRANSFORM.
+ * Ver 0.91  Jan 06 02   Added 'ignore' parameter when ide-scsi is a module
+ *                        so that use of scsi emulation can be made independent
+ *                        of load order when other IDE drivers are modules.
+ *                        Chris Ebenezer <chriseb@pobox.com>
+ * Ver 0.92  Mar 21 02   Include DevFs support
+ *                        Borsenkow Andrej <Andrej.Borsenkow@mow.siemens.ru>
+ * Ver 0.93  Jun 10 02   Fix "off by one" error in transforms
  */
 
-#define IDESCSI_VERSION "0.9"
+#define IDESCSI_VERSION "0.93"
 
 #include <linux/module.h>
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
@@ -53,76 +62,76 @@
 #include "ide-scsi.h"
 #include <scsi/sg.h>
 
-#define IDESCSI_DEBUG_LOG		0
+#define IDESCSI_DEBUG_LOG	0
 
 typedef struct idescsi_pc_s {
-	u8 c[12];				/* Actual packet bytes */
-	int request_transfer;			/* Bytes to transfer */
-	int actually_transferred;		/* Bytes actually transferred */
-	int buffer_size;			/* Size of our data buffer */
-	struct request *rq;			/* The corresponding request */
-	byte *buffer;				/* Data buffer */
-	byte *current_position;			/* Pointer into the above buffer */
-	struct scatterlist *sg;			/* Scatter gather table */
-	int b_count;				/* Bytes transferred from current entry */
-	Scsi_Cmnd *scsi_cmd;			/* SCSI command */
-	void (*done)(Scsi_Cmnd *);		/* Scsi completion routine */
-	unsigned long flags;			/* Status/Action flags */
-	unsigned long timeout;			/* Command timeout */
+	u8 c[12];			/* Actual packet bytes */
+	int request_transfer;		/* Bytes to transfer */
+	int actually_transferred;	/* Bytes actually transferred */
+	int buffer_size;		/* Size of our data buffer */
+	struct request *rq;		/* The corresponding request */
+	u8 *buffer;			/* Data buffer */
+	u8 *current_position;		/* Pointer into the above buffer */
+	struct scatterlist *sg;		/* Scatter gather table */
+	int b_count;			/* Bytes transferred from current entry */
+	Scsi_Cmnd *scsi_cmd;		/* SCSI command */
+	void (*done)(Scsi_Cmnd *);	/* Scsi completion routine */
+	unsigned long flags;		/* Status/Action flags */
+	unsigned long timeout;		/* Command timeout */
 } idescsi_pc_t;
 
 /*
  *	Packet command status bits.
  */
-#define PC_DMA_IN_PROGRESS		0	/* 1 while DMA in progress */
-#define PC_WRITING			1	/* Data direction */
-#define PC_TRANSFORM			2	/* transform SCSI commands */
+#define PC_DMA_IN_PROGRESS	0	/* 1 while DMA in progress */
+#define PC_WRITING		1	/* Data direction */
+#define PC_TRANSFORM		2	/* transform SCSI commands */
 
 /*
  *	SCSI command transformation layer
  */
-#define IDESCSI_TRANSFORM		0	/* Enable/Disable transformation */
-#define IDESCSI_SG_TRANSFORM		1	/* /dev/sg transformation */
+#define IDESCSI_TRANSFORM	0	/* Enable/Disable transformation */
+#define IDESCSI_SG_TRANSFORM	1	/* /dev/sg transformation */
 
 /*
  *	Log flags
  */
-#define IDESCSI_LOG_CMD			0	/* Log SCSI commands */
+#define IDESCSI_LOG_CMD		0	/* Log SCSI commands */
+
+#define IDESCSI_DEVFS
 
 typedef struct {
 	ide_drive_t *drive;
-	idescsi_pc_t *pc;			/* Current packet command */
-	unsigned long flags;			/* Status/Action flags */
-	unsigned long transform;		/* SCSI cmd translation layer */
-	unsigned long log;			/* log flags */
+	idescsi_pc_t *pc;		/* Current packet command */
+	unsigned long flags;		/* Status/Action flags */
+	unsigned long transform;	/* SCSI cmd translation layer */
+	unsigned long log;		/* log flags */
+	int id;				/* id */
+#ifdef IDESCSI_DEVFS
+	devfs_handle_t de;		/* pointer to IDE device */
+#endif /* IDESCSI_DEVFS */
 } idescsi_scsi_t;
 
 /*
  *	Per ATAPI device status bits.
  */
-#define IDESCSI_DRQ_INTERRUPT		0	/* DRQ interrupt device */
+#define IDESCSI_DRQ_INTERRUPT	0	/* DRQ interrupt device */
 
 /*
  *	ide-scsi requests.
  */
-#define IDESCSI_PC_RQ			90
-
-/*
- *	Bits of the interrupt reason register.
- */
-#define IDESCSI_IREASON_COD	0x1		/* Information transferred is command */
-#define IDESCSI_IREASON_IO	0x2		/* The device requests us to read */
+#define IDESCSI_PC_RQ		90
 
 static void idescsi_discard_data (ide_drive_t *drive, unsigned int bcount)
 {
 	while (bcount--)
-		IN_BYTE (IDE_DATA_REG);
+		(void) HWIF(drive)->INB(IDE_DATA_REG);
 }
 
 static void idescsi_output_zeros (ide_drive_t *drive, unsigned int bcount)
 {
 	while (bcount--)
-		OUT_BYTE (0, IDE_DATA_REG);
+		HWIF(drive)->OUTB(0, IDE_DATA_REG);
 }
 
 /*
@@ -134,13 +143,15 @@
 
 	while (bcount) {
 		if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
-			printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n");
-			idescsi_discard_data (drive, bcount);
+			printk(KERN_ERR "ide-scsi: scatter gather "
+				"table too small, discarding data\n");
+			idescsi_discard_data(drive, bcount);
 			return;
 		}
-		count = IDE_MIN (pc->sg->length - pc->b_count, bcount);
-		atapi_input_bytes (drive, pc->sg->address + pc->b_count, count);
-		bcount -= count; pc->b_count += count;
+		count = IDE_MIN(pc->sg->length - pc->b_count, bcount);
+		HWIF(drive)->atapi_input_bytes(drive, pc->sg->address + pc->b_count, count);
+		bcount -= count;
+		pc->b_count += count;
 		if (pc->b_count == pc->sg->length) {
 			pc->sg++;
 			pc->b_count = 0;
@@ -154,13 +165,15 @@
 
 	while (bcount) {
 		if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
-			printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n");
-			idescsi_output_zeros (drive, bcount);
+			printk(KERN_ERR "ide-scsi: scatter gather table "
+				"too small, padding with zeros\n");
+			idescsi_output_zeros(drive, bcount);
 			return;
 		}
-		count = IDE_MIN (pc->sg->length - pc->b_count, bcount);
-		atapi_output_bytes (drive, pc->sg->address + pc->b_count, count);
-		bcount -= count; pc->b_count += count;
+		count = IDE_MIN(pc->sg->length - pc->b_count, bcount);
+		HWIF(drive)->atapi_output_bytes(drive, pc->sg->address + pc->b_count, count);
+		bcount -= count;
+		pc->b_count += count;
 		if (pc->b_count == pc->sg->length) {
 			pc->sg++;
 			pc->b_count = 0;
@@ -181,26 +194,38 @@
 		return;
 	if (drive->media == ide_cdrom || drive->media == ide_optical) {
 		if (c[0] == READ_6 || c[0] == WRITE_6) {
-			c[8] = c[4];		c[5] = c[3];		c[4] = c[2];
-			c[3] = c[1] & 0x1f;	c[2] = 0;		c[1] &= 0xe0;
+			c[8] = c[4];
+			c[5] = c[3];
+			c[4] = c[2];
+			c[3] = c[1] & 0x1f;
+			c[2] = 0;
+			c[1] &= 0xe0;
 			c[0] += (READ_10 - READ_6);
 		}
 		if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) {
+			unsigned short new_len;
 			if (!scsi_buf)
 				return;
 			if ((atapi_buf = kmalloc(pc->buffer_size + 4, GFP_ATOMIC)) == NULL)
 				return;
 			memset(atapi_buf, 0, pc->buffer_size + 4);
 			memset (c, 0, 12);
-			c[0] = sc[0] | 0x40;	c[1] = sc[1];		c[2] = sc[2];
-			c[8] = sc[4] + 4;	c[9] = sc[5];
-			if (sc[4] + 4 > 255)
-				c[7] = sc[4] + 4 - 255;
+			c[0] = sc[0] | 0x40;
+			c[1] = sc[1];
+			c[2] = sc[2];
+ 			new_len = sc[4] + 4;
+			c[8] = new_len;
+			c[7] = new_len >> 8;
+			c[9] = sc[5];
 			if (c[0] == MODE_SELECT_10) {
-				atapi_buf[1] = scsi_buf[0];	/* Mode data length */
-				atapi_buf[2] = scsi_buf[1];	/* Medium type */
-				atapi_buf[3] = scsi_buf[2];	/* Device specific parameter */
-				atapi_buf[7] = scsi_buf[3];	/* Block descriptor length */
+				/* Mode data length */
+				atapi_buf[1] = scsi_buf[0];
+				/* Medium type */
+				atapi_buf[2] = scsi_buf[1];
+				/* Device specific parameter */
+				atapi_buf[3] = scsi_buf[2];
+				/* Block descriptor length */
+				atapi_buf[7] = scsi_buf[3];
 				memcpy(atapi_buf + 8, scsi_buf + 4, pc->buffer_size - 4);
 			}
 			pc->buffer = atapi_buf;
@@ -220,15 +245,21 @@
 		return;
 	if (drive->media == ide_cdrom || drive->media == ide_optical) {
 		if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) {
-			scsi_buf[0] = atapi_buf[1];		/* Mode data length */
-			scsi_buf[1] = atapi_buf[2];		/* Medium type */
-			scsi_buf[2] = atapi_buf[3];		/* Device specific parameter */
-			scsi_buf[3] = atapi_buf[7];		/* Block descriptor length */
+			/* Mode data length */
+			scsi_buf[0] = atapi_buf[1];
+			/* Medium type */
+			scsi_buf[1] = atapi_buf[2];
+			/* Device specific parameter */
+			scsi_buf[2] = atapi_buf[3];
+			/* Block descriptor length */
+			scsi_buf[3] = atapi_buf[7];
 			memcpy(scsi_buf + 4, atapi_buf + 8, pc->request_transfer - 8);
 		}
 		if (pc->c[0] == INQUIRY) {
-			scsi_buf[2] |= 2;			/* ansi_revision */
-			scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2;	/* response data format */
+			/* ansi_revision */
+			scsi_buf[2] |= 2;
+			/* response data format */
+			scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2;
 		}
 	}
 	if (atapi_buf && atapi_buf != scsi_buf)
@@ -256,47 +287,83 @@
 	printk("]\n");
 }
 
-static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
+static int idescsi_do_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		add_blkdev_randomness(MAJOR(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return ret;
+}
+
+static int idescsi_end_request (ide_drive_t *drive, int uptodate)
 {
-	ide_drive_t *drive = hwgroup->drive;
 	idescsi_scsi_t *scsi = drive->driver_data;
-	struct request *rq = hwgroup->rq;
+	struct request *rq = HWGROUP(drive)->rq;
 	idescsi_pc_t *pc = (idescsi_pc_t *) rq->buffer;
 	int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
 	u8 *scsi_buf;
 	unsigned long flags;
 
 	if (rq->cmd != IDESCSI_PC_RQ) {
-		ide_end_request (uptodate, hwgroup);
-		return;
+		idescsi_do_end_request(drive, uptodate);
+		return 0;
 	}
-	ide_end_drive_cmd (drive, 0, 0);
+	ide_end_drive_cmd(drive, 0, 0);
 	if (rq->errors >= ERROR_MAX) {
 		pc->scsi_cmd->result = DID_ERROR << 16;
 		if (log)
-			printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number);
+			printk("ide-scsi: %s: I/O error for %lu\n",
+				drive->name, pc->scsi_cmd->serial_number);
 	} else if (rq->errors) {
 		pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16);
 		if (log)
-			printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number);
+			printk("ide-scsi: %s: check condition for %lu\n",
+				drive->name, pc->scsi_cmd->serial_number);
 	} else {
 		pc->scsi_cmd->result = DID_OK << 16;
-		idescsi_transform_pc2 (drive, pc);
+		idescsi_transform_pc2(drive, pc);
 		if (log) {
-			printk ("ide-scsi: %s: suc %lu", drive->name, pc->scsi_cmd->serial_number);
-			if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) {
+			printk("ide-scsi: %s: suc %lu", drive->name,
+				pc->scsi_cmd->serial_number);
+			if (!test_bit(PC_WRITING, &pc->flags) &&
+			    pc->actually_transferred &&
+			    pc->actually_transferred <= 1024 &&
+			    pc->buffer) {
 				printk(", rst = ");
 				scsi_buf = pc->scsi_cmd->request_buffer;
 				hexdump(scsi_buf, IDE_MIN(16, pc->scsi_cmd->request_bufflen));
 			} else printk("\n");
 		}
 	}
-	spin_lock_irqsave(&io_request_lock,flags);	
+	spin_lock_irqsave(&io_request_lock, flags);	
 	pc->done(pc->scsi_cmd);
-	spin_unlock_irqrestore(&io_request_lock,flags);
-	idescsi_free_bh (rq->bh);
-	kfree(pc); kfree(rq);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	idescsi_free_bh(rq->bh);
+	kfree(pc);
+	kfree(rq);
 	scsi->pc = NULL;
+	return 0;
 }
 
 static inline unsigned long get_timeout(idescsi_pc_t *pc)
@@ -310,84 +377,112 @@
 static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
-	byte status, ireason;
-	int bcount;
-	idescsi_pc_t *pc=scsi->pc;
+	idescsi_pc_t *pc = scsi->pc;
 	struct request *rq = pc->rq;
+	atapi_bcount_t bcount;
+	atapi_status_t status;
+	atapi_ireason_t ireason;
+	atapi_feature_t feature;
 	unsigned int temp;
 
 #if IDESCSI_DEBUG_LOG
-	printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n");
+	printk(KERN_INFO "ide-scsi: Reached idescsi_pc_intr "
+		"interrupt handler\n");
 #endif /* IDESCSI_DEBUG_LOG */
 
-	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+	if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
 #if IDESCSI_DEBUG_LOG
-		printk ("ide-scsi: %s: DMA complete\n", drive->name);
+		printk("ide-scsi: %s: DMA complete\n", drive->name);
 #endif /* IDESCSI_DEBUG_LOG */
-		pc->actually_transferred=pc->request_transfer;
-		(void) (HWIF(drive)->dmaproc(ide_dma_end, drive));
+		pc->actually_transferred = pc->request_transfer;
+		(void) (HWIF(drive)->ide_dma_end(drive));
 	}
 
-	status = GET_STAT();						/* Clear the interrupt */
+	feature.all = 0;
+	/* Clear the interrupt */
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 
-	if ((status & DRQ_STAT) == 0) {					/* No more interrupts */
+	if (!status.b.drq) {
+		/* No more interrupts */
 		if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
-			printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
-		ide__sti();
-		if (status & ERR_STAT)
+			printk(KERN_INFO "Packet command completed, %d "
+				"bytes transferred\n",
+				pc->actually_transferred);
+		local_irq_enable();
+		if (status.b.check)
 			rq->errors++;
-		idescsi_end_request (1, HWGROUP(drive));
+		idescsi_end_request(drive, 1);
 		return ide_stopped;
 	}
-	bcount = IN_BYTE (IDE_BCOUNTH_REG) << 8 | IN_BYTE (IDE_BCOUNTL_REG);
-	ireason = IN_BYTE (IDE_IREASON_REG);
 
-	if (ireason & IDESCSI_IREASON_COD) {
-		printk (KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n");
-		return ide_do_reset (drive);
-	}
-	if (ireason & IDESCSI_IREASON_IO) {
-		temp = pc->actually_transferred + bcount;
-		if ( temp > pc->request_transfer) {
+	bcount.b.low	= HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	bcount.b.high	= HWIF(drive)->INB(IDE_BCOUNTH_REG);
+	ireason.all	= HWIF(drive)->INB(IDE_IREASON_REG);
+
+	if (ireason.b.cod) {
+		printk(KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n");
+		return ide_do_reset(drive);
+	}
+	if (ireason.b.io) {
+		temp = pc->actually_transferred + bcount.all;
+		if (temp > pc->request_transfer) {
 			if (temp > pc->buffer_size) {
-				printk (KERN_ERR "ide-scsi: The scsi wants to send us more data than expected - discarding data\n");
+				printk(KERN_ERR "ide-scsi: The scsi wants to "
+					"send us more data than expected "
+					"- discarding data\n");
+				printk(KERN_ERR "ide-scsi: [");
+				hexdump(pc->c, 12);
+				printk("]\n");
+				printk(KERN_ERR "ide-scsi: expected %d got %d limit %d\n",
+					pc->request_transfer, temp, pc->buffer_size);
 				temp = pc->buffer_size - pc->actually_transferred;
 				if (temp) {
 					clear_bit(PC_WRITING, &pc->flags);
 					if (pc->sg)
 						idescsi_input_buffers(drive, pc, temp);
 					else
-						atapi_input_bytes(drive, pc->current_position, temp);
-					printk(KERN_ERR "ide-scsi: transferred %d of %d bytes\n", temp, bcount);
+						HWIF(drive)->atapi_input_bytes(drive, pc->current_position, temp);
+					printk(KERN_ERR "ide-scsi: transferred %d of %d bytes\n", temp, bcount.all);
 				}
 				pc->actually_transferred += temp;
 				pc->current_position += temp;
-				idescsi_discard_data (drive,bcount - temp);
-				ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);
+				idescsi_discard_data(drive, bcount.all - temp);
+				if (HWGROUP(drive)->handler != NULL)
+					BUG();
+				ide_set_handler(drive,
+						&idescsi_pc_intr,
+						get_timeout(pc),
+						NULL);
 				return ide_started;
 			}
 #if IDESCSI_DEBUG_LOG
-			printk (KERN_NOTICE "ide-scsi: The scsi wants to send us more data than expected - allowing transfer\n");
+			printk(KERN_NOTICE "ide-scsi: The scsi wants to send "
+				"us more data than expected - "
+				"allowing transfer\n");
 #endif /* IDESCSI_DEBUG_LOG */
 		}
 	}
-	if (ireason & IDESCSI_IREASON_IO) {
+	if (ireason.b.io) {
 		clear_bit(PC_WRITING, &pc->flags);
 		if (pc->sg)
-			idescsi_input_buffers (drive, pc, bcount);
+			idescsi_input_buffers(drive, pc, bcount.all);
 		else
-			atapi_input_bytes (drive,pc->current_position,bcount);
+			HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all);
 	} else {
 		set_bit(PC_WRITING, &pc->flags);
 		if (pc->sg)
-			idescsi_output_buffers (drive, pc, bcount);
+			idescsi_output_buffers(drive, pc, bcount.all);
 		else
-			atapi_output_bytes (drive,pc->current_position,bcount);
+			HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all);
 	}
-	pc->actually_transferred+=bcount;				/* Update the current position */
-	pc->current_position+=bcount;
-
-	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);	/* And set the interrupt handler again */
+	/* Update the current position */
+	pc->actually_transferred += bcount.all;
+	pc->current_position += bcount.all;
+
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	/* And set the interrupt handler again */
+	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);
 	return ide_started;
 }
 
@@ -395,20 +490,29 @@
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
 	idescsi_pc_t *pc = scsi->pc;
-	byte ireason;
+	atapi_ireason_t ireason;
 	ide_startstop_t startstop;
 
-	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
-		printk (KERN_ERR "ide-scsi: Strange, packet command initiated yet DRQ isn't asserted\n");
+	if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+		printk(KERN_ERR "ide-scsi: Strange, packet command "
+			"initiated yet DRQ isn't asserted\n");
 		return startstop;
 	}
-	ireason = IN_BYTE (IDE_IREASON_REG);
-	if ((ireason & (IDESCSI_IREASON_IO | IDESCSI_IREASON_COD)) != IDESCSI_IREASON_COD) {
-		printk (KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while issuing a packet command\n");
-		return ide_do_reset (drive);
+
+	ireason.all	= HWIF(drive)->INB(IDE_IREASON_REG);
+
+	if (!ireason.b.cod || ireason.b.io) {
+		printk(KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while "
+				"issuing a packet command\n");
+		return ide_do_reset(drive);
 	}
-	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);	/* Set the interrupt routine */
-	atapi_output_bytes (drive, scsi->pc->c, 12);			/* Send the actual packet */
+
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	/* Set the interrupt routine */
+	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);
+	/* Send the actual packet */
+	HWIF(drive)->atapi_output_bytes(drive, scsi->pc->c, 12);
 	return ide_started;
 }
 
@@ -418,36 +522,50 @@
 static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
-	int bcount;
+	atapi_feature_t feature;
+	atapi_bcount_t bcount;
 	struct request *rq = pc->rq;
-	int dma_ok = 0;
-
-	scsi->pc=pc;							/* Set the current packet command */
-	pc->actually_transferred=0;					/* We haven't transferred any data yet */
-	pc->current_position=pc->buffer;
-	bcount = IDE_MIN (pc->request_transfer, 63 * 1024);		/* Request to transfer the entire buffer at once */
 
-	if (drive->using_dma && rq->bh)
-		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+	/* Set the current packet command */
+	scsi->pc = pc;
+	/* We haven't transferred any data yet */
+	pc->actually_transferred = 0;
+	pc->current_position = pc->buffer;
+	/* Request to transfer the entire buffer at once */
+	bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024);
+
+	if (drive->using_dma && rq->bh) {
+		if (test_bit(PC_WRITING, &pc->flags))
+			feature.b.dma = !HWIF(drive)->ide_dma_write(drive);
+		else
+			feature.b.dma = !HWIF(drive)->ide_dma_read(drive);
+	}
 
-	SELECT_DRIVE(HWIF(drive), drive);
+	SELECT_DRIVE(drive);
 	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
-	OUT_BYTE (dma_ok,IDE_FEATURE_REG);
-	OUT_BYTE (bcount >> 8,IDE_BCOUNTH_REG);
-	OUT_BYTE (bcount & 0xff,IDE_BCOUNTL_REG);
-
-	if (dma_ok) {
-		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
-	}
-	if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
-		ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc), NULL);
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
+		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+	HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);
+	HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
+	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
+
+	if (feature.b.dma) {
+		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->ide_dma_begin(drive));
+	}
+	if (test_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
+		ide_set_handler(drive,
+				&idescsi_transfer_pc,
+				get_timeout(pc),
+				NULL);
+		/* Issue the packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return ide_started;
 	} else {
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
-		return idescsi_transfer_pc (drive);
+		/* Issue the packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
+		return idescsi_transfer_pc(drive);
 	}
 }
 
@@ -457,19 +575,30 @@
 static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 #if IDESCSI_DEBUG_LOG
-	printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
-	printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+	printk(KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",
+		rq->rq_status, (unsigned int) rq->rq_dev, rq->cmd, rq->errors);
+	printk(KERN_INFO "sector: %ld, nr_sectors: %ld, "
+		"current_nr_sectors: %ld\n", rq->sector,
+		rq->nr_sectors, rq->current_nr_sectors);
 #endif /* IDESCSI_DEBUG_LOG */
 
 	if (rq->cmd == IDESCSI_PC_RQ) {
-		return idescsi_issue_pc (drive, (idescsi_pc_t *) rq->buffer);
+		return idescsi_issue_pc(drive, (idescsi_pc_t *) rq->buffer);
 	}
-	printk (KERN_ERR "ide-scsi: %s: unsupported command in request queue (%x)\n", drive->name, rq->cmd);
-	idescsi_end_request (0,HWGROUP (drive));
+	printk(KERN_ERR "ide-scsi: %s: unsupported command in request "
+		"queue (%x)\n", drive->name, rq->cmd);
+	idescsi_end_request(drive, 0);
 	return ide_stopped;
 }
 
-static int idescsi_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
+static int idescsi_do_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	/* need to figure out how to parse scsi-atapi media type */
+
+	return -EINVAL;
+}
+
+static int idescsi_ide_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	MOD_INC_USE_COUNT;
 	return 0;
@@ -482,6 +611,7 @@
 
 static ide_drive_t *idescsi_drives[MAX_HWIFS * MAX_DRIVES];
 static int idescsi_initialized = 0;
+static int drive_count = 0;
 
 static void idescsi_add_settings(ide_drive_t *drive)
 {
@@ -502,34 +632,58 @@
  */
 static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi, int id)
 {
+	int minor = (drive->select.b.unit) << PARTN_BITS;
+
 	DRIVER(drive)->busy++;
 	idescsi_drives[id] = drive;
 	drive->driver_data = scsi;
 	drive->ready_stat = 0;
-	memset (scsi, 0, sizeof (idescsi_scsi_t));
+	memset(scsi, 0, sizeof(idescsi_scsi_t));
 	scsi->drive = drive;
+	scsi->id = id;
 	if (drive->id && (drive->id->config & 0x0060) == 0x20)
-		set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);
+		set_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags);
 	set_bit(IDESCSI_TRANSFORM, &scsi->transform);
 	clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
 #if IDESCSI_DEBUG_LOG
 	set_bit(IDESCSI_LOG_CMD, &scsi->log);
 #endif /* IDESCSI_DEBUG_LOG */
 	idescsi_add_settings(drive);
+#ifdef IDESCSI_DEVFS
+	scsi->de = devfs_register(drive->de, "generic", DEVFS_FL_DEFAULT,
+					HWIF(drive)->major, minor,
+					S_IFBLK | S_IRUSR | S_IWUSR,
+					ide_fops, NULL);
+#endif /* IDESCSI_DEVFS */
+	drive_count++;
+	DRIVER(drive)->busy--;
 }
 
 static int idescsi_cleanup (ide_drive_t *drive)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
 
-	if (ide_unregister_subdriver (drive))
+	if (ide_unregister_subdriver(drive)) {
+		printk("%s: %s: failed to unregister! \n",
+			__FUNCTION__, drive->name);
+		printk("%s: usage %d, busy %d, driver %p, Dbusy %d\n",
+			drive->name, drive->usage, drive->busy,
+			drive->driver, DRIVER(drive)->busy);
 		return 1;
+	}
+	idescsi_drives[scsi->id] = NULL;
+#ifdef IDESCSI_DEVFS
+	if (scsi->de)
+		devfs_unregister(scsi->de);
+#endif /* IDESCSI_DEVFS */
 	drive->driver_data = NULL;
-	kfree (scsi);
+	kfree(scsi);
+	drive_count--;
 	return 0;
 }
 
-int idescsi_reinit(ide_drive_t *drive);
+int idescsi_init(void);
+int idescsi_attach(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -539,15 +693,23 @@
 	version:		IDESCSI_VERSION,
 	media:			ide_scsi,
 	busy:			0,
+#ifdef CONFIG_IDEDMA_ONLYDISK
+	supports_dma:		0,
+#else
 	supports_dma:		1,
+#endif
 	supports_dsc_overlap:	0,
 	cleanup:		idescsi_cleanup,
 	standby:		NULL,
+	suspend:		NULL,
+	resume:			NULL,
 	flushcache:		NULL,
 	do_request:		idescsi_do_request,
 	end_request:		idescsi_end_request,
-	ioctl:			NULL,
-	open:			idescsi_open,
+	sense:			NULL,
+	error:			NULL,
+	ioctl:			idescsi_do_ioctl,
+	open:			idescsi_ide_open,
 	release:		idescsi_ide_release,
 	media_change:		NULL,
 	revalidate:		NULL,
@@ -555,12 +717,12 @@
 	capacity:		NULL,
 	special:		NULL,
 	proc:			NULL,
-	reinit:			idescsi_reinit,
+	init:			idescsi_init,
+	attach:			idescsi_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 };
 
-int idescsi_init (void);
 static ide_module_t idescsi_module = {
 	IDE_DRIVER_MODULE,
 	idescsi_init,
@@ -568,51 +730,91 @@
 	NULL
 };
 
-int idescsi_reinit (ide_drive_t *drive)
+int idescsi_attach (ide_drive_t *drive)
 {
-#if 0
 	idescsi_scsi_t *scsi;
-	byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
-	int i, failed, id;
-
-	if (!idescsi_initialized)
-		return 0;
-	for (i = 0; i < MAX_HWIFS * MAX_DRIVES; i++)
-		idescsi_drives[i] = NULL;
+	u8 media[] = {	TYPE_DISK,		/* 0x00 */
+			TYPE_TAPE,		/* 0x01 */
+			TYPE_PRINTER,		/* 0x02 */
+			TYPE_PROCESSOR,		/* 0x03 */
+			TYPE_WORM,		/* 0x04 */
+			TYPE_ROM,		/* 0x05 */
+			TYPE_SCANNER,		/* 0x06 */
+			TYPE_MOD,		/* 0x07 */
+			255};
+	int i = 0, ret = 0, id = 0;
+//	int id = 2 * HWIF(drive)->index + drive->select.b.unit;
+//	int id = drive_count + 1;
+
+	for (id = 0; id < MAX_HWIFS*MAX_DRIVES; id++)
+		if (idescsi_drives[id] == NULL)
+			break;
+
+	printk("%s: id = %d\n", drive->name, id);
+
+	if ((!idescsi_initialized) || (drive->media == ide_disk)) {
+		printk(KERN_ERR "ide-scsi: (%sinitialized) %s: "
+				"media-type (%ssupported)\n",
+			(idescsi_initialized) ? "" : "! ",
+			drive->name,
+			(drive->media == ide_disk) ? "! " : "");
+		return (drive->media == ide_disk) ? 2 : 0;
+	}
 
 	MOD_INC_USE_COUNT;
+
 	for (i = 0; media[i] != 255; i++) {
-		failed = 0;
-		while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) {
+		if (drive->media != media[i])
+			continue;
+		else
+			break;
+	}
 
-			if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) {
-				printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name);
-				continue;
-			}
-			if (ide_register_subdriver (drive, &idescsi_driver, IDE_SUBDRIVER_VERSION)) {
-				printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name);
-				kfree (scsi);
-				continue;
-			}
-			for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++);
-				idescsi_setup (drive, scsi, id);
-			failed--;
-		}
+	if ((scsi = (idescsi_scsi_t *) kmalloc(sizeof(idescsi_scsi_t), GFP_KERNEL)) == NULL) {
+		printk(KERN_ERR "ide-scsi: %s: Can't allocate a scsi "
+			"structure\n", drive->name);
+		ret = 1;
+		goto bye_game_over;
 	}
-	ide_register_module(&idescsi_module);
+	if (ide_register_subdriver(drive, &idescsi_driver,
+			IDE_SUBDRIVER_VERSION)) {
+		printk(KERN_ERR "ide-scsi: %s: Failed to register the "
+			"driver with ide.c\n", drive->name);
+		kfree(scsi);
+		ret = 1;
+		goto bye_game_over;
+	}
+
+	idescsi_setup(drive, scsi, id);
+
+//	scan_scsis(HBA, 1, channel, id, lun);
+bye_game_over:
 	MOD_DEC_USE_COUNT;
-#endif
-	return 0;
+	return ret;
 }
 
-/*
- *	idescsi_init will register the driver for each scsi.
- */
+#ifdef MODULE
+/* options */
+char *ignore = NULL;
+
+MODULE_PARM(ignore, "s");
+#endif
+
 int idescsi_init (void)
 {
+#ifdef CLASSIC_BUILTINS_METHOD
 	ide_drive_t *drive;
 	idescsi_scsi_t *scsi;
-	byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
+	u8 media[] = {  TYPE_DISK,		/* 0x00 */
+			TYPE_TAPE,		/* 0x01 */
+			TYPE_PRINTER,		/* 0x02 */
+			TYPE_PROCESSOR,		/* 0x03 */
+			TYPE_WORM,		/* 0x04 */
+			TYPE_ROM,		/* 0x05 */
+			TYPE_SCANNER,		/* 0x06 */
+			TYPE_MOD,		/* 0x07 */
+			255};
+
 	int i, failed, id;
 
 	if (idescsi_initialized)
@@ -623,22 +825,47 @@
 	MOD_INC_USE_COUNT;
 	for (i = 0; media[i] != 255; i++) {
 		failed = 0;
-		while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) {
+		while ((drive = ide_scan_devices(media[i],
+				idescsi_driver.name, NULL, failed++)) != NULL) {
+#ifdef MODULE
+			/* skip drives we were told to ignore */
+			if (ignore != NULL && strstr(ignore, drive->name)) {
+				printk("ide-scsi: ignoring drive %s\n",
+					drive->name);
+				continue;
+			}
+#endif
 
-			if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) {
-				printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name);
+		if ((scsi = (idescsi_scsi_t *) kmalloc(sizeof(idescsi_scsi_t), GFP_KERNEL)) == NULL) {
+				printk(KERN_ERR "ide-scsi: %s: Can't allocate "
+					"a scsi structure\n", drive->name);
 				continue;
 			}
-			if (ide_register_subdriver (drive, &idescsi_driver, IDE_SUBDRIVER_VERSION)) {
-				printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name);
-				kfree (scsi);
+			if (ide_register_subdriver(drive, &idescsi_driver,
+					IDE_SUBDRIVER_VERSION)) {
+				printk(KERN_ERR "ide-scsi: %s: Failed to "
+					"register the driver with ide.c\n",
+					drive->name);
+				kfree(scsi);
 				continue;
 			}
-			for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++);
-				idescsi_setup (drive, scsi, id);
+			for (id = 0;
+				id < MAX_HWIFS*MAX_DRIVES && idescsi_drives[id];
+					id++);
+				idescsi_setup(drive, scsi, id);
 			failed--;
 		}
 	}
+#else /* ! CLASSIC_BUILTINS_METHOD */
+	int i;
+
+	if (idescsi_initialized)
+		return 0;
+	idescsi_initialized = 1;
+	for (i = 0; i < MAX_HWIFS * MAX_DRIVES; i++)
+		idescsi_drives[i] = NULL;
+	MOD_INC_USE_COUNT;
+#endif /* CLASSIC_BUILTINS_METHOD */
 	ide_register_module(&idescsi_module);
 	MOD_DEC_USE_COUNT;
 	return 0;
@@ -652,9 +879,11 @@
 
 	host_template->proc_name = "ide-scsi";
 	host = scsi_register(host_template, 0);
-	if(host == NULL)
+	if (host == NULL) {
+		printk(KERN_WARNING "%s: host failure!\n", __FUNCTION__);
 		return 0;
-		
+	}
+
 	for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++)
 		last_lun = IDE_MAX(last_lun, idescsi_drives[id]->last_lun);
 	host->max_id = id;
@@ -701,32 +930,36 @@
 {
 	struct buffer_head *bh, *bhp, *first_bh;
 
-	if ((first_bh = bhp = bh = kmalloc (sizeof(struct buffer_head), GFP_ATOMIC)) == NULL)
+	if ((first_bh = bhp = bh = kmalloc(sizeof(struct buffer_head), GFP_ATOMIC)) == NULL)
 		goto abort;
-	memset (bh, 0, sizeof (struct buffer_head));
+	memset(bh, 0, sizeof(struct buffer_head));
 	bh->b_reqnext = NULL;
 	while (--count) {
-		if ((bh = kmalloc (sizeof(struct buffer_head), GFP_ATOMIC)) == NULL)
+		if ((bh = kmalloc(sizeof(struct buffer_head), GFP_ATOMIC)) == NULL)
 			goto abort;
-		memset (bh, 0, sizeof (struct buffer_head));
+		memset(bh, 0, sizeof(struct buffer_head));
 		bhp->b_reqnext = bh;
 		bhp = bh;
 		bh->b_reqnext = NULL;
 	}
 	return first_bh;
 abort:
-	idescsi_free_bh (first_bh);
+	idescsi_free_bh(first_bh);
 	return NULL;
 }
 
 static inline int idescsi_set_direction (idescsi_pc_t *pc)
 {
 	switch (pc->c[0]) {
-		case READ_6: case READ_10: case READ_12:
-			clear_bit (PC_WRITING, &pc->flags);
+		case READ_6:
+		case READ_10:
+		case READ_12:
+			clear_bit(PC_WRITING, &pc->flags);
 			return 0;
-		case WRITE_6: case WRITE_10: case WRITE_12:
-			set_bit (PC_WRITING, &pc->flags);
+		case WRITE_6:
+		case WRITE_10:
+		case WRITE_12:
+			set_bit(PC_WRITING, &pc->flags);
 			return 0;
 		default:
 			return 1;
@@ -744,12 +977,17 @@
 	if (idescsi_set_direction(pc))
 		return NULL;
 	if (segments) {
-		if ((first_bh = bh = idescsi_kmalloc_bh (segments)) == NULL)
+		if ((first_bh = bh = idescsi_kmalloc_bh(segments)) == NULL)
 			return NULL;
 #if IDESCSI_DEBUG_LOG
-		printk ("ide-scsi: %s: building DMA table, %d segments, %dkB total\n", drive->name, segments, pc->request_transfer >> 10);
+		printk("ide-scsi: %s: building DMA table, %d segments, "
+			"%dkB total\n", drive->name, segments,
+			pc->request_transfer >> 10);
 #endif /* IDESCSI_DEBUG_LOG */
 		while (segments--) {
+#if 1
+			bh->b_data = sg->address;
+#else
 			if (sg->address) {
 				bh->b_page = virt_to_page(sg->address);
 				bh->b_data = (char *) ((unsigned long) sg->address & ~PAGE_MASK);
@@ -757,7 +995,7 @@
 				bh->b_page = sg->page;
 				bh->b_data = (char *) sg->offset;
 			}
-
+#endif
 			bh->b_size = sg->length;
 			bh = bh->b_reqnext;
 			sg++;
@@ -766,10 +1004,12 @@
 		/*
 		 * non-sg requests are guarenteed not to reside in highmem /jens
 		 */
-		if ((first_bh = bh = idescsi_kmalloc_bh (1)) == NULL)
+		if ((first_bh = bh = idescsi_kmalloc_bh(1)) == NULL)
 			return NULL;
 #if IDESCSI_DEBUG_LOG
-		printk ("ide-scsi: %s: building DMA table for a single buffer (%dkB)\n", drive->name, pc->request_transfer >> 10);
+		printk("ide-scsi: %s: building DMA table for a single "
+			"buffer (%dkB)\n", drive->name,
+			pc->request_transfer >> 10);
 #endif /* IDESCSI_DEBUG_LOG */
 		bh->b_data = pc->scsi_cmd->request_buffer;
 		bh->b_size = pc->request_transfer;
@@ -794,21 +1034,22 @@
 	idescsi_pc_t *pc = NULL;
 
 	if (!drive) {
-		printk (KERN_ERR "ide-scsi: drive id %d not present\n", cmd->target);
+		printk(KERN_ERR "ide-scsi: drive id %d not present\n",
+			cmd->target);
 		goto abort;
 	}
 	scsi = drive->driver_data;
-	pc = kmalloc (sizeof (idescsi_pc_t), GFP_ATOMIC);
-	rq = kmalloc (sizeof (struct request), GFP_ATOMIC);
+	pc = kmalloc(sizeof(idescsi_pc_t), GFP_ATOMIC);
+	rq = kmalloc(sizeof(struct request), GFP_ATOMIC);
 	if (rq == NULL || pc == NULL) {
-		printk (KERN_ERR "ide-scsi: %s: out of memory\n", drive->name);
+		printk(KERN_ERR "ide-scsi: %s: out of memory\n", drive->name);
 		goto abort;
 	}
 
-	memset (pc->c, 0, 12);
+	memset(pc->c, 0, 12);
 	pc->flags = 0;
 	pc->rq = rq;
-	memcpy (pc->c, cmd->cmnd, cmd->cmd_len);
+	memcpy(pc->c, cmd->cmnd, cmd->cmd_len);
 	if (cmd->use_sg) {
 		pc->buffer = NULL;
 		pc->sg = cmd->request_buffer;
@@ -824,28 +1065,30 @@
 
 	if (should_transform(drive, cmd))
 		set_bit(PC_TRANSFORM, &pc->flags);
-	idescsi_transform_pc1 (drive, pc);
+	idescsi_transform_pc1(drive, pc);
 
 	if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {
-		printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number);
+		printk("ide-scsi: %s: que %lu, cmd = ",
+			drive->name, cmd->serial_number);
 		hexdump(cmd->cmnd, cmd->cmd_len);
 		if (memcmp(pc->c, cmd->cmnd, cmd->cmd_len)) {
-			printk ("ide-scsi: %s: que %lu, tsl = ", drive->name, cmd->serial_number);
+			printk("ide-scsi: %s: que %lu, tsl = ",
+				drive->name, cmd->serial_number);
 			hexdump(pc->c, 12);
 		}
 	}
 
-	ide_init_drive_cmd (rq);
+	ide_init_drive_cmd(rq);
 	rq->buffer = (char *) pc;
-	rq->bh = idescsi_dma_bh (drive, pc);
+	rq->bh = idescsi_dma_bh(drive, pc);
 	rq->cmd = IDESCSI_PC_RQ;
 	spin_unlock_irq(&io_request_lock);
-	(void) ide_do_drive_cmd (drive, rq, ide_end);
+	(void) ide_do_drive_cmd(drive, rq, ide_end);
 	spin_lock_irq(&io_request_lock);
 	return 0;
 abort:
-	if (pc) kfree (pc);
-	if (rq) kfree (rq);
+	if (pc) kfree(pc);
+	if (rq) kfree(rq);
 	cmd->result = DID_ERROR << 16;
 	done(cmd);
 	return 0;
@@ -858,6 +1101,9 @@
 
 int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags)
 {
+	ide_drive_t *drive	= idescsi_drives[cmd->target];
+
+	(void) ide_do_reset(drive);
 	return SCSI_RESET_SUCCESS;
 }
 
@@ -877,24 +1123,25 @@
 
 static int __init init_idescsi_module(void)
 {
+	drive_count = 0;
 	idescsi_init();
 	idescsi_template.module = THIS_MODULE;
-	scsi_register_module (MODULE_SCSI_HA, &idescsi_template);
+	scsi_register_module(MODULE_SCSI_HA, &idescsi_template);
 	return 0;
 }
 
 static void __exit exit_idescsi_module(void)
 {
 	ide_drive_t *drive;
-	byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
+	u8 media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
 	int i, failed;
 
-	scsi_unregister_module (MODULE_SCSI_HA, &idescsi_template);
+	scsi_unregister_module(MODULE_SCSI_HA, &idescsi_template);
 	for (i = 0; media[i] != 255; i++) {
 		failed = 0;
-		while ((drive = ide_scan_devices (media[i], idescsi_driver.name, &idescsi_driver, failed)) != NULL)
-			if (idescsi_cleanup (drive)) {
-				printk ("%s: exit_idescsi_module() called while still busy\n", drive->name);
+		while ((drive = ide_scan_devices(media[i], idescsi_driver.name, &idescsi_driver, failed)) != NULL)
+			if (idescsi_cleanup(drive)) {
+				printk("%s: exit_idescsi_module() called while still busy\n", drive->name);
 				failed++;
 			}
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/ide-scsi.h linux-2.4.21/drivers/scsi/ide-scsi.h
--- linux-2.4.20/drivers/scsi/ide-scsi.h	1998-04-10 22:22:21.000000000 +0000
+++ linux-2.4.21/drivers/scsi/ide-scsi.h	2002-12-18 18:58:12.000000000 +0000
@@ -16,22 +16,22 @@
 extern int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags);
 extern int idescsi_bios (Disk *disk, kdev_t dev, int *parm);
 
-#define IDESCSI  {								\
-	name:            "idescsi",		/* name		*/		\
-	detect:          idescsi_detect,	/* detect	*/		\
-	release:         idescsi_release,	/* release	*/		\
-	info:            idescsi_info,		/* info		*/		\
-	ioctl:           idescsi_ioctl,		/* ioctl        */		\
-	queuecommand:    idescsi_queue,		/* queuecommand */		\
-	abort:           idescsi_abort,		/* abort	*/		\
-	reset:           idescsi_reset,		/* reset	*/		\
-	bios_param:      idescsi_bios,		/* bios_param	*/		\
-	can_queue:       10,			/* can_queue	*/		\
-	this_id:         -1,			/* this_id	*/		\
-	sg_tablesize:    256,			/* sg_tablesize	*/		\
-	cmd_per_lun:     5,			/* cmd_per_lun	*/		\
-	use_clustering:  DISABLE_CLUSTERING,	/* clustering	*/		\
-	emulated:        1			/* emulated     */		\
+#define IDESCSI  {							\
+	name:            "idescsi",		/* name		*/	\
+	detect:          idescsi_detect,	/* detect	*/	\
+	release:         idescsi_release,	/* release	*/	\
+	info:            idescsi_info,		/* info		*/	\
+	ioctl:           idescsi_ioctl,		/* ioctl        */	\
+	queuecommand:    idescsi_queue,		/* queuecommand */	\
+	abort:           idescsi_abort,		/* abort	*/	\
+	reset:           idescsi_reset,		/* reset	*/	\
+	bios_param:      idescsi_bios,		/* bios_param	*/	\
+	can_queue:       10,			/* can_queue	*/	\
+	this_id:         -1,			/* this_id	*/	\
+	sg_tablesize:    256,			/* sg_tablesize	*/	\
+	cmd_per_lun:     5,			/* cmd_per_lun	*/	\
+	use_clustering:  DISABLE_CLUSTERING,	/* clustering	*/	\
+	emulated:        1			/* emulated     */	\
 }
 
 #endif /* IDESCSI_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/in2000.c linux-2.4.21/drivers/scsi/in2000.c
--- linux-2.4.20/drivers/scsi/in2000.c	2001-09-30 19:26:07.000000000 +0000
+++ linux-2.4.21/drivers/scsi/in2000.c	2002-12-18 18:58:04.000000000 +0000
@@ -1916,14 +1916,14 @@
    0
    };
 
-static const unsigned short base_tab[] in2000__INITDATA = {
+static unsigned short base_tab[] in2000__INITDATA = {
    0x220,
    0x200,
    0x110,
    0x100,
    };
 
-static const int int_tab[] in2000__INITDATA = {
+static int int_tab[] in2000__INITDATA = {
    15,
    14,
    11,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/megaraid.c linux-2.4.21/drivers/scsi/megaraid.c
--- linux-2.4.20/drivers/scsi/megaraid.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/scsi/megaraid.c	2002-12-18 18:58:01.000000000 +0000
@@ -2,14 +2,14 @@
  *
  *                    Linux MegaRAID device driver
  *
- * Copyright 2001  American Megatrends Inc.
+ * Copyright 2001  LSI Logic 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.
  *
- * Version : v1.18 (Oct 11, 2001)
+ * Version : v1.18f (Dec 10, 2002)
  *
  * Description: Linux device driver for LSI Logic MegaRAID controller
  *
@@ -459,6 +459,58 @@
  *
  * References to AMI have been changed to LSI Logic.
  *
+ * Version 1.18a
+ * Mon Mar 11 11:38:38 EST 2002 - Atul Mukker <Atul.Mukker@lsil.com>
+ *
+ * RAID On MotherBoard (ROMB) - boot from logical or physical drives
+ *
+ * Support added for discovery(ROMB) vendor and device ids.
+ *
+ * Data transfer length for passthru commands must be valid even if the
+ * command has an associated scatter-gather list.
+ *
+ *
+ * Version 1.18b
+ * Tue Apr 23 11:01:58 EDT 2002 - Atul Mukker <Atul.Mukker@lsil.com>
+ *
+ * typo corrected for scsi condition CHECK_CONDITION in mega_cmd_done()
+ *
+ * Support added for PCI_VENDOR_ID_LSI_LOGIC with device id
+ * PCI_DEVICE_ID_AMI_MEGARAID3.
+ *
+ *
+ * Version 1.18c
+ * Thu May 16 10:27:55 EDT 2002 - Atul Mukker <Atul.Mukker@lsil.com>
+ *
+ * Retrun valid return status for mega passthru commands resulting in
+ * contingent allegiance condition. Check for 64-bit passthru commands also.
+ *
+ * Do not check_region() anymore and check for return value of
+ * request_region()
+ *
+ * Send valid sense data to appliations using the private ioctl interface.
+ *
+ *
+ * Version 1.18d
+ * Wed Aug  7 18:51:51 EDT 2002 - Atul Mukker <atul.mukker@lsil.com>
+ *
+ * Added support for yellowstone and verde controller
+ *
+ * Version 1.18e
+ * Mon Nov 18 12:11:02 EST 2002 - Atul Mukker <atul.mukker@lsil.com>
+ *
+ * Don't use virt_to_bus in mega_register_mailbox when you've got the DMA
+ * address already. Submitted by Jens Axboe and is included in SuSE Linux
+ * Enterprise Server 7.
+ *
+ * s/pcibios_read_config/pci_read_config - Matt Domsch <mdomsch@dell.com>
+ *
+ * remove an unsed variable
+ *
+ * Version 1.18f
+ * Tue Dec 10 09:54:39 EST 2002 - Atul Mukker <atul.mukker@lsil.com>
+ *
+ * remove GFP_DMA flag for ioctl. This was causing overrun of DMA buffers.
  *
  * BUGS:
  *     Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
@@ -772,7 +824,7 @@
 static struct mcontroller mcontroller[MAX_CONTROLLERS];
 
 /* The current driver version */
-static u32 driver_ver = 114;
+static u32 driver_ver = 0x118C;
 
 /* major number used by the device for character interface */
 static int major;
@@ -795,8 +847,7 @@
 extern struct proc_dir_entry proc_root;
 #endif
 
-static char mega_ch_class;	/* channels are raid or scsi */
-#define	IS_RAID_CH(ch)	( (mega_ch_class >> (ch)) & 0x01 )
+#define	IS_RAID_CH(this, ch)	( (this->mega_ch_class >> (ch)) & 0x01 )
 
 #if SERDEBUG
 static char strbuf[MAX_SERBUF + 1];
@@ -1076,11 +1127,14 @@
 		panic(KERN_ERR "megaraid:Problem...!\n");
 	}
 
+#if 0
 	islogical = ( (SCpnt->channel >= megaCfg->productInfo.SCSIChanPresent) &&
 					(SCpnt->channel <= megaCfg->host->max_channel) );
+#endif
 #if 0
 	islogical = (SCpnt->channel == megaCfg->host->max_channel);
 #endif
+	islogical = megaCfg->logdrv_chan[SCpnt->channel];
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	/* Special Case to handle PassThrough->XferAddrress > 4GB */
@@ -1117,7 +1171,7 @@
 			status = 0xF0;
 		}
 #endif
-		if( IS_RAID_CH(SCpnt->channel) && ((c & 0x1F ) == TYPE_DISK) ) {
+		if(IS_RAID_CH(megaCfg, SCpnt->channel) && ((c & 0x1F) == TYPE_DISK)) {
 			status = 0xF0;
 		}
 	}
@@ -1126,7 +1180,7 @@
 	/* clear result; otherwise, success returns corrupt value */
 	SCpnt->result = 0;
 
-	if ((SCpnt->cmnd[0] & M_RD_IOCTL_CMD)) {	/* i.e. ioctl cmd such as M_RD_IOCTL_CMD, M_RD_IOCTL_CMD_NEW of megamgr */
+	if ( 0 && SCpnt->cmnd[0] & M_RD_IOCTL_CMD ) {	/* i.e. ioctl cmd such as M_RD_IOCTL_CMD, M_RD_IOCTL_CMD_NEW of megamgr */
 		switch (status) {
 		case 2:
 		case 0xF0:
@@ -1146,18 +1200,21 @@
 		case 0x02:	/* ERROR_ABORTED, i.e. SCSI_STATUS_CHECK_CONDITION */
 
 			/*set sense_buffer and result fields */
-			if (mbox->cmd == MEGA_MBOXCMD_PASSTHRU) {
+			if (mbox->cmd == MEGA_MBOXCMD_PASSTHRU || mbox->cmd ==
+							MEGA_MBOXCMD_PASSTHRU64 ) {
+
 				memcpy (SCpnt->sense_buffer, pthru->reqsensearea, 14);
+
+				SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) |
+						(CHECK_CONDITION << 1);
+
 			} else if (mbox->cmd == MEGA_MBOXCMD_EXTPASSTHRU) {
-				SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION << 1);
-				memcpy(
-					SCpnt->sense_buffer,
-					epthru->reqsensearea, 14
-				);
-				SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION << 1);
-				/*SCpnt->result =
-					(DRIVER_SENSE << 24) |
-					(DID_ERROR << 16) | status;*/
+
+				memcpy( SCpnt->sense_buffer, epthru->reqsensearea, 14);
+
+				SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) |
+						(CHECK_CONDITION << 1);
+
 			} else {
 				SCpnt->sense_buffer[0] = 0x70;
 				SCpnt->sense_buffer[2] = ABORTED_COMMAND;
@@ -1204,8 +1261,10 @@
 	mega_ext_passthru *epthru;
 	long seg;
 	char islogical;
-	int lun = SCpnt->lun;
-	int		max_lun;
+	int		max_ldrv_num;
+	int		channel = 0;
+	int		target = 0;
+	int		ldrv_num = 0;	/* logical drive number */
 
 	if ((SCpnt->cmnd[0] == MEGADEVIOC))
 		return megadev_doioctl (megaCfg, SCpnt);
@@ -1222,15 +1281,61 @@
 	}
 #endif
 
+#if 0
 	islogical = ( (SCpnt->channel >= megaCfg->productInfo.SCSIChanPresent) &&
 					(SCpnt->channel <= megaCfg->host->max_channel) );
+#endif
 #if 0
 	islogical = (IS_RAID_CH(SCpnt->channel) && /* virtual ch is raid - AM */
 						(SCpnt->channel == megaCfg->host->max_channel));
 #endif
 
+	/*
+	 * We know on what channels are our logical drives - mega_findCard()
+	 */
+	islogical = megaCfg->logdrv_chan[SCpnt->channel];
+
+	/*
+	 * The theory: If physical drive is chosen for boot, all the physical
+	 * devices are exported before the logical drives, otherwise physical
+	 * devices are pushed after logical drives, in which case - Kernel sees
+	 * the physical devices on virtual channel which is obviously converted
+	 * to actual channel on the HBA.
+	 */
+	if( megaCfg->boot_pdrv_enabled ) {
+		if( islogical ) {
+			/* logical channel */
+			channel = SCpnt->channel - megaCfg->productInfo.SCSIChanPresent;
+		}
+		else {
+			channel = SCpnt->channel; /* this is physical channel */
+			target = SCpnt->target;
+
+			/*
+			 * boot from a physical disk, that disk needs to be exposed first
+			 * IF both the channels are SCSI, then booting from the second
+			 * channel is not allowed.
+			 */
+			if( target == 0 ) {
+				target = megaCfg->boot_pdrv_tgt;
+			}
+			else if( target == megaCfg->boot_pdrv_tgt ) {
+				target = 0;
+			}
+		}
+	}
+	else {
+		if( islogical ) {
+			channel = SCpnt->channel; /* this is the logical channel */
+		}
+		else {
+			channel = SCpnt->channel - NVIRT_CHAN;	/* physical channel */
+			target = SCpnt->target;
+		}
+	}
+
 	if ( ! megaCfg->support_ext_cdb ) {
-		if (!islogical && lun != 0) {
+		if (!islogical && SCpnt->lun != 0) {
 			SCpnt->result = (DID_BAD_TARGET << 16);
 			callDone (SCpnt);
 			return NULL;
@@ -1252,39 +1357,26 @@
 			return NULL;
 		}
 
-		lun = mega_get_lun(megaCfg, SCpnt);
+		ldrv_num = mega_get_ldrv_num(megaCfg, SCpnt, channel);
 
-	    max_lun = (megaCfg->flag & BOARD_40LD) ?
+	    max_ldrv_num = (megaCfg->flag & BOARD_40LD) ?
 						FC_MAX_LOGICAL_DRIVES : MAX_LOGICAL_DRIVES;
 
 		 /*
-		  * max_lun increases by 0x80 if some logical drive was deleted.
+		  * max_ldrv_num increases by 0x80 if some logical drive was deleted.
 		  */
 		if(megaCfg->read_ldidmap) {
-			max_lun += 0x80;
+			max_ldrv_num += 0x80;
 		}
 
-		if( lun > max_lun ) {
+		if( ldrv_num > max_ldrv_num ) {
 			SCpnt->result = (DID_BAD_TARGET << 16);
 			callDone (SCpnt);
 			return NULL;
 		}
 
-		/*
-		 * If we have a logical drive with boot enabled, project it first
-		 */
-		if( megaCfg->boot_ldrv_enabled ) {
-			if( lun == 0 ) {
-				lun = megaCfg->boot_ldrv;
-			}
-			else {
-				if( lun <= megaCfg->boot_ldrv ) {
-					lun--;
-				}
-			}
-		}
 	} else {
-		if ( lun > 7) {
+		if ( SCpnt->lun > 7) {
 				/* Do not support lun >7 for physically accessed devices */
 			SCpnt->result = (DID_BAD_TARGET << 16);
 			callDone (SCpnt);
@@ -1312,6 +1404,14 @@
 
 		case READ_CAPACITY:
 		case INQUIRY:
+			if(!(megaCfg->flag & (1L << SCpnt->channel))) {
+				printk(KERN_NOTICE
+					"scsi%d: scanning virtual channel %d for logical drives.\n",
+					megaCfg->host->host_no, channel);
+
+				megaCfg->flag |= (1L << SCpnt->channel);
+			}
+
 			/* Allocate a SCB and initialize passthru */
 			if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
 				SCpnt->result = (DID_ERROR << 16);
@@ -1331,7 +1431,7 @@
 			pthru->ars = 1;
 			pthru->reqsenselen = 14;
 			pthru->islogical = 1;
-			pthru->logdrv = lun;
+			pthru->logdrv = ldrv_num;
 			pthru->cdblen = SCpnt->cmd_len;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
@@ -1386,7 +1486,7 @@
 			mbox = (mega_mailbox *) & pScb->mboxData;
 
 			memset (mbox, 0, sizeof (pScb->mboxData));
-			mbox->logdrv = lun;
+			mbox->logdrv = ldrv_num;
 
 			if (megaCfg->flag & BOARD_64BIT) {
 				mbox->cmd = (*SCpnt->cmnd == READ_6
@@ -1410,12 +1510,12 @@
 				mbox->lba &= 0x1FFFFF;
 
 				if (*SCpnt->cmnd == READ_6) {
-					megaCfg->nReads[(int) lun]++;
-					megaCfg->nReadBlocks[(int) lun] +=
+					megaCfg->nReads[(int)ldrv_num]++;
+					megaCfg->nReadBlocks[(int)ldrv_num] +=
 					    mbox->numsectors;
 				} else {
-					megaCfg->nWrites[(int) lun]++;
-					megaCfg->nWriteBlocks[(int) lun] +=
+					megaCfg->nWrites[(int)ldrv_num]++;
+					megaCfg->nWriteBlocks[(int)ldrv_num] +=
 					    mbox->numsectors;
 				}
 			}
@@ -1432,12 +1532,12 @@
 				    (u32) SCpnt->cmnd[5];
 
 				if (*SCpnt->cmnd == READ_10) {
-					megaCfg->nReads[(int) lun]++;
-					megaCfg->nReadBlocks[(int) lun] +=
+					megaCfg->nReads[(int)ldrv_num]++;
+					megaCfg->nReadBlocks[(int)ldrv_num] +=
 					    mbox->numsectors;
 				} else {
-					megaCfg->nWrites[(int) lun]++;
-					megaCfg->nWriteBlocks[(int) lun] +=
+					megaCfg->nWrites[(int)ldrv_num]++;
+					megaCfg->nWriteBlocks[(int)ldrv_num] +=
 					    mbox->numsectors;
 				}
 			}
@@ -1457,12 +1557,12 @@
 				    (u32) SCpnt->cmnd[9];
 
 				if (*SCpnt->cmnd == READ_12) {
-					megaCfg->nReads[(int) lun]++;
-					megaCfg->nReadBlocks[(int) lun] +=
+					megaCfg->nReads[(int)ldrv_num]++;
+					megaCfg->nReadBlocks[(int)ldrv_num] +=
 					    mbox->numsectors;
 				} else {
-					megaCfg->nWrites[(int) lun]++;
-					megaCfg->nWriteBlocks[(int) lun] +=
+					megaCfg->nWrites[(int)ldrv_num]++;
+					megaCfg->nWriteBlocks[(int)ldrv_num] +=
 					    mbox->numsectors;
 				}
 			}
@@ -1516,7 +1616,8 @@
 		memset (mbox, 0, sizeof (pScb->mboxData));
 
 		if ( megaCfg->support_ext_cdb && SCpnt->cmd_len > 10 ) {
-			epthru = mega_prepare_extpassthru(megaCfg, pScb, SCpnt);
+			epthru = mega_prepare_extpassthru(megaCfg, pScb, SCpnt, channel,
+					target);
 			mbox->cmd = MEGA_MBOXCMD_EXTPASSTHRU;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 			mbox->xferaddr = pScb->dma_ext_passthruhandle64;
@@ -1531,7 +1632,8 @@
 #endif
 		}
 		else {
-			pthru = mega_prepare_passthru(megaCfg, pScb, SCpnt);
+			pthru = mega_prepare_passthru(megaCfg, pScb, SCpnt, channel,
+					target);
 
 			/* Initialize mailbox */
 			mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
@@ -1553,18 +1655,30 @@
 }
 
 static int
-mega_get_lun(mega_host_config *this_hba, Scsi_Cmnd *sc)
+mega_get_ldrv_num(mega_host_config *this_hba, Scsi_Cmnd *sc, int channel)
 {
 	int		tgt;
-	int		lun;
-	int		virt_chan;
+	int		ldrv_num;
 
 	tgt = sc->target;
 	
 	if ( tgt > 7 ) tgt--;	/* we do not get inquires for tgt 7 */
 
-	virt_chan = sc->channel - this_hba->productInfo.SCSIChanPresent;
-	lun = (virt_chan * 15) + tgt;
+	ldrv_num = (channel * 15) + tgt; /* 14 targets per channel */
+
+	/*
+	 * If we have a logical drive with boot enabled, project it first
+	 */
+	if( this_hba->boot_ldrv_enabled ) {
+		if( ldrv_num == 0 ) {
+			ldrv_num = this_hba->boot_ldrv;
+		}
+		else {
+			if( ldrv_num <= this_hba->boot_ldrv ) {
+				ldrv_num--;
+			}
+		}
+	}
 
 	/*
 	 * If "delete logical drive" feature is enabled on this controller.
@@ -1582,16 +1696,17 @@
 		case WRITE_6:	/* fall through */
 		case READ_10:	/* fall through */
 		case WRITE_10:
-			lun += 0x80;
+			ldrv_num += 0x80;
 		}
 	 }
 
-	 return lun;
+	 return ldrv_num;
 }
 
 
 static mega_passthru *
-mega_prepare_passthru(mega_host_config *megacfg, mega_scb *scb, Scsi_Cmnd *sc)
+mega_prepare_passthru(mega_host_config *megacfg, mega_scb *scb, Scsi_Cmnd *sc,
+		int channel, int target)
 {
 	mega_passthru *pthru;
 
@@ -1608,9 +1723,9 @@
 	pthru->ars = 1;
 	pthru->reqsenselen = 14;
 	pthru->islogical = 0;
-	pthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : sc->channel;
+	pthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : channel;
 	pthru->target = (megacfg->flag & BOARD_40LD) ?
-	    (sc->channel << 4) | sc->target : sc->target;
+	    (channel << 4) | target : target;
 	pthru->cdblen = sc->cmd_len;
 	pthru->logdrv = sc->lun;
 
@@ -1624,6 +1739,15 @@
 	switch (sc->cmnd[0]) {
 	case INQUIRY:
 	case READ_CAPACITY:
+
+		if(!(megacfg->flag & (1L << sc->channel))) {
+			printk(KERN_NOTICE
+				"scsi%d: scanning physical channel %d for devices.\n",
+				megacfg->host->host_no, channel);
+
+			megacfg->flag |= (1L << sc->channel);
+		}
+
 		pthru->numsgelements = 0;
 		pthru->dataxferaddr = scb->dma_bounce_buffer;
 		pthru->dataxferlen = sc->request_bufflen;
@@ -1647,7 +1771,8 @@
 }
 
 static mega_ext_passthru *
-mega_prepare_extpassthru(mega_host_config *megacfg, mega_scb *scb, Scsi_Cmnd *sc)
+mega_prepare_extpassthru(mega_host_config *megacfg, mega_scb *scb,
+		Scsi_Cmnd *sc, int channel, int target)
 {
 	mega_ext_passthru *epthru;
 
@@ -1664,9 +1789,9 @@
 	epthru->ars = 1;
 	epthru->reqsenselen = 14;
 	epthru->islogical = 0;
-	epthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : sc->channel;
+	epthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : channel;
 	epthru->target = (megacfg->flag & BOARD_40LD) ?
-	    (sc->channel << 4) | sc->target : sc->target;
+	    (channel << 4) | target : target;
 	epthru->cdblen = sc->cmd_len;
 	epthru->logdrv = sc->lun;
 
@@ -1680,6 +1805,14 @@
 	switch (sc->cmnd[0]) {
 	case INQUIRY:
 	case READ_CAPACITY:
+		if(!(megacfg->flag & (1L << sc->channel))) {
+			printk(KERN_NOTICE
+				"scsi%d: scanning physical channel %d for devices.\n",
+				megacfg->host->host_no, channel);
+
+			megacfg->flag |= (1L << sc->channel);
+		}
+
 		epthru->numsgelements = 0;
 		epthru->dataxferaddr = scb->dma_bounce_buffer;
 		epthru->dataxferlen = sc->request_bufflen;
@@ -2240,7 +2373,6 @@
 			return 0;
 		}
 		udelay (100);
-		barrier ();
 	}
 	return -1;		/* give up after 1 second */
 }
@@ -2439,7 +2571,7 @@
 			scb->sg64List[0].address = scb->dma_h_bulkdata;
 			scb->sg64List[0].length = scb->SCpnt->request_bufflen;
 			*buffer = scb->dma_sghandle64;
-			*length = 0;
+			*length = (u32)scb->SCpnt->request_bufflen;
 			scb->sglist_count = 1;
 			return 1;
 		} else {
@@ -2520,7 +2652,15 @@
 #else
 	*buffer = virt_to_bus (scb->sgList);
 #endif
+
+#if 0
 	*length = 0;
+#endif
+	/*
+	 * For passthru command, dataxferlen must be set, even for commands with a
+	 * sg list
+	 */
+	*length = (u32)scb->SCpnt->request_bufflen;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	/* Return count of SG requests */
@@ -2743,12 +2883,7 @@
 		megaCfg->productInfo.SCSIChanPresent + NVIRT_CHAN -1;
 
 	megaCfg->host->max_id = 16;	/* max targets per channel */
-	/*(megaCfg->flag & BOARD_40LD)?FC_MAX_TARGETS_PER_CHANNEL:MAX_TARGET+1; */
-#if 0
-	megaCfg->host->max_lun =	/* max lun */
-	    (megaCfg->flag & BOARD_40LD) ?
-			FC_MAX_LOGICAL_DRIVES : MAX_LOGICAL_DRIVES;
-#endif
+
 	megaCfg->host->max_lun = 7;	/* Upto 7 luns for non disk devices */
 
 	megaCfg->host->cmd_per_lun = MAX_CMD_PER_LUN;
@@ -2760,12 +2895,6 @@
 
 	megaCfg->host->can_queue = megaCfg->max_cmds - 1;
 
-#if 0
-	if (megaCfg->host->can_queue >= MAX_COMMANDS) {
-		megaCfg->host->can_queue = MAX_COMMANDS - 16;
-	}
-#endif
-
 	/* use HP firmware and bios version encoding */
 	if (megaCfg->productInfo.subSystemVendorID == HP_SUBSYS_ID) {
 		sprintf (megaCfg->fwVer, "%c%d%d.%d%d",
@@ -2833,7 +2962,7 @@
 	u32 magic64;
 #endif
 
-	int		i;
+	int		i, j;
 
 #if BITS_PER_LONG==64
 	u64 megaBase;
@@ -2863,20 +2992,27 @@
 		pciDevFun = pdev->devfn;
 #endif
 		if ((flag & BOARD_QUARTZ) && (skip_id == -1)) {
-			pcibios_read_config_word (pciBus, pciDevFun,
-						  PCI_CONF_AMISIG, &magic);
-			if ((magic != AMI_SIGNATURE)
-			    && (magic != AMI_SIGNATURE_471)) {
-				pciIdx++;
-				continue;	/* not an AMI board */
-			}
+				if( (pciVendor == PCI_VENDOR_ID_PERC4_DI_YSTONE &&
+					pciDev == PCI_DEVICE_ID_PERC4_DI_YSTONE) ||
+					(pciVendor == PCI_VENDOR_ID_PERC4_QC_VERDE &&
+					pciDev == PCI_DEVICE_ID_PERC4_QC_VERDE) ) {
+
+					flag |= BOARD_64BIT;
+				}
+				else {
+					pci_read_config_word (pdev, PCI_CONF_AMISIG, &magic);
+					if ((magic != AMI_SIGNATURE)
+						&& (magic != AMI_SIGNATURE_471)) {
+						pciIdx++;
+						continue;	/* not an AMI board */
+					}
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-			pcibios_read_config_dword (pciBus, pciDevFun,
-						   PCI_CONF_AMISIG64, &magic64);
+					pci_read_config_dword (pdev, PCI_CONF_AMISIG64, &magic64);
 
-			if (magic64 == AMI_64BIT_SIGNATURE)
-				flag |= BOARD_64BIT;
+					if (magic64 == AMI_64BIT_SIGNATURE)
+						flag |= BOARD_64BIT;
 #endif
+				}
 		}
 
 		/* Hmmm...Should we not make this more modularized so that in future we dont add
@@ -2898,24 +3034,15 @@
 					      PCI_SUBSYSTEM_ID, &subsysid);
 #endif
 
-#if 0
 			/*
-			 * This routine is called with well know values and we
-			 * should not be getting what we have not asked.
-			 * Also, the check is not right. It should have been for
-			 * pci_vendor_id not subsysvid - AM
-			 */
-
-			/* If we dont detect this valid subsystem vendor id's 
-			   we refuse to load the driver 
-			   PART of PC200X compliance
+			 * If we do not find the valid subsys vendor id, refuse to load
+			 * the driver. This is part of PCI200X compliance
 			 */
+			if( (subsysvid != AMI_SUBSYS_ID) &&
+					(subsysvid != DELL_SUBSYS_ID) &&
+					(subsysvid != LSI_SUBSYS_ID) &&
+					(subsysvid != HP_SUBSYS_ID) ) continue;
 
-			if ((subsysvid != AMI_SUBSYS_ID)
-			    && (subsysvid != DELL_SUBSYS_ID)
-			    && (subsysvid != HP_SUBSYS_ID))
-				continue;
-#endif
 		}
 
 		printk (KERN_NOTICE
@@ -3004,11 +3131,10 @@
 		megaCtlrs[numCtlrs] = megaCfg;
 
 		if (!(flag & BOARD_QUARTZ)) {
+
 			/* Request our IO Range */
-			if (!request_region(megaBase, 16, "megaraid")) {
-				printk(KERN_WARNING "megaraid: Couldn't register I/O range!\n");
+			if( !request_region(megaBase, 16, "megaraid") )
 				goto err_unregister;
-			}
 		}
 
 		/* Request our IRQ */
@@ -3031,9 +3157,7 @@
 					    sizeof (mega_mailbox64),
 					    &(megaCfg->dma_handle64));
 
-		mega_register_mailbox (megaCfg,
-				       virt_to_bus ((void *) megaCfg->
-						    mailbox64ptr));
+		mega_register_mailbox (megaCfg,megaCfg->dma_handle64);
 #else
 		mega_register_mailbox (megaCfg,
 				       virt_to_bus ((void *) &megaCfg->
@@ -3097,18 +3221,35 @@
 		 * Find out which channel is raid and which is scsi
 		 */
 		mega_enum_raid_scsi(megaCfg);
-		for( i = 0; i < megaCfg->productInfo.SCSIChanPresent; i++ ) {
-			if(IS_RAID_CH(i))
-				printk(KERN_NOTICE"megaraid: channel[%d] is raid.\n", i+1);
-			else
-				printk(KERN_NOTICE"megaraid: channel[%d] is scsi.\n", i+1);
-		}
 
 		/*
 		 * Find out if a logical drive is set as the boot drive. If there is
 		 * one, will make that as the first logical drive.
+		 * ROMB: Do we have to boot from a physical drive. Then all the
+		 * physical drives would appear before the logical disks. Else, all
+		 * the physical drives would be exported to the mid layer after
+		 * logical disks.
 		 */
-		mega_get_boot_ldrv(megaCfg);
+		mega_get_boot_drv(megaCfg);
+
+		if( ! megaCfg->boot_pdrv_enabled ) {
+			for( i = 0; i < NVIRT_CHAN; i++ )
+				megaCfg->logdrv_chan[i] = 1;
+
+			for( i = NVIRT_CHAN; i < MAX_CHANNEL + NVIRT_CHAN; i++ )
+				megaCfg->logdrv_chan[i] = 0;
+
+			megaCfg->mega_ch_class <<= NVIRT_CHAN;
+		}
+		else {
+			j = megaCfg->productInfo.SCSIChanPresent;
+			for( i = 0; i < j; i++ )
+				megaCfg->logdrv_chan[i] = 0;
+
+			for( i = j; i < NVIRT_CHAN + j; i++ )
+				megaCfg->logdrv_chan[i] = 1;
+		}
+
 
 		mega_hbas[numCtlrs].hostdata_addr = megaCfg;
 
@@ -3208,6 +3349,12 @@
 
 	memset (mega_hbas, 0, sizeof (mega_hbas));
 
+	/* Detect ROMBs first */
+	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_DISCOVERY,
+				PCI_DEVICE_ID_DISCOVERY, BOARD_QUARTZ);
+	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_PERC4_DI_YSTONE,
+				PCI_DEVICE_ID_PERC4_DI_YSTONE, BOARD_QUARTZ);
+	/* Then detect cards based on date they were produced, oldest first */
 	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
 				PCI_DEVICE_ID_AMI_MEGARAID, 0);
 	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
@@ -3216,6 +3363,10 @@
 				PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
 	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
 				PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
+	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_LSI_LOGIC,
+				PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
+	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_PERC4_QC_VERDE,
+				PCI_DEVICE_ID_PERC4_QC_VERDE, BOARD_QUARTZ);
 
 	mega_reorder_hosts ();
 
@@ -3366,7 +3517,7 @@
 /*
  * Find out what channels are RAID/SCSI
  */
-void
+static void
 mega_enum_raid_scsi(mega_host_config *megacfg)
 {
 	mega_mailbox *mboxp;
@@ -3401,16 +3552,16 @@
 	 * Non-ROMB firware fail this command, so all channels
 	 * must be shown RAID
 	 */
+	megacfg->mega_ch_class = 0xFF;
 	if( megaIssueCmd(megacfg, mbox, NULL, 0) == 0 ) {
-		mega_ch_class = *((char *)megacfg->mega_buffer);
-
-		for( i = 0; i < NVIRT_CHAN; i++ ) {
-			/* logical drives channel is RAID */
-			mega_ch_class |= (0x01 << (megacfg->productInfo.SCSIChanPresent+i));
-		}
+		megacfg->mega_ch_class = *((char *)megacfg->mega_buffer);
 	}
-	else {
-		mega_ch_class = 0xFF;
+
+	for( i = 0; i < megacfg->productInfo.SCSIChanPresent; i++ ) {
+		if( (megacfg->mega_ch_class >> i) & 0x01 )
+			printk(KERN_NOTICE"megaraid: channel[%d] is raid.\n", i+1);
+		else
+			printk(KERN_NOTICE"megaraid: channel[%d] is scsi.\n", i+1);
 	}
 
 
@@ -3426,13 +3577,14 @@
  * get the boot logical drive number if enabled
  */
 void
-mega_get_boot_ldrv(mega_host_config *megacfg)
+mega_get_boot_drv(mega_host_config *megacfg)
 {
 	mega_mailbox *mboxp;
 	unsigned char mbox[16];
 	struct private_bios_data *prv_bios_data;
 	u16		cksum = 0;
-	char	*cksum_p;
+	u8		*cksum_p;
+	u8		boot_pdrv;
 	int		i;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
@@ -3459,19 +3611,35 @@
 
 	megacfg->boot_ldrv_enabled = 0;
 	megacfg->boot_ldrv = 0;
-	if( megaIssueCmd(megacfg, mbox, NULL, 0) == 0 ) {
 
+	megacfg->boot_pdrv_enabled = 0;
+	megacfg->boot_pdrv_ch = 0;
+	megacfg->boot_pdrv_tgt = 0;
+
+	if( megaIssueCmd(megacfg, mbox, NULL, 0) == 0 ) {
 		prv_bios_data = (struct private_bios_data *)megacfg->mega_buffer;
 
 		cksum = 0;
-		cksum_p = (char *)prv_bios_data;
+		cksum_p = (u8 *)prv_bios_data;
 		for( i = 0; i < 14; i++ ) {
-			cksum += (u16)(*cksum_p++);
+			cksum += *cksum_p++;
 		}
 
 		if( prv_bios_data->cksum == (u16)(0-cksum) ) {
-			megacfg->boot_ldrv_enabled = 1;
-			megacfg->boot_ldrv = prv_bios_data->boot_ldrv;
+
+			/*
+			 * If MSB is set, a physical drive is set as boot device
+			 */
+			if( prv_bios_data->boot_drv & 0x80 ) {
+				megacfg->boot_pdrv_enabled = 1;
+				boot_pdrv = prv_bios_data->boot_drv & 0x7F;
+				megacfg->boot_pdrv_ch = boot_pdrv / 16;
+				megacfg->boot_pdrv_tgt = boot_pdrv % 16;
+			}
+			else {
+				megacfg->boot_ldrv_enabled = 1;
+				megacfg->boot_ldrv = prv_bios_data->boot_drv;
+			}
 		}
 	}
 
@@ -3681,7 +3849,7 @@
 	sprintf (buffer,
 		 "LSI Logic MegaRAID %s %d commands %d targs %d chans %d luns",
 		 megaCfg->fwVer, megaCfg->productInfo.MaxConcCmds,
-		 megaCfg->host->max_id, megaCfg->host->max_channel,
+		 megaCfg->host->max_id-1, megaCfg->host->max_channel,
 		 megaCfg->host->max_lun);
 	return buffer;
 }
@@ -3710,6 +3878,7 @@
 	megaCfg = (mega_host_config *) SCpnt->host->hostdata;
 	DRIVER_LOCK (megaCfg);
 
+#if 0
 	if (!(megaCfg->flag & (1L << SCpnt->channel))) {
 		if (SCpnt->channel < megaCfg->productInfo.SCSIChanPresent)
 			printk ( KERN_NOTICE
@@ -3723,6 +3892,7 @@
 
 		megaCfg->flag |= (1L << SCpnt->channel);
 	}
+#endif
 
 	SCpnt->scsi_done = pktComp;
 
@@ -4232,7 +4402,7 @@
 	/* Get pointer to host config structure */
 	megaCfg = (mega_host_config *) disk->device->host->hostdata;
 
-	if( IS_RAID_CH(disk->device->channel)) {
+	if( IS_RAID_CH(megaCfg, disk->device->channel)) {
 			/* Default heads (64) & sectors (32) */
 			heads = 64;
 			sectors = 32;
@@ -4297,7 +4467,15 @@
 	int heads, cyls, sectors;
 	int capacity = disk->capacity;
 
-	if(!(bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, block_size(dev))))
+	int ma = MAJOR(dev);
+	int mi = (MINOR(dev) & ~0xf);
+
+	int block = 1024; 
+
+	if(blksize_size[ma])
+		block = blksize_size[ma][mi];
+		
+	if(!(bh = bread(MKDEV(ma,mi), 0, block)))
 		return -1;
 
 	if( *(unsigned short *)(bh->b_data + 510) == 0xAA55 ) {
@@ -4626,9 +4804,10 @@
 			/*
 			 * Copy struct mcontroller to user area
 			 */
-			copy_to_user (ioc.data,
+			if (copy_to_user (ioc.data,
 				      mcontroller + adapno,
-				      sizeof (struct mcontroller));
+				      sizeof (struct mcontroller)))
+				      return -EFAULT;
 			return 0;
 
 		default:
@@ -4694,7 +4873,7 @@
 		if(shpnt == NULL)  return -ENODEV;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-		scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL|GFP_DMA);
+		scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL);
 #else
 		scsicmd = (Scsi_Cmnd *)scsi_init_malloc(sizeof(Scsi_Cmnd),
 							  GFP_ATOMIC | GFP_DMA);
@@ -4745,7 +4924,8 @@
 		down(&mimd_ioctl_sem);
 
 		if( !scsicmd->result && outlen ) {
-			copy_to_user(uaddr, kvaddr, length);
+			if (copy_to_user(uaddr, kvaddr, length))
+				return -EFAULT;
 		}
 
 		/*
@@ -4755,6 +4935,9 @@
 
 		if( ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU ) {
 			put_user( scsicmd->result, &uioc->pthru.scsistatus );
+			if (copy_to_user( uioc->pthru.reqsensearea, scsicmd->sense_buffer,
+							  MAX_REQ_SENSE_LEN ));
+				ret= -EFAULT;
 		} else {
 			put_user(1, &uioc->mbox[16]);	/* numstatus */
 			/* status */
@@ -4836,7 +5019,7 @@
 		}
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-		scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL|GFP_DMA);
+		scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL);
 #else
 		scsicmd = (Scsi_Cmnd *)scsi_init_malloc(sizeof(Scsi_Cmnd),
 							  GFP_ATOMIC | GFP_DMA);
@@ -4894,9 +5077,11 @@
 
 		if (!scsicmd->result && outlen) {
 			if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
-				copy_to_user (uaddr, kvaddr, ioc.pthru.dataxferlen);
+				if (copy_to_user (uaddr, kvaddr, ioc.pthru.dataxferlen))	
+					ret = -EFAULT;
 			} else {
-				copy_to_user (uaddr, kvaddr, outlen);
+				if (copy_to_user (uaddr, kvaddr, outlen)) 
+					ret = -EFAULT;
 			}
 		}
 
@@ -4907,6 +5092,15 @@
 
 		if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
 			put_user (scsicmd->result, &uioc->pthru.scsistatus);
+
+			/*
+			 * If scsicmd->result is 0x02 (CHECK CONDITION) then copy the
+			 * SCSI sense data into user area
+			 */
+			if (copy_to_user( uioc->pthru.reqsensearea, scsicmd->sense_buffer,
+							  MAX_REQ_SENSE_LEN ))
+				ret = -EFAULT;
+							
 		} else {
 			put_user (1, &uioc->mbox[16]);	/* numstatus */
 			put_user (scsicmd->result, &uioc->mbox[17]); /* status */
@@ -4995,7 +5189,7 @@
 			scb->sg64List[0].length = 4096;	// TODO: Check this
 			pthru->dataxferaddr = scb->dma_sghandle64;
 			pthru->numsgelements = 1;
-			mboxpthru->cmd = 0xC3;
+			mboxpthru->cmd = MEGA_MBOXCMD_PASSTHRU64;
 		} else {
 			mboxpthru->dataxferaddr = scb->dma_passthruhandle64;
 			pthru->dataxferaddr =
@@ -5189,8 +5383,6 @@
 		return rval;
 	}
 
-	printk("megaraid: logical drive %d deleted.\n", logdrv);
-
 	/*
 	 * After deleting first logical drive, the logical drives must be
 	 * addressed by adding 0x80 to the logical drive id.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/megaraid.h linux-2.4.21/drivers/scsi/megaraid.h
--- linux-2.4.20/drivers/scsi/megaraid.h	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/scsi/megaraid.h	2002-12-18 18:58:09.000000000 +0000
@@ -30,7 +30,7 @@
 #define M_RD_IOCTL_CMD_NEW		0x81
 #define M_RD_DRIVER_IOCTL_INTERFACE	0x82
 
-#define MEGARAID_VERSION "v1.18 (Release Date: Thu Oct 11 15:02:53 EDT 2001)\n"
+#define MEGARAID_VERSION "v1.18f (Release Date: Tue Dec 10 09:54:39 EST 2002)\n"
 
 #define MEGARAID_IOCTL_VERSION 	114
 
@@ -73,6 +73,7 @@
 #define MEGA_MBOXCMD_LWRITE64		0xA8
 #define MEGA_MBOXCMD_PASSTHRU		0x03
 #define MEGA_MBOXCMD_EXTPASSTHRU	0xE3
+#define MEGA_MBOXCMD_PASSTHRU64		0xC3
 #define MEGA_MBOXCMD_ADAPTERINQ		0x05
 
 
@@ -121,6 +122,10 @@
 #define ENABLE_INTR(base)	WRITE_PORT(base,I_TOGGLE_PORT,ENABLE_INTR_BYTE)
 #define DISABLE_INTR(base)	WRITE_PORT(base,I_TOGGLE_PORT,DISABLE_INTR_BYTE)
 
+#ifndef PCI_VENDOR_ID_LSI_LOGIC
+#define PCI_VENDOR_ID_LSI_LOGIC		0x1000
+#endif
+
 /* Define AMI's PCI codes */
 #ifndef PCI_VENDOR_ID_AMI
 #define PCI_VENDOR_ID_AMI		0x101E
@@ -138,6 +143,15 @@
 #define PCI_DEVICE_ID_AMI_MEGARAID3	0x1960
 #endif
 
+#define PCI_VENDOR_ID_DISCOVERY		0x1028
+#define PCI_DEVICE_ID_DISCOVERY		0x000E
+
+#define PCI_VENDOR_ID_PERC4_DI_YSTONE	0x1028
+#define PCI_DEVICE_ID_PERC4_DI_YSTONE	0x000F
+
+#define PCI_VENDOR_ID_PERC4_QC_VERDE	0x1000
+#define PCI_DEVICE_ID_PERC4_QC_VERDE	0x0407
+
 /* Special Adapter Commands */
 #define FW_FIRE_WRITE   	0x2C
 #define FW_FIRE_FLASH   	0x2D
@@ -172,6 +186,7 @@
 #define PCI_CONF_AMISIG64		0xa4
 
 /* Sub-System Vendor ID sorted on alphabetical order*/
+#define LSI_SUBSYS_ID                  0x1000
 #define	AMI_SUBSYS_ID			0x101E
 #define DELL_SUBSYS_ID			0x1028
 #define	HP_SUBSYS_ID			0x103C
@@ -704,12 +719,15 @@
 #define INTR_ENB	0	/* do not disable interrupt while manipulating */
 #define INTR_DIS	1	/* disable interrupt while manipulating */
 
+#define NVIRT_CHAN		4	/* # of virtual channels to represent 60 logical
+							drives */
+
 /* Per-controller data */
 typedef struct _mega_host_config {
 	u8 numldrv;
 	u32 flag;
 
-#if BITS_PER_LONG==64
+#ifdef __LP64__
 	u64 base;
 #else
 	u32 base;
@@ -769,8 +787,12 @@
 	struct proc_dir_entry *controller_proc_dir_entry;
 	struct proc_dir_entry *proc_read, *proc_stat, *proc_status, *proc_mbox;
 	int		support_ext_cdb;
-	int		boot_ldrv_enabled;
-	int		boot_ldrv;
+
+	u8		boot_ldrv_enabled;	/* boot from logical drive */
+	u8		boot_ldrv;			/* boot logical drive */
+	u8		boot_pdrv_enabled;	/* boot from physical drive */
+	u8		boot_pdrv_ch;		/* boot physical drive channel */
+	u8		boot_pdrv_tgt;		/* boot physical drive target */
 
 	int		support_random_del;	/* Do we support random deletion of logdrvs */
 	int		read_ldidmap;	/* set after logical drive deltion. The logical
@@ -782,6 +804,9 @@
 	mega_scb	*int_qh;	/* commands are queued in the internal queue */
 	mega_scb	*int_qt;	/* while the hba is quiescent */
 	int			int_qlen;
+	char		logdrv_chan[MAX_CHANNEL+NVIRT_CHAN]; /* logical drive are on
+														 what channels. */
+	int			mega_ch_class;
 } mega_host_config;
 
 typedef struct _driver_info {
@@ -916,8 +941,8 @@
 							 * Others values are invalid
 							 */
 	u8		unused:4;		/* bits 4-7 are unused */
-	u8		boot_ldrv;		/*
-							 * logical drive set as boot drive
+	u8		boot_drv;		/*
+							 * logical/physical drive set as boot drive
 							 * 0..7 - for 8LD cards
 							 * 0..39 - for 40LD cards
 							 */
@@ -926,9 +951,6 @@
 };
 #pragma pack()
 
-#define NVIRT_CHAN		4	/* # of virtual channels to represent 60 logical
-							drives */
-
 /*
  * Command for random deletion of logical drives
  */
@@ -994,13 +1016,13 @@
 static void mega_create_proc_entry (int index, struct proc_dir_entry *);
 static int mega_support_ext_cdb(mega_host_config *);
 static mega_passthru* mega_prepare_passthru(mega_host_config *, mega_scb *,
-		Scsi_Cmnd *);
+		Scsi_Cmnd *, int, int);
 static mega_ext_passthru* mega_prepare_extpassthru(mega_host_config *,
-		mega_scb *, Scsi_Cmnd *);
+		mega_scb *, Scsi_Cmnd *, int, int);
 static void mega_enum_raid_scsi(mega_host_config *);
 static int mega_partsize(Disk *, kdev_t, int *);
-static void mega_get_boot_ldrv(mega_host_config *);
-static int mega_get_lun(mega_host_config *, Scsi_Cmnd *);
+static void mega_get_boot_drv(mega_host_config *);
+static int mega_get_ldrv_num(mega_host_config *, Scsi_Cmnd *, int);
 static int mega_support_random_del(mega_host_config *);
 static int mega_del_logdrv(mega_host_config *, int);
 static int mega_do_del_logdrv(mega_host_config *, int);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/nsp32.c linux-2.4.21/drivers/scsi/nsp32.c
--- linux-2.4.20/drivers/scsi/nsp32.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/scsi/nsp32.c	2002-12-18 18:58:09.000000000 +0000
@@ -0,0 +1,3526 @@
+/*
+ * NinjaSCSI-32Bi Cardbus, NinjaSCSI-32UDE PCI/CardBus SCSI driver
+ * Copyright (C) 2001, 2002
+ *      YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
+ *      GOTO Masanori <gotom@debian.or.jp>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include <scsi/scsi_ioctl.h>
+#include <scsi/scsi.h>
+
+#include "nsp32.h"
+
+
+static int trans_mode = 0;	/* default: BIOS */
+static int auto_param = 0;	/* default: ON */
+MODULE_PARM(trans_mode, "i");
+MODULE_PARM(auto_param, "i");
+MODULE_PARM_DESC(trans_mode, "transfer mode (0: BIOS 1: Async 2: Ultra20M");
+MODULE_PARM_DESC(auto_param, "AutoParameter mode (0: ON 1: OFF)");
+#define ASYNC_MODE    1
+#define ULTRA20M_MODE 2
+
+MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>, GOTO Masanori <gotom@debian.or.jp>");
+MODULE_DESCRIPTION("Workbit NinjaSCSI-32Bi/UDE PCI/CardBus SCSI host bus adapter module");
+MODULE_LICENSE("GPL");
+
+static const char *nsp32_release_version = "1.0";
+
+
+/*
+ * structure for DMA/Scatter Gather list
+ */
+#define AUTOPARAM_SIZE		(sizeof(int)*0x15)	/* 4x15H = 0x60 */
+#define NSP_SG_SIZE		SG_ALL
+#define NSP32_SG_END_SGT	0x80000000		/* Last SGT marker */
+#define NSP32_SG_CNT_MASK	0x1FFFF
+
+struct nsp32_sgtable {
+	unsigned long		addr;		/* transfer address */
+	unsigned long		len;		/* transfer length.
+						   Bit (24-32) is for SGT_END */
+};
+
+struct nsp32_sglun {
+	struct nsp32_sgtable sgt[NSP_SG_SIZE+1];	/* SG table */
+};
+
+
+/*
+ * host data structure
+ */
+/* message in/out buffer */
+#define MSGOUTBUF_MAX	13  /* 13 is ok ? */
+#define MSGINBUF_MAX	13
+
+/* flag for trans_method */
+#define NSP32_TRANSFER_BUSMASTER	BIT(0)
+#define NSP32_TRANSFER_MMIO		BIT(1)	/* Not supported yet */
+#define NSP32_TRANSFER_PIO		BIT(2)	/* Not supported yet */
+
+
+/*
+ * SCSI TARGET/LUN definition
+ */
+#define NSP32_HOST_SCSIID	7	/* SCSI initiator is everytime defined as 7 */
+#define MAX_TARGET		8
+#define MAX_LUN			8	/* XXX: In SPI3, max number of LUN is 64. */
+
+
+/*
+ * structure for synchronous transfer negotiation data
+ */
+#define SYNC_NOT_YET	0
+#define SYNC_OK		1
+#define SYNC_NG		2
+
+struct nsp32_sync_table {
+	unsigned char	period_num;	/* period number */
+	unsigned char	ackwidth;	/* ack width designated by period */
+	unsigned char	start_period;	/* search range - start period */
+	unsigned char	end_period;	/* search range - end period */
+};
+
+
+/*
+ * structure for target device static data
+ */
+/* flag for nsp32_target.sync_flag */
+#define SDTR_INITIATOR		BIT(0)	/* sending SDTR from initiator */
+#define SDTR_TARGET		BIT(1)	/* sending SDTR from target */
+#define SDTR_DONE		BIT(2)	/* exchanging SDTR has been processed */
+
+/* syncronous period value for nsp32_target.config_max */
+#define FAST5M			0x32
+#define FAST10M			0x19
+#define ULTRA20M		0x0c
+
+/* flag for nsp32_target.{sync_offset}, period */
+#define ASYNC_OFFSET		0	/* asynchronous transfer */
+#define SYNC_OFFSET		0xf	/* synchronous transfer max offset */
+
+/* syncreg:
+      07 06 05 04 03 02 01 00
+      ---PERIOD-- ---OFFSET--   */
+#define TO_SYNCREG(period, offset)	(period << 4 | offset)
+
+struct nsp32_target {
+	unsigned char	syncreg;	/* value for SYNCREG  */
+	unsigned char	ackwidth;	/* value for ACKWIDTH */
+	unsigned char	offset;		/* sync offset (0-15) */
+	int		sync_flag;	/* SDTR_*, 0 */
+	int		limit_entry;	/* max speed limit entry designated
+					   by EEPROM configuration */
+};
+
+typedef struct _nsp32_hw_data {
+	int IrqNumber;
+	int BaseAddress;
+	int NumAddress;
+#define NSP32_MMIO_OFFSET 0x0800
+	unsigned long MmioAddress;
+	unsigned long length;
+
+	Scsi_Cmnd *CurrentSC;
+
+	struct pci_dev *Pci;
+	const struct pci_device_id *pci_devid;
+	struct Scsi_Host *Host;
+	spinlock_t Lock;
+
+	char info_str[100];
+
+	/* allocated memory region */
+	struct nsp32_lunt	*lunt_list;	/* kmalloc region for lunt */
+	struct nsp32_sglun	*sg_list;	/* sglist virtual address */
+	dma_addr_t		sgaddr;		/* physical address of hw_sg_table */
+	unsigned char		*autoparam;	/* auto parameter transfer region */
+	dma_addr_t		apaddr;		/* physical address of autoparam */
+	int 			cur_entry;	/* current sgt entry */
+
+	/* target/LUN */
+	struct nsp32_lunt	*curlunt;	/* Current connected LUN table */
+	struct nsp32_lunt	*lunt[MAX_TARGET][MAX_LUN];  /* All LUN table */
+	struct nsp32_target	*curtarget;	/* Current connected SCSI ID */
+	struct nsp32_target	target[MAX_TARGET];	     /* SCSI ID */
+	int			pid;		/* Current connected target ID */
+	int			plun;		/* Current connected target LUN */
+
+	/* behavior setting parameters */
+	int			trans_method;	/* transfer method flag */
+	int			resettime;	/* Reset time */
+	int 			clock;	       	/* clock dividing flag */
+	struct nsp32_sync_table	*synct;		/* sync_table determined by clock */
+	int			syncnum;	/* the max number of synct element */
+
+	/* message buffer */
+        unsigned char	msgoutbuf[MSGOUTBUF_MAX]; /* msgout buffer */
+	char		msgoutlen;		  /* msgoutbuf length */
+	unsigned char	msginbuf[MSGINBUF_MAX];	  /* megin buffer */
+	char		msginlen;		  /* msginbuf length */
+
+
+} nsp32_hw_data;
+static nsp32_hw_data nsp32_data_base;  /* probe <-> detect glue */
+
+
+/*
+ * TIME definition
+ */
+#define RESET_HOLD_TIME		10000	/* reset time in us (SCSI-2 says the
+					   minimum is 25us) */
+#define SEL_TIMEOUT_TIME	10000	/* 250ms defined in SCSI specification
+					   (25.6us/1unit) */
+#define ARBIT_TIMEOUT_TIME	100	/* 100us */
+#define REQSACK_TIMEOUT_TIME	10000	/* max wait time for REQ/SACK assertion
+					   or negation, 10000us == 10ms */
+
+/*
+ * structure for connected LUN dynamic data
+ *
+ * Note: Currently tagged queuing is disabled, each nsp32_lunt holds
+ *       one SCSI command and one state.
+ */
+#define DISCPRIV_OK		BIT(0)		/* DISCPRIV Enable mode */
+#define MSGIN03			BIT(1)		/* Auto Msg In 03 Flag */
+
+struct nsp32_lunt {
+	Scsi_Cmnd		*SCpnt;		/* Current Handling Scsi_Cmnd */
+	unsigned long		save_datp;	/* Save Data Pointer - saved position from initial address */
+	int			msgin03;	/* auto msg in 03 flag */
+	unsigned int		sg_num;		/* Total number of SG entries */
+	int			cur_entry;	/* Current SG entry number */
+	struct nsp32_sglun	*sglun;		/* sg table per lun */
+	long			sglun_paddr;	/* sglun physical address */
+};
+
+
+/*
+ * Period/AckWidth speed conversion table
+ *
+ * Note: This period/ackwidth speed table must be in descending order.
+ */
+static struct nsp32_sync_table nsp32_sync_table_40M[] = {
+     /* {PNo, AW,  SP,   EP}  Speed(MB/s) Period AckWidth */
+	{0x1, 0, 0x0c, 0x0c},	/*  20.0 :  50ns,  25ns */
+	{0x2, 0, 0x0d, 0x18},	/*  13.3 :  75ns,  25ns */
+	{0x3, 1, 0x19, 0x19},	/*  10.0 : 100ns,  50ns */
+	{0x4, 1, 0x1a, 0x1f},	/*   8.0 : 125ns,  50ns */
+	{0x5, 2, 0x20, 0x25},	/*   6.7 : 150ns,  75ns */
+	{0x6, 2, 0x26, 0x31},	/*   5.7 : 175ns,  75ns */
+	{0x7, 3, 0x32, 0x32},	/*   5.0 : 200ns, 100ns */
+	{0x8, 3, 0x33, 0x38},	/*   4.4 : 225ns, 100ns */
+	{0x9, 3, 0x39, 0x3e},	/*   4.0 : 250ns, 100ns */
+};
+static const int nsp32_table_40M_num =
+		sizeof(nsp32_sync_table_40M)/sizeof(struct nsp32_sync_table);
+
+static struct nsp32_sync_table nsp32_sync_table_20M[] = {
+	{0x1, 0, 0x19, 0x19},	/* 10.0 : 100ns,  50ns */
+	{0x2, 0, 0x1a, 0x25},	/*  6.7 : 150ns,  50ns */
+	{0x3, 1, 0x26, 0x32},	/*  5.0 : 200ns, 100ns */
+	{0x4, 1, 0x33, 0x3e},	/*  4.0 : 250ns, 100ns */
+	{0x5, 2, 0x3f, 0x4b},	/*  3.3 : 300ns, 150ns */
+	{0x6, 2, 0x4c, 0x57},	/*  2.8 : 350ns, 150ns */
+	{0x7, 3, 0x58, 0x64},	/*  2.5 : 400ns, 200ns */
+	{0x8, 3, 0x65, 0x70},	/*  2.2 : 450ns, 200ns */
+	{0x9, 3, 0x71, 0x7d},	/*  2.0 : 500ns, 200ns */
+};
+static const int nsp32_table_20M_num =
+		sizeof(nsp32_sync_table_20M)/sizeof(struct nsp32_sync_table);
+
+static struct nsp32_sync_table nsp32_sync_table_pci[] = {
+	{0x1, 0, 0x0c, 0x0f},	/* 16.6 :  60ns,  30ns */
+	{0x2, 0, 0x10, 0x16},	/* 11.1 :  90ns,  30ns */
+	{0x3, 1, 0x17, 0x1e},	/*  8.3 : 120ns,  60ns */
+	{0x4, 1, 0x1f, 0x25},	/*  6.7 : 150ns,  60ns */
+	{0x5, 2, 0x26, 0x2d},	/*  5.6 : 180ns,  90ns */
+	{0x6, 2, 0x2e, 0x34},	/*  4.8 : 210ns,  90ns */
+	{0x7, 3, 0x35, 0x3c},	/*  4.2 : 240ns, 120ns */
+	{0x8, 3, 0x3d, 0x43},	/*  3.7 : 270ns, 120ns */
+	{0x9, 3, 0x44, 0x4b}, 	/*  3.3 : 300ns, 120ns */
+};
+static const int nsp32_table_pci_num =
+		sizeof(nsp32_sync_table_pci)/sizeof(struct nsp32_sync_table);
+
+/*
+ * function declaration
+ */
+static int nsp32_detect(Scsi_Host_Template *);
+static int nsp32_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static const char *nsp32_info(struct Scsi_Host *);
+static int nsp32_eh_abort(Scsi_Cmnd *);
+static int nsp32_eh_bus_reset(Scsi_Cmnd *);
+static int nsp32_eh_host_reset(Scsi_Cmnd *);
+static int nsp32_reset(Scsi_Cmnd *, unsigned int);
+static int nsp32_release(struct Scsi_Host *);
+static int nsp32_proc_info(char *, char **, off_t, int, int, int);
+static int __devinit nsp32_probe(struct pci_dev *, const struct pci_device_id *);
+static void __devexit nsp32_remove(struct pci_dev *);
+static int __init init_nsp32(void);
+static void __exit exit_nsp32(void);
+
+static void nsp32_message(char *, int, char *, char *, ...);
+static void nsp32_dmessage(char *, int, int, char *, ...);
+static void nsp32_build_identify(nsp32_hw_data *, Scsi_Cmnd *);
+static void nsp32_build_sdtr(nsp32_hw_data *, unsigned char, unsigned char);
+static void nsp32_build_nop(nsp32_hw_data *);
+static void nsp32_build_reject(nsp32_hw_data *);
+static int nsp32hw_start_selection(Scsi_Cmnd *, nsp32_hw_data *);
+static int nsp32_selection_autoscsi(Scsi_Cmnd *, nsp32_hw_data *);
+static int nsp32_reselection(nsp32_hw_data *, unsigned char);
+static int nsp32hw_setup_sg_table(Scsi_Cmnd *, nsp32_hw_data *);
+static int nsp32hw_init(struct Scsi_Host *);
+static void nsp32_scsi_done(nsp32_hw_data *, Scsi_Cmnd *);
+static int nsp32_busfree_occur(nsp32_hw_data *, unsigned short);
+static void nsp32_adjust_busfree(nsp32_hw_data *, unsigned int);
+static void nsp32_msgout_occur(nsp32_hw_data *);
+static void nsp32_restart_autoscsi(nsp32_hw_data *, unsigned short);
+static void nsp32_msgin_occur(nsp32_hw_data *, unsigned long, unsigned short);
+static void nsp32_analyze_sdtr(nsp32_hw_data *);
+static int nsp32_search_period_entry(nsp32_hw_data *,struct nsp32_target *, unsigned char);
+static void nsp32_set_async(nsp32_hw_data *, struct nsp32_target *);
+static void nsp32_set_max_sync(nsp32_hw_data *, struct nsp32_target *, unsigned char *, unsigned char *);
+static void nsp32_set_sync_entry(nsp32_hw_data *, struct nsp32_target *, int, unsigned char);
+static void nsp32_wait_req(nsp32_hw_data *, int);
+static void nsp32_wait_sack(nsp32_hw_data *, int);
+static void nsp32_sack_assert(nsp32_hw_data *);
+static void nsp32_sack_negate(nsp32_hw_data *);
+static void nsp32_do_bus_reset(nsp32_hw_data *);
+static void do_nsp32_isr(int, void *, struct pt_regs *);
+
+static int nsp32_getprom_param(nsp32_hw_data *);
+static int nsp32_getprom_new(nsp32_hw_data *);
+static int nsp32_getprom_standard(nsp32_hw_data *);
+static int nsp32_prom_read(nsp32_hw_data *, int);
+static void nsp32_prom_start(nsp32_hw_data *);
+static void nsp32_prom_stop(nsp32_hw_data *);
+static void nsp32_prom_write(nsp32_hw_data *, int);
+static int nsp32_prom_fetch(nsp32_hw_data *);
+static inline void nsp32_prom_set(nsp32_hw_data *, int, int);
+static inline int nsp32_prom_get(nsp32_hw_data *, int);
+
+
+/*
+ * max_sectors is currently limited up to 128.
+ */
+static Scsi_Host_Template driver_template = {
+	.proc_name =			"nsp32",
+	.name =				"Workbit NinjaSCSI-32Bi/UDE",
+	.proc_info =			nsp32_proc_info,
+	.detect =			nsp32_detect,
+	.info =				nsp32_info,
+	.queuecommand =			nsp32_queuecommand,
+	.can_queue =			1,
+	.sg_tablesize =			NSP_SG_SIZE,
+	.max_sectors =			128,
+	.cmd_per_lun =			1,
+	.this_id =			7,
+	.use_clustering =		DISABLE_CLUSTERING,
+	.eh_abort_handler =       	nsp32_eh_abort,
+	.eh_device_reset_handler =	NULL,
+	.eh_bus_reset_handler =		nsp32_eh_bus_reset,
+	.eh_host_reset_handler =	nsp32_eh_host_reset,
+	.reset =			nsp32_reset,
+	.release =			nsp32_release,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2))
+	.use_new_eh_code =        	1,
+#else
+	/* .highmem_io =		1,	*/
+#endif
+};
+
+#include "nsp32_io.h"
+
+/*
+ * debug, error print
+ */
+#define nsp32_msg(type, args...) \
+	nsp32_message(__FUNCTION__, __LINE__, (type), ## args)
+#define nsp32_dbg(mask, args...) \
+	nsp32_dmessage(__FUNCTION__, __LINE__, (mask), ## args)
+
+#ifndef NSP32_DEBUG
+# define NSP32_DEBUG_MASK		0x000000
+#else
+# define NSP32_DEBUG_MASK		0xffffff
+#endif
+
+#define NSP32_DEBUG_QUEUECOMMAND	0x000001
+#define NSP32_DEBUG_REGISTER		0x000002
+#define NSP32_DEBUG_AUTOSCSI		0x000004
+#define NSP32_DEBUG_INTR		0x000008
+#define NSP32_DEBUG_SGLIST		0x000010
+#define NSP32_DEBUG_BUSFREE		0x000020
+#define NSP32_DEBUG_CDB_CONTENTS	0x000040
+#define NSP32_DEBUG_RESELECTION		0x000080
+#define NSP32_DEBUG_MSGINOCCUR		0x000100
+#define NSP32_DEBUG_EEPROM		0x000200
+#define NSP32_DEBUG_MSGOUTOCCUR		0x000400
+#define NSP32_DEBUG_BUSRESET		0x000800
+#define NSP32_DEBUG_RESTART		0x001000
+#define NSP32_DEBUG_SYNC		0x002000
+#define NSP32_DEBUG_WAIT		0x004000
+#define NSP32_DEBUG_TARGETFLAG		0x008000
+#define NSP32_DEBUG_PROC		0x010000
+#define NSP32_DEBUG_INIT		0x020000
+#define NSP32_SPECIAL_PRINT_REGISTER	0x100000
+
+#define NSP32_DEBUG_BUF_LEN		100
+
+static void nsp32_message(char *func, int line, char *type, char *fmt, ...)
+{
+	va_list args;
+	char buf[NSP32_DEBUG_BUF_LEN];
+
+	va_start(args, fmt);
+	vsprintf(buf, fmt, args);
+	va_end(args);
+
+#ifndef NSP32_DEBUG
+	printk("%snsp32: %s\n", type, buf);
+#else
+	printk("%snsp32: %s (%d): %s\n", type, func, line, buf);
+#endif
+}
+
+static void nsp32_dmessage(char *func, int line, int mask, char *fmt, ...)
+{
+	va_list args;
+	char buf[NSP32_DEBUG_BUF_LEN];
+
+	va_start(args, fmt);
+	vsprintf(buf, fmt, args);
+	va_end(args);
+
+	if (mask & NSP32_DEBUG_MASK) {
+		printk("Ninja: %d %s (%d): %s\n", mask, func, line, buf);
+	}
+}
+
+#ifdef NSP32_DEBUG
+# include "nsp32_debug.c"
+#else
+# define show_command(arg)   /* */
+# define show_busphase(arg)  /* */
+# define show_autophase(arg) /* */
+#endif
+
+#ifdef NSP32_DEBUG
+static int pc_debug = NSP32_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(/*KERN_DEBUG*/ args)
+#else
+#define DEBUG(n, args...)
+#endif
+
+
+/*
+ * IDENTIFY Message
+ */
+static void nsp32_build_identify(nsp32_hw_data *data, Scsi_Cmnd *SCpnt)
+{
+	int pos = data->msgoutlen;
+
+	data->msgoutbuf[pos++] =
+		0x80 |		/* Identify */
+#if 0
+		/* XXX: Auto DiscPriv detection is progressing... */
+		0x40 |		/* DiscPriv */
+#endif
+		SCpnt->lun;	/* LUNTRN */
+
+	data->msgoutlen = pos;
+}
+
+/*
+ * SDTR Message Routine
+ */
+static void nsp32_build_sdtr(nsp32_hw_data *data,
+			     unsigned char period, unsigned char offset)
+{
+	int pos = data->msgoutlen;
+
+	data->msgoutbuf[pos++] = EXTENDED_MESSAGE;
+	data->msgoutbuf[pos++] = EXTENDED_SDTR_LEN;
+	data->msgoutbuf[pos++] = EXTENDED_SDTR;
+	data->msgoutbuf[pos++] = period;
+	data->msgoutbuf[pos++] = offset;
+
+	data->msgoutlen = pos;
+}
+
+/*
+ * No Operation Message
+ */
+static void nsp32_build_nop(nsp32_hw_data *data)
+{
+	int pos = data->msgoutlen;
+
+	if (pos != 0) {
+		nsp32_msg(KERN_WARNING,
+			  "Some messages are already contained!");
+		return;
+	}
+
+	data->msgoutbuf[pos++] = NOP;
+	data->msgoutlen = pos;
+}
+
+/*
+ * Reject Message
+ */
+static void nsp32_build_reject(nsp32_hw_data *data)
+{
+	int pos = data->msgoutlen;
+
+	data->msgoutbuf[pos++] = MESSAGE_REJECT;
+	data->msgoutlen = pos;
+}
+	
+/*
+ * timer
+ */
+#if 0
+static void nsp32_start_timer(Scsi_Cmnd *SCpnt, int time)
+{
+	unsigned int base = SCpnt->host->io_port;
+
+	DEBUG(0, __func__ " time=%d\n", time);
+
+	if (time & (~TIMER_CNT_MASK)) {
+		printk("timer set overflow\n");
+	}
+
+	nsp32_write2(base, TIMER_SET, time & TIMER_CNT_MASK);
+}
+#endif
+
+
+/*
+ * set SCSI command and other parameter to asic, and start selection phase
+ */
+static int nsp32hw_start_selection(Scsi_Cmnd *SCpnt, nsp32_hw_data *data)
+{
+	unsigned int   host_id = SCpnt->host->this_id;
+	unsigned int   base    = SCpnt->host->io_port;
+	unsigned char  target  = SCpnt->target;
+	unsigned char  *param  = data->autoparam;
+	unsigned char  phase, arbit;
+	int	       i, time;
+	unsigned int   msgout;
+	unsigned long  l;
+	unsigned short s;
+
+	/*
+	 * check bus free
+	 */
+	phase = nsp32_read1(base, SCSI_BUS_MONITOR);
+	if (phase != BUSMON_BUS_FREE) {
+		nsp32_msg(KERN_WARNING, "bus busy");
+		show_busphase(phase & BUSMON_PHASE_MASK);
+		SCpnt->result = DID_BUS_BUSY << 16;
+		return FALSE;
+	}
+
+	/*
+	 * message out
+	 *
+	 * Note: If the range of msgoutlen is 1 - 3, fill scsi_msgout.
+	 *       over 3 messages needs another routine.
+	 */
+	if (data->msgoutlen == 0) {
+		nsp32_msg(KERN_ERR, "SCSI MsgOut without any message!");
+		SCpnt->result = DID_ERROR << 16;
+		return FALSE;
+	} else if (data->msgoutlen > 0 && data->msgoutlen <= 3) {
+		msgout = 0;
+		for (i=0; i<data->msgoutlen; i++) {
+			/*
+			 * the sending order of the message is:
+			 *  MCNT 3: MSG#0 -> MSG#1 -> MSG#2
+			 *  MCNT 2:          MSG#1 -> MSG#2
+			 *  MCNT 1:                   MSG#2    
+			 */
+			msgout >>= 8;
+			msgout |= (unsigned int)(data->msgoutbuf[i] << 24);
+		}
+		msgout |= MV_VALID;	/* MV valid */
+		msgout |= (unsigned int)data->msgoutlen; /* len */
+	} else {
+		/* data->msgoutlen > 3 */
+		msgout = 0;
+	}
+
+	/*
+	 * setup asic parameter
+	 */
+	memset(param, 0, AUTOPARAM_SIZE);
+
+	/* cdb */
+	for (i=0; i<SCpnt->cmd_len; i++) {
+		param[4*i] = SCpnt->cmnd[i];
+	}
+
+	/* message out */
+	param[4*0x10 +0] = (msgout & 0x000000ff) >> 0;
+	param[4*0x10 +1] = (msgout & 0x0000ff00) >> 8;
+	param[4*0x10 +2] = (msgout & 0x00ff0000) >> 16;
+	param[4*0x10 +3] = (msgout & 0xff000000) >> 24;
+
+	/* syncreg, ackwidth, target id, sampleing rate */
+	param[4*0x11 +0] = data->curtarget->syncreg;
+	param[4*0x11 +1] = data->curtarget->ackwidth;
+	param[4*0x11 +2] = BIT(host_id) | BIT(target);
+	param[4*0x11 +3] = 0;
+
+	/* command control */
+	s = (CLEAR_CDB_FIFO_POINTER | AUTOSCSI_START |
+	     AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02 | AUTO_ATN);
+	param[4*0x12 +0] = (s & 0x00ff) >> 0;
+	param[4*0x12 +1] = (s & 0xff00) >> 8;
+
+	/* transfer control */
+	s = 0;
+	switch (data->trans_method) {
+	case NSP32_TRANSFER_BUSMASTER:
+		s |= BM_START;
+		break;
+	case NSP32_TRANSFER_MMIO:
+		s |= CB_MMIO_MODE;
+		break;
+	case NSP32_TRANSFER_PIO:
+		s |= CB_IO_MODE;
+		break;
+	default:
+		nsp32_msg(KERN_ERR, "unknown trans_method");
+	}
+	/*
+	 * ORed BLIEND_MODE, FIFO intr is decreased, instead of PCI bus waits.
+	 * For bus master transfer, it's taken off.
+	 */
+	s |= (TRANSFER_GO | ALL_COUNTER_CLR);
+	param[4*0x12 +2] = (s & 0x00ff) >> 0;
+	param[4*0x12 +3] = (s & 0xff00) >> 8;
+
+	/* sg table addr */
+	l = data->curlunt->sglun_paddr;
+	param[4*0x13 +0] = (l & 0x000000ff) >> 0;
+	param[4*0x13 +1] = (l & 0x0000ff00) >> 8;
+	param[4*0x13 +2] = (l & 0x00ff0000) >> 16;
+	param[4*0x13 +3] = (l & 0xff000000) >> 24;
+
+	/*
+	 * transfer parameter to asic
+	 */
+	nsp32_write4(base, SGT_ADR,         virt_to_bus(param));
+	nsp32_write2(base, COMMAND_CONTROL, CLEAR_CDB_FIFO_POINTER |
+		                            AUTO_PARAMETER         );
+
+	/*
+	 * Arbitration Status Check
+	 *	
+	 * Note: Arbitration counter is wait during ARBIT_GO is not lifting.
+	 *	 Using udelay(1) consumes CPU time and system time, but 
+	 *	 arbitration delay time is defined minimal 2.4us in SCSI
+	 *	 specification, thus udelay works as coarse grained wait timer.
+	 */
+	time = 0;
+	do {
+		arbit = nsp32_read1(base, ARBIT_STATUS);
+		nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "arbit=0x%x", arbit);
+	} while ((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&
+		 (time++ <= 1000));
+
+	nsp32_dbg(NSP32_DEBUG_AUTOSCSI,
+		  "arbit: 0x%x, delay time: %d", arbit, time);
+
+	if (arbit & ARBIT_WIN) {
+		SCpnt->result = DID_OK << 16;
+		/* PCI LED on! */
+		nsp32_index_write1(base, EXT_PORT, LED_ON);
+	} else if (arbit & ARBIT_FAIL) {
+		SCpnt->result = DID_BUS_BUSY << 16;
+		nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR);
+		return FALSE;
+	} else {
+		/* unknown error or ARBIT_GO timeout */
+		nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "arbit fail");
+		SCpnt->result = DID_NO_CONNECT << 16;
+		nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR);
+		return FALSE;
+        }
+
+	/*
+	 * clear Arbit
+	 */
+	nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR);
+
+	return TRUE;
+}
+
+
+/*
+ * Selection with AUTO SCSI (without AUTO PARAMETER)
+ */
+static int nsp32_selection_autoscsi(Scsi_Cmnd *SCpnt, nsp32_hw_data *data)
+{
+	unsigned char	phase;
+	unsigned char	arbit;
+	int		status;
+	int		i;
+	unsigned short	command	= 0;
+	int		time = 0;
+	unsigned int	msgout = 0;
+	unsigned short	execph;
+	unsigned int	base = data->BaseAddress;
+
+	/*
+	 * IRQ disable
+	 */
+	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
+
+	/*
+	 * check bus line
+	 */
+	phase = nsp32_read1(base, SCSI_BUS_MONITOR);
+	if(((phase & BUSMON_BSY) == 1) ||
+	   (phase & BUSMON_SEL) == 1) {
+		nsp32_msg(KERN_WARNING, "bus busy");
+		SCpnt->result = DID_BUS_BUSY << 16;
+		status = 1;
+		goto out;
+        }
+
+	/*
+	 * clear execph
+	 */
+	execph = nsp32_read2(base, SCSI_EXECUTE_PHASE);
+
+	/*
+	 * clear FIFO counter to set CDBs
+	 */
+	nsp32_write2(base, COMMAND_CONTROL, CLEAR_CDB_FIFO_POINTER);
+
+	/*
+	 * set CDB0 - CDB15
+	 */
+	for (i=0; i<SCpnt->cmd_len; i++) {
+		nsp32_write1(base, COMMAND_DATA, SCpnt->cmnd[i]);
+        }
+	nsp32_dbg(NSP32_DEBUG_CDB_CONTENTS, "CDB[0]=[0x%x]", SCpnt->cmnd[i]);
+
+	/*
+	 * set SCSIOUT LATCH(initiator)/TARGET(target) (ORed) ID
+	 */
+	nsp32_write1(base, SCSI_OUT_LATCH_TARGET_ID,
+		((1 << NSP32_HOST_SCSIID) | (1 << SCpnt->target)));
+
+	/*
+	 * set SCSI MSGOUT REG
+	 *
+	 * Note: If the range of msgoutlen is 1 - 3, fill scsi_msgout.
+	 *       over 3 messages needs another routine.
+	 */
+	if (data->msgoutlen == 0) {
+		nsp32_msg(KERN_ERR, 
+			  "SCSI MsgOut without any message!");
+		SCpnt->result = DID_ERROR << 16;
+		status = 1;
+		goto out;
+	} else if (data->msgoutlen > 0 && data->msgoutlen <= 3) {
+		msgout = 0;
+		for (i=0; i<data->msgoutlen; i++) {
+			/*
+			 * the sending order of the message is:
+			 *  MCNT 3: MSG#0 -> MSG#1 -> MSG#2
+			 *  MCNT 2:          MSG#1 -> MSG#2
+			 *  MCNT 1:                   MSG#2    
+			 */
+			msgout >>= 8;
+			msgout |= (unsigned int)(data->msgoutbuf[i] << 24);
+		}
+		msgout |= MV_VALID;	/* MV valid */
+		msgout |= (unsigned int)data->msgoutlen; /* len */
+		nsp32_write4(base, SCSI_MSG_OUT, msgout);
+	} else {
+		/* data->msgoutlen > 3 */
+		nsp32_write4(base, SCSI_MSG_OUT, 0);
+	}
+
+	/*
+	 * set selection timeout(= 250ms)
+	 */
+	nsp32_write2(base, SEL_TIME_OUT, SEL_TIMEOUT_TIME);
+
+	/*
+	 * set smpl rate
+	 * 
+	 * TODO: smpl_rate (BASE+0F) is 0 when internal clock = 40MHz.
+	 *      check other internal clock!
+	 */
+	nsp32_write1(base, SREQ_SMPL_RATE, 0);
+
+	/*
+	 * clear Arbit
+	 */
+	nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR);
+
+	/*
+	 * set SYNCREG
+	 * Don't set BM_START_ADR before setting this register.
+	 */
+	nsp32_write1(base, SYNC_REG, data->curtarget->syncreg);
+
+	/*
+	 * set ACKWIDTH
+	 */
+	nsp32_write1(base, ACK_WIDTH, data->curtarget->ackwidth);
+
+	nsp32_dbg(NSP32_DEBUG_AUTOSCSI,
+		  "syncreg=0x%x, ackwidth=0x%x, sgtpaddr=0x%x, id=0x%x",
+		  nsp32_read1(base, SYNC_REG), nsp32_read1(base, ACK_WIDTH),
+		  nsp32_read4(base, SGT_ADR), nsp32_read1(base, SCSI_OUT_LATCH_TARGET_ID));
+	nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "msgoutlen=%d, msgout=0x%x",
+		  data->msgoutlen, msgout);
+
+	/*
+	 * set SGT ADDR (physical address)
+	 */
+	nsp32_write4(base, SGT_ADR, data->curlunt->sglun_paddr);
+
+	/*
+	 * set TRANSFER CONTROL REG
+	 */
+	command = 0;
+	command |= ( TRANSFER_GO | ALL_COUNTER_CLR);
+	if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
+		if (SCpnt->request_bufflen > 0) {
+			command |= BM_START;
+		}
+	} else if (data->trans_method & NSP32_TRANSFER_MMIO) {
+		command |= CB_MMIO_MODE;
+	} else if (data->trans_method & NSP32_TRANSFER_PIO) {
+		command |= CB_IO_MODE;
+	}
+	nsp32_write2(base, TRANSFER_CONTROL, command);
+
+	/*
+	 * start AUTO SCSI, kick off arbitration
+	 */
+	command = 0;
+	command |= (CLEAR_CDB_FIFO_POINTER
+		    | AUTOSCSI_START
+		    | AUTO_MSGIN_00_OR_04
+		    | AUTO_MSGIN_02 
+		    | AUTO_ATN);
+	nsp32_write2(base, COMMAND_CONTROL, command);
+
+	/*
+	 * Arbitration Status Check
+	 *	
+	 * Note: Arbitration counter is wait during ARBIT_GO is not lifting.
+	 *	 Using udelay(1) consumes CPU time and system time, but 
+	 *	 arbitration delay time is defined minimal 2.4us in SCSI
+	 *	 specification, thus udelay works as coarse grained wait timer.
+	 */
+	time = 0;
+	while(1) {
+		arbit = nsp32_read1(base, ARBIT_STATUS);
+		if(arbit & ARBIT_GO) {
+			udelay(1);
+			time++;
+			if ( time > ARBIT_TIMEOUT_TIME ) {
+				/* something lock up! guess no connection */
+				SCpnt->result = DID_NO_CONNECT << 16;
+				status = FALSE;
+				goto out;
+			}
+		} else {
+			break;
+		}
+	};
+
+	nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "arbit: 0x%x, delay time: %d", arbit, time);
+
+	/*
+	 * check Arbitration Status Result
+	 */
+	if(arbit & ARBIT_WIN) {
+		/* Arbitration succeeded */
+		status = TRUE;
+		SCpnt->result = DID_OK << 16;
+		/* PCI LED on! */
+		nsp32_index_write1(base, EXT_PORT, LED_ON);
+	} else if(arbit & ARBIT_FAIL) {
+		/* Arbitration failed */
+		status = FALSE;
+		SCpnt->result = DID_BUS_BUSY << 16;
+	} else {
+		/* unknown error? */
+		status = FALSE;
+		SCpnt->result = DID_ERROR << 16;
+		SCpnt->result = DID_NO_CONNECT << 16;
+	}
+
+	/*
+	 * clear Arbit
+	 */
+	nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR);
+
+ out:
+	/*
+	 * IRQ enable
+	 */
+	nsp32_write2(base, IRQ_CONTROL, 0);
+
+	return(status);
+}
+
+
+/*
+ * reselection
+ *
+ * Note: This reselection routine is called from msgin_occur,
+ *	 reselection target id&lun must be already set.
+ *	 SCSI-2 says IDENTIFY implies RESTORE_POINTER operation.
+ */
+static int nsp32_reselection(nsp32_hw_data *data, unsigned char newlun)
+{
+	unsigned int base = data->BaseAddress;
+	unsigned char tmpid, newid;
+
+	nsp32_dbg(NSP32_DEBUG_RESELECTION, "enter");
+
+	/*
+	 * calculate reselected SCSI ID
+	 */
+	tmpid = nsp32_read1(base, RESELECT_ID);
+	tmpid &= 0x7f;
+	newid = 0;
+	while (tmpid) {
+		if (tmpid & 1) {
+			break;
+		}
+		tmpid >>= 1;
+		newid++;
+	}
+
+	/*
+	 * If reselected New ID:LUN is not existed
+	 * or current nexus is not existed, unexpected
+	 * reselection is occured. Send reject message.
+	 */
+	if (newid >= MAX_TARGET || newlun >= MAX_LUN) {
+		nsp32_msg(KERN_WARNING, "unknown id/lun");
+		return FALSE;
+	} else if(data->lunt[newid][newlun]->SCpnt == NULL) {
+		nsp32_msg(KERN_WARNING, "no SCSI command is processing");
+		return FALSE;
+	}
+
+	data->pid       = newid;
+	data->plun      = newlun;
+	data->curtarget = &data->target[newid];
+	data->curlunt   = data->lunt[newid][newlun];
+
+	/* reset SACK/SavedACK counter (or ALL clear?) */
+	nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK);
+
+	return TRUE;
+}
+
+
+/*
+ * nsp32hw_setup_sg_table - build scatter gather list for transfer data
+ *			    with bus master.
+ *
+ * Note: NinjaSCSI-32Bi/UDE bus master can not transfer over 64KB at a time.
+ */
+static int nsp32hw_setup_sg_table(Scsi_Cmnd *SCpnt, nsp32_hw_data *data)
+{
+	struct scatterlist *sgl;
+	struct nsp32_sgtable *sgt = data->curlunt->sglun->sgt;
+	int num, i;
+
+	if (SCpnt->request_bufflen == 0) {
+		return TRUE;
+	}
+
+	if (sgt == NULL) {
+		nsp32_dbg(NSP32_DEBUG_SGLIST, "SGT == null");
+		return FALSE;
+	}
+
+	if (SCpnt->use_sg) {
+		sgl = (struct scatterlist *)SCpnt->request_buffer;
+		num = pci_map_sg(data->Pci, sgl, SCpnt->use_sg,
+				 scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+		for (i=0; i<num; i++) {
+			/*
+			 * Build nsp32_sglist, substitute sg dma addresses.
+			 */
+			sgt[i].addr = cpu_to_le32(sg_dma_address(sgl));
+			sgt[i].len  = cpu_to_le32(sg_dma_len(sgl));
+			sgl++;
+
+			if (sgt[i].len > 65536) {
+				nsp32_msg(KERN_ERR,
+					"can't transfer over 64KB at a time");
+				return FALSE;
+			}
+			nsp32_dbg(NSP32_DEBUG_SGLIST,
+				  "num 0x%x : addr 0x%lx len 0x%x",
+				  i, sgt[i].addr, sgt[i].len);
+		}
+		sgt[num-1].len |= NSP32_SG_END_SGT; /* set end mark */
+	} else {
+		SCpnt->SCp.have_data_in	= pci_map_single(data->Pci,
+			SCpnt->request_buffer, SCpnt->request_bufflen,
+			scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+		sgt[0].addr = cpu_to_le32(SCpnt->SCp.have_data_in);
+		sgt[0].len  = cpu_to_le32(SCpnt->request_bufflen);
+		sgt[0].len |= NSP32_SG_END_SGT; /* set end mark */
+
+		nsp32_dbg(NSP32_DEBUG_SGLIST, "single : addr 0x%lx len=0x%x",
+			  sgt[0].addr, sgt[0].len);
+	}
+
+	return TRUE;
+}
+
+static int nsp32_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->host->hostdata;
+	struct nsp32_target *target;
+	struct nsp32_lunt *curlunt;
+	int ret;
+
+	nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
+		  "enter. target: 0x%x LUN: 0x%x cmnd: 0x%x cmndlen: 0x%x "
+		  "use_sg: 0x%x reqbuf: 0x%lx reqlen: 0x%x",
+		  SCpnt->target, SCpnt->lun, SCpnt->cmnd[0], SCpnt->cmd_len,
+		  SCpnt->use_sg, SCpnt->request_buffer, SCpnt->request_bufflen);
+
+	if (data->CurrentSC != NULL ) {
+		nsp32_msg(KERN_ERR, "Currentsc != NULL. Cancel this command request");
+		data->CurrentSC = NULL;
+		SCpnt->result   = DID_NO_CONNECT << 16;
+		done(SCpnt);
+
+		return 1;
+	}
+
+	/* check target ID is not same as this initiator ID */
+	if (SCpnt->target == NSP32_HOST_SCSIID) {
+		SCpnt->result = DID_BAD_TARGET << 16;
+		done(SCpnt);
+		return 1;
+	}
+
+	/* check target LUN is allowable value */
+	if (SCpnt->lun >= MAX_LUN) {
+		SCpnt->result = DID_BAD_TARGET << 16;
+		done(SCpnt);
+		return 1;
+	}
+
+	show_command(SCpnt);
+
+	SCpnt->scsi_done     = done;
+	data->CurrentSC      = SCpnt;
+	SCpnt->SCp.Status    = CHECK_CONDITION;
+	SCpnt->SCp.Message   = 0;
+	SCpnt->resid         = 0; //SCpnt->request_bufflen;
+
+	SCpnt->SCp.ptr		    = (char *) SCpnt->request_buffer;
+	SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
+	SCpnt->SCp.buffer	    = NULL;
+	SCpnt->SCp.buffers_residual = 0;
+
+	/* initialize data */
+	data->msgoutlen		= 0;
+	data->msginlen		= 0;
+	curlunt			= data->lunt[SCpnt->target][SCpnt->lun];
+	curlunt->SCpnt		= SCpnt;
+	curlunt->save_datp	= 0;
+	curlunt->msgin03	= FALSE;
+	data->curlunt		= curlunt;
+	data->pid		= SCpnt->target;
+	data->plun		= SCpnt->lun;
+
+	ret = nsp32hw_setup_sg_table(SCpnt, data);
+	if (ret == FALSE) {
+		SCpnt->result = DID_ERROR << 16;
+		nsp32_scsi_done(data, SCpnt);
+	}
+
+	/* Build IDENTIFY */
+	nsp32_build_identify(data, SCpnt);
+
+	/* 
+	 * If target is the first time to transfer after the reset
+	 * (target don't have SDTR_DONE and SDTR_INITIATOR), sync
+	 * message SDTR is needed to do synchronous transfer.
+	 */
+	target = &data->target[SCpnt->target];
+	data->curtarget = target;
+
+	if (!(target->sync_flag & (SDTR_DONE | SDTR_INITIATOR | SDTR_TARGET))) {
+		unsigned char period, offset;
+
+		if (trans_mode != ASYNC_MODE) {
+			nsp32_set_max_sync(data, target, &period, &offset);
+			nsp32_build_sdtr(data, period, offset);
+			target->sync_flag |= SDTR_INITIATOR;
+		} else {
+			nsp32_set_async(data, target);
+			target->sync_flag |= SDTR_DONE;
+		}
+
+		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
+			  "SDTR: entry: %d start_period: 0x%x offset: 0x%x\n",
+			  target->limit_entry, period, offset);
+	} else if (target->sync_flag & SDTR_INITIATOR) {
+		/*
+		 * It was negotiating SDTR with target, sending from the
+		 * initiator, but there are no chance to remove this flag.
+		 * Set async because we don't get proper negotiation.
+		 */
+		nsp32_set_async(data, target);
+		target->sync_flag &= ~SDTR_INITIATOR;
+		target->sync_flag |= SDTR_DONE;
+
+		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
+			  "SDTR_INITIATOR: fall back to async");
+	} else if (target->sync_flag & SDTR_TARGET) {
+		/*
+		 * It was negotiating SDTR with target, sending from target,
+		 * but there are no chance to remove this flag.  Set async
+		 * because we don't get proper negotiation.
+		 */
+		nsp32_set_async(data, target);
+		target->sync_flag &= ~SDTR_TARGET;
+		target->sync_flag |= SDTR_DONE;
+
+		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
+			  "Unknown SDTR from target is reached, fall back to async.");
+	}
+
+	nsp32_dbg(NSP32_DEBUG_TARGETFLAG,
+		  "target: %d sync_flag: 0x%x syncreg: 0x%x ackwidth: 0x%x",
+		  SCpnt->target, target->sync_flag, target->syncreg,
+		  target->ackwidth);
+
+	/* Selection */
+	if (auto_param == 0) {
+		ret = nsp32hw_start_selection(SCpnt, data);
+	} else {
+		ret = nsp32_selection_autoscsi(SCpnt, data);
+	}
+
+	if (ret != TRUE) {
+		nsp32_scsi_done(data, SCpnt);
+		return 1;
+	}
+
+	return 0;
+}
+
+/* initialize asic */
+static int nsp32hw_init(struct Scsi_Host *host)
+{
+	unsigned int  base = host->io_port;
+	unsigned short irq_stat;
+	unsigned long lc_reg;
+	unsigned char power;
+	nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata;
+
+	lc_reg = nsp32_index_read4(base, CFG_LATE_CACHE);
+	if ((lc_reg & 0xff00) == 0) {
+		lc_reg |= (0x20 << 8);
+		nsp32_index_write2(base, CFG_LATE_CACHE, lc_reg & 0xffff);
+	}
+
+	nsp32_write2(base, IRQ_CONTROL,      IRQ_CONTROL_ALL_IRQ_MASK);
+	nsp32_write2(base, TRANSFER_CONTROL, 0);
+	nsp32_write4(base, BM_CNT,           0);
+	nsp32_write2(base, SCSI_EXECUTE_PHASE, 0);
+
+	do {
+		irq_stat = nsp32_read2(base, IRQ_STATUS);
+	} while (irq_stat & IRQSTATUS_ANY_IRQ);
+	nsp32_dbg(NSP32_DEBUG_INIT, "irq_stat 0x%x", irq_stat);
+
+	/*
+	 * Fill FIFO_FULL_SHLD, FIFO_EMPTY_SHLD. Below parameter is
+	 *  designated by specification.
+	 */
+	if ((data->trans_method & NSP32_TRANSFER_PIO) ||
+	    (data->trans_method & NSP32_TRANSFER_MMIO)) {
+		nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT, 0x40);
+	} else if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
+		nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT, 0x10);
+	}
+	nsp32_index_write1(base, FIFO_EMPTY_SHLD_COUNT, 0x60);
+
+	nsp32_dbg(NSP32_DEBUG_INIT, "full 0x%x emp 0x%x",
+		  nsp32_index_read1(base, FIFO_FULL_SHLD_COUNT),
+		  nsp32_index_read1(base, FIFO_EMPTY_SHLD_COUNT));
+
+	nsp32_index_write1(base, CLOCK_DIV, data->clock);
+	nsp32_index_write1(base, BM_CYCLE, MEMRD_CMD1 | SGT_AUTO_PARA_MEMED_CMD);
+	nsp32_write1(base, PARITY_CONTROL, 0);	/* parity check is disable */
+
+	/*
+	 * initialize I_MISC_WRRD register
+	 * 
+	 * Note: Designated parameters is obeyed as following:
+	 *	MISC_SCSI_DIRECTION_DETECTOR_SELECT: It must be set.
+	 *	MISC_MASTER_TERMINATION_SELECT:      It must be set.
+	 *	MISC_BMREQ_NEGATE_TIMING_SEL:	     It should be set.
+	 *	MISC_AUTOSEL_TIMING_SEL:	     It should be set.
+	 *	MISC_BMSTOP_CHANGE2_NONDATA_PHASE:   It should be set.
+	 *	MISC_DELAYED_BMSTART:		     It's selected for safety.
+	 *
+	 * Note: If MISC_BMSTOP_CHANGE2_NONDATA_PHASE is set, then
+	 *	we have to set TRANSFERCONTROL_BM_START as 0 and set
+	 *	appropriate value before restarting bus master transfer.
+	 */
+	nsp32_index_write2(base, MISC_WR,
+			   (SCSI_DIRECTION_DETECTOR_SELECT |
+			    DELAYED_BMSTART |
+			    MASTER_TERMINATION_SELECT |
+			    BMREQ_NEGATE_TIMING_SEL |
+			    AUTOSEL_TIMING_SEL |
+			    BMSTOP_CHANGE2_NONDATA_PHASE));
+
+	nsp32_index_write1(base, TERM_PWR_CONTROL, 0);
+	power = nsp32_index_read1(base, TERM_PWR_CONTROL);
+	if (!(power & SENSE)) {
+		nsp32_msg(KERN_INFO, "term power on");
+		nsp32_index_write1(base, TERM_PWR_CONTROL, BPWR);
+	}
+
+	nsp32_write2(base, TIMER_SET, TIMER_STOP);
+	nsp32_write2(base, TIMER_SET, TIMER_STOP);
+
+	nsp32_write1(base, SYNC_REG,  0);
+	nsp32_write1(base, ACK_WIDTH, 0);
+	nsp32_write2(base, SEL_TIME_OUT, 10000); /* 25us x10000 = 250ms defined in SCSI */
+
+	/*
+	 * enable to select designated IRQ (except for
+	 * IRQSELECT_SERR, IRQSELECT_PERR, IRQSELECT_BMCNTERR)
+	 */
+	nsp32_index_write2(base, IRQ_SELECT, IRQSELECT_TIMER_IRQ         |
+			                     IRQSELECT_SCSIRESET_IRQ     |
+			                     IRQSELECT_FIFO_SHLD_IRQ     |
+			                     IRQSELECT_RESELECT_IRQ      |
+			                     IRQSELECT_PHASE_CHANGE_IRQ  |
+			                     IRQSELECT_AUTO_SCSI_SEQ_IRQ |
+			                     //IRQSELECT_BMCNTERR_IRQ    |
+			                     IRQSELECT_TARGET_ABORT_IRQ  |
+			                     IRQSELECT_MASTER_ABORT_IRQ );
+	nsp32_write2(base, IRQ_CONTROL, 0);
+
+	/* PCI LED off */
+	nsp32_index_write1(base, EXT_PORT_DDR, LED_OFF);
+	nsp32_index_write1(base, EXT_PORT, LED_OFF);
+
+	return TRUE;
+}
+
+
+/* interrupt routine */
+static void do_nsp32_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	nsp32_hw_data *data = dev_id;
+	unsigned int base = data->BaseAddress;
+	Scsi_Cmnd *SCpnt = data->CurrentSC;
+	unsigned short auto_stat, irq_stat, trans_stat;
+	unsigned char busmon, busphase;
+	unsigned long flags;
+	int ret;
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+	struct Scsi_Host *host = data->Host;
+	spin_lock_irqsave(host->host_lock, flags);
+#else
+	spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+	/*
+	 * IRQ check, then enable IRQ mask
+	 */
+	irq_stat = nsp32_read2(base, IRQ_STATUS);
+	nsp32_dbg(NSP32_DEBUG_INTR, 
+		  "enter IRQ: %d, IRQstatus: 0x%x", irq, irq_stat);
+	/* is this interrupt comes from Ninja asic? */
+	if ((irq_stat & IRQSTATUS_ANY_IRQ) == 0) {
+		nsp32_msg(KERN_INFO, "spurious interrupt: irq other 0x%x", irq_stat);
+		goto out2;
+	}
+	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
+
+	busmon = nsp32_read1(base, SCSI_BUS_MONITOR);
+	busphase = busmon & BUSMON_PHASE_MASK;
+
+	trans_stat = nsp32_read2(base, TRANSFER_STATUS);
+	if ((irq_stat == 0xffff) && (trans_stat == 0xffff)) {
+		nsp32_msg(KERN_INFO, "card disconnect");
+		if (data->CurrentSC != NULL) {
+			nsp32_msg(KERN_INFO, "clean up current SCSI command");
+			SCpnt->result = DID_BAD_TARGET << 16;
+			nsp32_scsi_done(data, SCpnt);
+		}
+		goto out;
+	}
+
+	/* Timer IRQ */
+	if (irq_stat & IRQSTATUS_TIMER_IRQ) {
+		DEBUG(0, "timer stop\n");
+		nsp32_write2(base, TIMER_SET, TIMER_STOP);
+		goto out;
+	}
+
+	/* SCSI reset */
+	if (irq_stat & IRQSTATUS_SCSIRESET_IRQ) {
+		nsp32_msg(KERN_INFO, "detected someone do bus reset");
+		nsp32_do_bus_reset(data);
+		if (SCpnt != NULL) {
+			SCpnt->result = DID_RESET << 16;
+			nsp32_scsi_done(data, SCpnt);
+		}
+		goto out;
+	}
+	
+	if (SCpnt == NULL) {
+		nsp32_msg(KERN_WARNING, "SCpnt==NULL this can't be happen\n");
+		nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x\n", irq_stat, trans_stat);
+		goto out;
+	}
+
+	/*
+	 * AutoSCSI Interrupt.
+	 * Note: This interrupt is occured when AutoSCSI is finished.  Then
+	 * check SCSIEXECUTEPHASE, and do appropriate action.  Each phases are
+	 * recorded when AutoSCSI sequencer has been processed.
+	 */
+	if(irq_stat & IRQSTATUS_AUTOSCSI_IRQ) {
+		/* getting SCSI executed phase */
+		auto_stat = nsp32_read2(base, SCSI_EXECUTE_PHASE);
+		nsp32_write2(base, SCSI_EXECUTE_PHASE, 0);
+
+		/* Selection Timeout, go busfree phase. */
+		if (auto_stat & SELECTION_TIMEOUT) {
+			nsp32_dbg(NSP32_DEBUG_INTR,
+				  "selection timeout occured");
+
+			SCpnt->result = DID_TIME_OUT << 16;
+			nsp32_scsi_done(data, SCpnt);
+			goto out;
+		}
+
+		if (auto_stat & MSGOUT_PHASE) {
+			/*
+			 * MsgOut phase was processed.
+			 * If MSG_IN_OCCUER is not set, then MsgOut phase is
+			 * completed. Thus, msgoutlen must reset.  Otherwise,
+			 * nothing to do here. If MSG_OUT_OCCUER is occured,
+			 * then we will encounter the condition and check.
+			 */
+			if (!(auto_stat & MSG_IN_OCCUER) &&
+			     (data->msgoutlen <= 3)) {
+				/*
+				 * !MSG_IN_OCCUER && msgoutlen <=3
+				 *   ---> AutoSCSI with MSGOUTreg is processed.
+				 */
+				data->msgoutlen = 0;
+			};
+
+			nsp32_dbg(NSP32_DEBUG_INTR, "MsgOut phase processed");
+		}
+
+		if ((auto_stat & DATA_IN_PHASE) &&
+		    (SCpnt->resid > 0) &&
+		    ((nsp32_read2(base, FIFO_REST_CNT) & FIFO_REST_MASK) != 0)) {
+			printk( "auto+fifo\n");
+			//nsp32_pio_read(SCpnt);
+		}
+
+		if (auto_stat & (DATA_IN_PHASE | DATA_OUT_PHASE)) {
+			/* DATA_IN_PHASE/DATA_OUT_PHASE was processed. */
+			nsp32_dbg(NSP32_DEBUG_INTR,
+				  "Data in/out phase processed");
+
+			/* read BMCNT, SGT pointer addr */
+			nsp32_dbg(NSP32_DEBUG_INTR, "BMCNT=0x%lx", 
+				    nsp32_read4(base, BM_CNT));
+			nsp32_dbg(NSP32_DEBUG_INTR, "addr=0x%lx", 
+				    nsp32_read4(base, SGT_ADR));
+			nsp32_dbg(NSP32_DEBUG_INTR, "SACK=0x%lx", 
+				    nsp32_read4(base, SACK_CNT));
+			nsp32_dbg(NSP32_DEBUG_INTR, "SSACK=0x%lx", 
+				    nsp32_read4(base, SAVED_SACK_CNT));
+			
+		}
+
+		/*
+		 * MsgIn Occur
+		 */
+		if (auto_stat & MSG_IN_OCCUER) {
+			nsp32_msgin_occur(data, irq_stat, auto_stat);
+		}
+
+		/*
+		 * MsgOut Occur
+		 */
+		if (auto_stat & MSG_OUT_OCCUER) {
+			nsp32_msgout_occur(data);
+		}
+
+		/*
+		 * Bus Free Occur
+		 */
+		if (auto_stat & BUS_FREE_OCCUER) {
+			ret = nsp32_busfree_occur(data, auto_stat);
+			if (ret == TRUE) {
+				goto out;
+			}
+		}
+
+		if (auto_stat & STATUS_PHASE) {
+			/*
+			 * Read CSB and substitute CSB for SCpnt->result
+			 * to save status phase stutas byte.
+			 * scsi error handler checks host_byte (DID_*:
+			 * low level driver to indicate status), then checks 
+			 * status_byte (SCSI status byte).
+			 */
+			SCpnt->result =	(int)nsp32_read1(base, SCSI_CSB_IN);
+		}
+
+		if (auto_stat & ILLEGAL_PHASE) {
+			/* Illegal phase is detected. SACK is not back. */
+			nsp32_msg(KERN_WARNING, 
+				  "AUTO SCSI ILLEGAL PHASE OCCUR!!!!");
+
+			/* TODO: currently we don't have any action... bus reset? */
+
+			/*
+			 * To send back SACK, assert, wait, and negate.
+			 */
+			nsp32_sack_assert(data);
+			nsp32_wait_req(data, NEGATE);
+			nsp32_sack_negate(data);
+
+		}
+
+		if (auto_stat & COMMAND_PHASE) {
+			/* nothing to do */
+			nsp32_dbg(NSP32_DEBUG_INTR, "Command phase processed");
+		}
+
+		if (auto_stat & AUTOSCSI_BUSY) {
+			/* AutoSCSI is running */
+		}
+
+		show_autophase(auto_stat);
+	}
+
+	/* FIFO_SHLD_IRQ */
+	if (irq_stat & IRQSTATUS_FIFO_SHLD_IRQ) {
+		nsp32_dbg(NSP32_DEBUG_INTR, "FIFO IRQ");
+
+		switch(busphase) {
+		case BUSPHASE_DATA_OUT:
+			printk( "write\n");
+
+			//nsp32_pio_write(SCpnt);
+
+			break;
+
+		case BUSPHASE_DATA_IN:
+			printk( "read\n");
+
+			//nsp32_pio_read(SCpnt);
+
+			break;
+
+		case BUSPHASE_STATUS:
+			//DEBUG(0, "fifo/status\n");
+
+			SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN);
+
+			break;
+		default:
+			printk("fifo/other phase?\n");
+			printk("irq_stat=0x%x trans_stat=0x%x\n", irq_stat, trans_stat);
+			show_busphase(busphase);
+			break;
+		}
+
+		goto out;
+	}
+
+	/* Phase Change IRQ */
+	if (irq_stat & IRQSTATUS_PHASE_CHANGE_IRQ) {
+		nsp32_dbg(NSP32_DEBUG_INTR, "phase change IRQ");
+
+		switch(busphase) {
+		case BUSPHASE_MESSAGE_IN:
+			nsp32_dbg(NSP32_DEBUG_INTR, "phase chg/msg in");
+			nsp32_msgin_occur(data, irq_stat, 0);
+			break;
+		default:
+			nsp32_msg(KERN_WARNING, "phase chg/other phase?");
+			nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x\n",
+				  irq_stat, trans_stat);
+			show_busphase(busphase);
+			break;
+		}
+		goto out;
+	}
+
+	/* PCI_IRQ */
+	if (irq_stat & IRQSTATUS_PCI_IRQ) {
+		nsp32_dbg(NSP32_DEBUG_INTR, "PCI IRQ occured");
+		/* Do nothing */
+	}
+
+	/* BMCNTERR_IRQ */
+	if (irq_stat & IRQSTATUS_BMCNTERR_IRQ) {
+		nsp32_msg(KERN_ERR, "Received unexpected BMCNTERR IRQ! ");
+		/*
+		 * TODO: To be implemented improving bus master
+		 * transfer reliablity when BMCNTERR is occured in
+		 * AutoSCSI phase described in specification.
+		 */
+	}
+
+#if 0
+	printk("irq_stat=0x%x trans_stat=0x%x\n", irq_stat, trans_stat);
+	show_busphase(busphase);
+#endif
+
+ out:
+	/* disable IRQ mask */
+	nsp32_write2(base, IRQ_CONTROL, 0);
+
+ out2:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	spin_unlock_irqrestore(&io_request_lock, flags);
+#else
+	spin_unlock_irqrestore(host->host_lock, flags);
+#endif
+
+	nsp32_dbg(NSP32_DEBUG_INTR, "exit");
+
+	return;
+}
+
+#undef SPRINTF
+#define SPRINTF(args...) \
+        do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0)
+static int nsp32_proc_info(char  *buffer,
+			   char **start,
+			   off_t  offset,
+			   int    length,
+			   int    hostno,
+			   int    inout)
+{
+	char *pos = buffer;
+	int thislength;
+	unsigned long flags;
+	nsp32_hw_data *data;
+	struct Scsi_Host *host = NULL;
+	unsigned int base;
+	unsigned char mode_reg;
+
+	/* Write is not supported, just return. */
+	if (inout == TRUE) {
+		return -EINVAL;
+	}
+
+	/* search this HBA host */
+	for (host=scsi_hostlist; host; host=host->next) {
+		if (host->host_no == hostno) {
+			break;
+		}
+	}
+	if (host == NULL) {
+		return -ESRCH;
+	}
+	data = (nsp32_hw_data *)host->hostdata;
+	base = host->io_port;
+
+	SPRINTF("NinjaSCSI-32 status\n\n");
+	SPRINTF("Driver version:        %s\n",		nsp32_release_version);
+	SPRINTF("SCSI host No.:         %d\n",		hostno);
+	SPRINTF("IRQ:                   %d\n",		host->irq);
+	SPRINTF("IO:                    0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
+	SPRINTF("MMIO(virtual address): 0x%lx\n",	host->base);
+	SPRINTF("sg_tablesize:          %d\n",		host->sg_tablesize);
+	SPRINTF("Chip revision:         %d\n",		(nsp32_read2(base, INDEX_REG) >> 8) - 0x4f);
+
+	mode_reg = nsp32_index_read1(base, CHIP_MODE);
+
+#ifdef CONFIG_PM
+	//SPRINTF("Power Management:      %s\n",          (mode_reg & OPTF) ? "yes" : "no");
+#endif
+	SPRINTF("OEM:                   %s\n",          nsp32_model[mode_reg & (OEM0|OEM1)]);
+
+	spin_lock_irqsave(&(data->Lock), flags);
+	SPRINTF("CurrentSC:             0x%p\n\n",      data->CurrentSC);
+	spin_unlock_irqrestore(&(data->Lock), flags);
+
+	thislength = pos - (buffer + offset);
+
+	if(thislength < 0) {
+		*start = 0;
+                return 0;
+        }
+
+
+	thislength = MIN(thislength, length);
+	*start = buffer + offset;
+
+	return thislength;
+}
+#undef SPRINTF
+
+/*
+ * Note: n_io_port is defined as 0x7f because I/O register port is
+ *	 assigned as:
+ *	0x800-0x8ff: memory mapped I/O port
+ *	0x900-0xbff: (map same 0x800-0x8ff I/O port image repeatedly)
+ *	0xc00-0xfff: CardBus status registers
+ */
+static int nsp32_detect(Scsi_Host_Template *sht)
+{
+	struct Scsi_Host *host;	/* registered host structure */
+	int ret;
+	nsp32_hw_data *data;
+	int i, j;
+
+	nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
+
+	/*
+	 * register this HBA as SCSI device
+	 */
+	host = scsi_register(sht, sizeof(nsp32_hw_data));
+	if (host == NULL) {
+		nsp32_msg (KERN_ERR, "failed to scsi register");
+		goto err;
+	}
+
+	/*
+	 * set nsp32_hw_data
+	 */
+	data = (nsp32_hw_data *)host->hostdata;
+	memset(data, 0, sizeof(nsp32_hw_data));
+
+	data->IrqNumber   = nsp32_data_base.IrqNumber;
+	data->BaseAddress = nsp32_data_base.BaseAddress;
+	data->NumAddress  = nsp32_data_base.NumAddress; 
+	data->MmioAddress = nsp32_data_base.MmioAddress;
+	data->Pci         = nsp32_data_base.Pci;
+	data->pci_devid   = nsp32_data_base.pci_devid;
+
+	host->irq         = data->IrqNumber;
+	host->io_port	  = data->BaseAddress;
+	host->unique_id	  = data->BaseAddress;
+	host->n_io_port	  = data->NumAddress;
+	host->base        = data->MmioAddress;
+	scsi_set_pci_device(host, data->Pci);
+
+	data->Host        = host;
+	spin_lock_init(&(data->Lock));
+
+	data->curlunt     = NULL;
+	data->curtarget   = NULL;
+
+	/*
+	 * Bus master transfer mode is supported currently.
+	 */
+	data->trans_method	= NSP32_TRANSFER_BUSMASTER;
+
+	/*
+	 * Set clock div, CLOCK_4 (HBA has external clock, and
+	 * dividing * 100ns/4).
+	 * Currently CLOCK_4 has only tested, not for CLOCK_2/PCICLK yet.
+	 */
+	data->clock = CLOCK_4;
+
+	/*
+	 * Select appropriate nsp32_sync_table and set I_CLOCKDIV.
+	 */
+	switch (data->clock) {
+	case CLOCK_4:
+		/* If data->clock is CLOCK_4, then select 40M sync table. */
+		data->synct = nsp32_sync_table_40M;
+		data->syncnum = nsp32_table_40M_num;
+		break;
+	case CLOCK_2:
+		/* If data->clock is CLOCK_2, then select 20M sync table. */
+		data->synct = nsp32_sync_table_20M;
+		data->syncnum = nsp32_table_20M_num;
+		break;
+	case PCICLK:
+		/* If data->clock is PCICLK, then select pci sync table. */
+		data->synct = nsp32_sync_table_pci;
+		data->syncnum = nsp32_table_pci_num;
+		break;
+	default:
+		nsp32_msg(KERN_WARNING,
+			  "Invalid clock div is selected, set CLOCK_4.");
+		/* Use default value CLOCK_4 */
+		data->clock = CLOCK_4;
+		data->synct = nsp32_sync_table_40M;
+		data->syncnum = nsp32_table_40M_num;
+	}
+
+	/*
+	 * setup nsp32_lunt
+	 */
+	data->lunt_list = (struct nsp32_lunt *)
+		kmalloc(sizeof(struct nsp32_lunt) * MAX_TARGET * MAX_LUN,
+			GFP_KERNEL);
+	if (data->lunt_list == NULL) {
+		nsp32_msg(KERN_ERR, "cannot allocate LUN memory");
+		goto scsi_unregister;
+	}
+	nsp32_dbg(NSP32_DEBUG_REGISTER, "0x%x 0x%x",
+		  data->lunt_list, sizeof(struct nsp32_lunt)*MAX_TARGET*MAX_LUN);
+
+	/*
+	 * setup DMA 
+	 */
+	if (pci_set_dma_mask(data->Pci, 0xffffffffUL)) {
+		nsp32_msg (KERN_ERR, "failed to set PCI DMA mask");
+		goto kfree_lunt;
+	}
+
+	/*
+	 * allocate autoparam DMA resource.
+	 */
+	data->autoparam = pci_alloc_consistent(data->Pci, AUTOPARAM_SIZE, &data->apaddr);
+	if (data->autoparam == NULL) {
+		nsp32_msg(KERN_ERR, "failed to allocate DMA memory");
+		goto kfree_lunt;
+	}
+
+	/*
+	 * allocate scatter-gather DMA resource.
+	 */
+	data->sg_list = pci_alloc_consistent(data->Pci, 
+			(sizeof(struct nsp32_sgtable) * NSP_SG_SIZE * MAX_TARGET * MAX_LUN),
+			 &data->sgaddr);
+	if (data->sg_list == NULL) {
+		nsp32_msg(KERN_ERR, "failed to allocate DMA memory");
+		goto free_autoparam;
+	}
+
+	for (i=0; i<MAX_TARGET; i++) {
+		for (j=0; j<MAX_LUN; j++) {
+			data->lunt[i][j] = data->lunt_list + (i * MAX_LUN + j);
+		}
+	}
+
+	for (i=0; i<MAX_TARGET; i++) {
+		for (j=0; j<MAX_LUN; j++) {
+			struct nsp32_lunt *lp = data->lunt[i][j];
+			lp->sglun = (struct nsp32_sglun *)
+				(data->sg_list + (i * MAX_LUN + j));
+			lp->sglun_paddr = data->sgaddr +
+				(long)((i * MAX_LUN + j) 
+				       * sizeof(struct nsp32_sglun));
+			lp->SCpnt = NULL;
+			lp->save_datp = 0;
+			lp->msgin03 = FALSE;
+			lp->sg_num = 0;
+			lp->cur_entry = 0;
+		}
+	}
+
+	/*
+	 * setup target
+	 */
+	for (i=0; i<MAX_TARGET; i++) {
+		struct nsp32_target *target = &data->target[i];
+
+		target->limit_entry  = 0;
+		target->sync_flag    = 0;
+		nsp32_set_async(data, target);
+	}
+
+	/*
+	 * EEPROM check
+	 */
+	ret = nsp32_getprom_param(data);
+	if (ret == FALSE) {
+		data->resettime = 3;	/* default 3 */
+	}
+
+	/*
+	 * setup HBA
+	 */
+	nsp32hw_init(host);
+
+	snprintf(data->info_str, sizeof(data->info_str),
+		 "NinjaSCSI-32Bi/UDE: irq %d, io 0x%lx+0x%x",
+		 host->irq, host->io_port, host->n_io_port);
+
+	sht->name = data->info_str;
+
+	/*
+	 * SCSI bus reset
+	 *
+	 * Note: It's important to reset SCSI bus in initialization phase.
+	 *     NinjaSCSI-32Bi/UDE HBA EEPROM seems to exchange SDTR when system is
+	 *     coming up, so SCSI devices connected to HBA is set as
+	 *     un-asynchronous mode.  It brings the merit that this HBA is
+	 *     ready to start synchronous transfer without any preparation,
+	 *     but we are difficult to control transfer speed.  In addition,
+	 *     it prevents device transfer speed from effecting EEPROM start-up
+	 *     SDTR.  NinjaSCSI-32Bi/UDE has the feature if EEPROM is set as Auto
+	 *     Mode, then FAST-10M is selected when SCSI devices are connected
+	 *     same or more than 4 devices.  It should be avoided depending on
+	 *     this specification Thus, resetting the SCSI bus restores all
+	 *     connected SCSI devices to asynchronous mode, then this driver
+	 *     put SDTR safely later, and we can control all SCSI device
+	 *     transfer mode.
+	 */
+	nsp32_do_bus_reset(data);
+
+	ret = request_irq(host->irq, do_nsp32_isr, SA_SHIRQ, "nsp32", data);
+	if (ret < 0) {
+		nsp32_msg(KERN_ERR, "Unable to allocate IRQ for NSP32 "
+			  "SCSI PCI controller. Interrupt: %d\n", host->irq);
+		goto free_sg_list;
+	}
+
+        /*
+         * PCI IO register
+         */
+	if(!request_region(host->io_port, host->n_io_port, "nsp32")) {
+		nsp32_msg(KERN_ERR, 
+			  "I/O region 0x%lx+0x%lx is already used",
+			  data->BaseAddress, data->length);
+		goto free_irq;
+        }
+
+	return 1;
+
+ free_irq:
+	free_irq(host->irq, data);
+
+ free_autoparam:
+	pci_free_consistent(data->Pci, AUTOPARAM_SIZE, data->autoparam, data->apaddr);
+	
+ free_sg_list:
+	pci_free_consistent(data->Pci,
+		(sizeof(struct nsp32_sgtable) * NSP_SG_SIZE * MAX_TARGET * MAX_LUN),
+		data->sg_list, data->sgaddr);
+	
+ kfree_lunt:
+	kfree(data->lunt_list);
+
+ scsi_unregister:
+	scsi_unregister(host);
+
+ err:
+	return 0;
+}
+
+static int nsp32_release(struct Scsi_Host *shpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)shpnt->hostdata;
+
+	if (data->lunt_list) {
+		kfree(data->lunt_list);
+	}
+
+	if (data->autoparam) {
+		pci_free_consistent(data->Pci, AUTOPARAM_SIZE,
+					data->autoparam, data->apaddr);
+	}
+
+	if (data->sg_list) {
+		pci_free_consistent(data->Pci, 
+			(sizeof(struct nsp32_sgtable) * NSP_SG_SIZE * MAX_TARGET * MAX_LUN),
+			data->sg_list, data->sgaddr);
+	}
+
+	DEBUG(0, "free irq\n");
+	if (shpnt->irq) {
+		free_irq(shpnt->irq, data);
+	}
+
+	DEBUG(0, "free io\n");
+	if (shpnt->io_port && shpnt->n_io_port) {
+		release_region(shpnt->io_port, shpnt->n_io_port);
+	}
+
+	if (data->MmioAddress != 0) {
+		iounmap((void *)(data->MmioAddress));
+	}
+
+	return 0;
+}
+
+static const char *nsp32_info(struct Scsi_Host *shpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)shpnt->hostdata;
+
+	return data->info_str;
+}
+
+
+/*
+ * error handler
+ */
+static int nsp32_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+{
+	nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%p why=%d\n", SCpnt, reset_flags);
+
+	nsp32_eh_bus_reset(SCpnt);
+
+	return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+}
+
+static int nsp32_eh_abort(Scsi_Cmnd *SCpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->host->hostdata;
+	unsigned int base = data->BaseAddress;
+
+	nsp32_msg(KERN_WARNING, "abort");
+
+	if (data->curlunt->SCpnt == NULL) {
+		return (FAILED);
+	}
+
+	if (data->curtarget->sync_flag & (SDTR_INITIATOR | SDTR_TARGET)) {
+		/* reset SDTR negotiation */
+		data->curtarget->sync_flag = 0;
+	}
+
+	nsp32_write2(base, TRANSFER_CONTROL, 0);
+	nsp32_write2(base, BM_CNT, 0);
+
+	return (FAILED);
+}
+
+static int nsp32_eh_bus_reset(Scsi_Cmnd *SCpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->host->hostdata;
+	unsigned int base = data->BaseAddress;
+
+	nsp32_msg(KERN_INFO, "Bus Reset");	
+	nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%x", SCpnt);
+
+	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
+	nsp32_do_bus_reset(data);
+	nsp32_write2(base, IRQ_CONTROL, 0);
+
+	return SUCCESS;	/* SCSI bus reset is succeeded at any time. */
+}
+
+static void nsp32_do_bus_reset(nsp32_hw_data *data)
+{
+	unsigned int base = data->BaseAddress;
+	unsigned short intrdat;
+	int i;
+
+	/*
+	 * stop all transfer
+	 * clear TRANSFERCONTROL_BM_START
+	 * clear counter
+	 */
+	nsp32_write2(base, TRANSFER_CONTROL, 0);
+	nsp32_write4(base, BM_CNT,           0);
+	nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK);
+
+	/*
+	 * fall back to asynchronous transfer mode
+	 * initialize SDTR negotiation flag
+	 */
+	for (i=0; i<MAX_TARGET; i++) {
+		struct nsp32_target *target = &data->target[i];
+
+		target->sync_flag = 0;
+		nsp32_set_async(data, target);
+	}
+
+	/*
+	 * reset SCSI bus
+	 */
+	nsp32_write1(base, SCSI_BUS_CONTROL, BUSCTL_RST);
+	udelay(RESET_HOLD_TIME);
+	nsp32_write1(base, SCSI_BUS_CONTROL, 0);
+	for(i = 0; i < 5; i++) {
+		intrdat = nsp32_read2(base, IRQ_STATUS); /* dummy read */
+		nsp32_dbg(NSP32_DEBUG_BUSRESET, "irq:1: 0x%x", intrdat);
+        }
+
+	data->CurrentSC = NULL;
+}
+
+static int nsp32_eh_host_reset(Scsi_Cmnd *SCpnt)
+{
+	struct Scsi_Host *host = SCpnt->host;
+	nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata;
+	unsigned int base = data->BaseAddress;
+
+	nsp32_msg(KERN_INFO, "Host Reset");	
+	nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%x", SCpnt);
+
+	nsp32hw_init(host);
+	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
+	nsp32_do_bus_reset(data);
+	nsp32_write2(base, IRQ_CONTROL, 0);
+
+	return SUCCESS;	/* Host reset is succeeded at any time. */
+}
+
+/*
+ * PCI/Cardbus probe/remove routine
+ */
+static int __devinit nsp32_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	int ret;
+	nsp32_hw_data *data = &nsp32_data_base;
+
+	nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
+
+        ret = pci_enable_device(pdev);
+	if (ret) {
+		nsp32_msg(KERN_ERR, "failed to enable pci device");
+		return ret;
+	}
+
+	data->Pci = pdev;
+	data->pci_devid = id;
+	data->IrqNumber = pdev->irq;
+	data->BaseAddress = pci_resource_start(pdev, 0);
+	data->NumAddress = pci_resource_len(pdev, 0);
+	data->MmioAddress = (unsigned long)ioremap_nocache(
+		pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
+
+	pci_set_master(pdev);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2))
+	scsi_register_host(&driver_template);
+#else
+	scsi_register_module(MODULE_SCSI_HA, &driver_template);
+#endif
+
+	nsp32_msg(KERN_INFO, "nsp32 irq: %i mmio: 0x%lx slot: %s model: %s",
+		  pdev->irq, data->MmioAddress, pdev->slot_name,
+		  nsp32_model[id->driver_data]);
+
+	nsp32_dbg(NSP32_DEBUG_REGISTER, "exit");
+
+	return 0;
+}
+
+static void __devexit nsp32_remove(struct pci_dev *pdev)
+{
+	nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
+	
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2))
+	scsi_unregister_host(&driver_template);
+#else
+	scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+#endif
+}
+
+static struct pci_device_id nsp32_pci_table[] __devinitdata = {
+	{
+		vendor:      PCI_VENDOR_ID_IODATA,
+		device:      PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_IODATA,
+	},
+	{
+		vendor:      PCI_VENDOR_ID_WORKBIT,
+		device:      PCI_DEVICE_ID_NINJASCSI_32BI_KME,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_KME,
+	},
+	{
+		vendor:      PCI_VENDOR_ID_WORKBIT,
+		device:      PCI_DEVICE_ID_NINJASCSI_32BI_WBT,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_WORKBIT,
+	},
+	{
+		vendor:      PCI_VENDOR_ID_WORKBIT,
+		device:      PCI_DEVICE_ID_WORKBIT_STANDARD,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_PCI_WORKBIT,
+	},
+	{
+		vendor:      PCI_VENDOR_ID_WORKBIT,
+		device:      PCI_DEVICE_ID_NINJASCSI_32BI_LOGITEC,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_EXT_ROM,
+	},
+	{
+		vendor:      PCI_VENDOR_ID_WORKBIT,
+		device:      PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_PCI_LOGITEC,
+	},
+	{
+		vendor:      PCI_VENDOR_ID_WORKBIT,
+		device:      PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_PCI_MELCO,
+	},
+	{0,0,},
+};
+MODULE_DEVICE_TABLE(pci, nsp32_pci_table);
+
+static struct pci_driver nsp32_driver = {
+	.name =		"nsp32",
+	.id_table =	nsp32_pci_table,
+	.probe =	nsp32_probe,
+	.remove =	nsp32_remove,
+#ifdef CONFIG_PM
+/*	.suspend =	nsp32_suspend,*/
+/*	.resume =	nsp32_resume,*/
+#endif
+};
+
+static int __init init_nsp32(void) {
+	return pci_module_init(&nsp32_driver);
+}
+
+static void __exit exit_nsp32(void) {
+	pci_unregister_driver(&nsp32_driver);
+}
+
+module_init(init_nsp32);
+module_exit(exit_nsp32);
+
+
+/*
+ * Reset parameters and call scsi_done for data->curlunt.
+ * Be careful setting SCpnt->result = DID_* before calling this function.
+ */
+static void nsp32_scsi_done(nsp32_hw_data *data, Scsi_Cmnd *SCpnt)
+{
+	unsigned int base = data->BaseAddress;
+
+	/*
+	 * unmap pci
+	 */
+	if (SCpnt->request_bufflen == 0) {
+		goto skip;
+	}
+
+	if (SCpnt->use_sg) {
+		pci_unmap_sg(data->Pci,
+			(struct scatterlist *)SCpnt->buffer,
+			SCpnt->use_sg,
+			scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+	} else {
+		pci_unmap_single(data->Pci,
+			(u32)SCpnt->SCp.have_data_in,
+			SCpnt->request_bufflen,
+			scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+	}
+
+ skip:
+	/*
+	 * clear TRANSFERCONTROL_BM_START
+	 */
+	nsp32_write2(base, TRANSFER_CONTROL, 0);
+	nsp32_write4(base, BM_CNT, 0);
+
+	/*
+	 * call scsi_done
+	 */
+	(*SCpnt->scsi_done)(SCpnt);
+
+	/*
+	 * reset parameters
+	 */
+	data->curlunt->SCpnt = NULL;
+	data->curlunt = NULL;
+	data->curtarget = NULL;
+	data->CurrentSC = NULL;
+}
+
+
+/*
+ * Bus Free Occur
+ *
+ * Current Phase is BUSFREE. AutoSCSI is automatically execute BUSFREE phase
+ * with ACK reply when below condition is matched:
+ *	MsgIn 00: Command Complete.
+ *	MsgIn 02: Save Data Pointer.
+ *	MsgIn 04: Diconnect.
+ * In other case, unexpected BUSFREE is detected.
+ */
+static int nsp32_busfree_occur(nsp32_hw_data *data, unsigned short execph)
+{
+	Scsi_Cmnd *SCpnt = data->curlunt->SCpnt;
+	unsigned int base = data->BaseAddress;
+
+	nsp32_dbg(NSP32_DEBUG_BUSFREE, "enter");
+
+	nsp32_write4(base, BM_CNT, 0);
+	nsp32_write2(base, TRANSFER_CONTROL, 0);
+
+	/*
+	 * MsgIn 02: Save Data Pointer
+	 *
+	 * VALID:
+	 *   Save Data Pointer is received. Adjust pointer.
+	 *   
+	 * NO-VALID:
+	 *   SCSI-3 says if Save Data Pointer is not received, then we restart
+	 *   processing and we can't adjust any SCSI data pointer in next data
+	 *   phase.
+	 */
+	if (execph & MSGIN_02_VALID) {
+		nsp32_dbg(NSP32_DEBUG_BUSFREE, "MsgIn02_Valid");
+
+		/*
+		 * Check sack_cnt/saved_sack_cnt, then adjust sg table if
+		 * needed.
+		 */
+		if (!(execph & MSGIN_00_VALID) && 
+		    ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE))) {
+			unsigned int sacklen, s_sacklen;
+
+			/*
+			 * Read SACK count and SAVEDSACK count, then compare.
+			 */
+			sacklen   = nsp32_read4(base, SACK_CNT);
+			s_sacklen = nsp32_read4(base, SAVED_SACK_CNT);
+
+			/*
+			 * If SAVEDSACKCNT == 0, it means SavedDataPointer is
+			 * come after data transfering.
+			 */
+			if (s_sacklen > 0) {
+				/*
+				 * Comparing between sack and savedsack to
+				 * check the condition of AutoMsgIn03.
+				 *
+				 * If they are same, set msgin03 == TRUE,
+				 * COMMANDCONTROL_AUTO_MSGIN_03 is enabled at
+				 * reselection.  On the other hand, if they
+				 * aren't same, set msgin03 == FALSE, and
+				 * COMMANDCONTROL_AUTO_MSGIN_03 is disabled at
+				 * reselection.
+				 */
+				if (sacklen != s_sacklen) {
+					data->curlunt->msgin03 = FALSE;
+				} else {
+					data->curlunt->msgin03 = TRUE;
+				}
+
+				nsp32_adjust_busfree(data, s_sacklen);
+			}
+		}
+
+		/* This value has not substitude with valid value yet... */
+		//data->curlunt->save_datp = data->cur_datp;
+	} else {
+		/*
+		 * no processing.
+		 */
+	}
+	
+	if (execph & MSGIN_03_VALID) {
+		/* MsgIn03 was valid to be processed. No need processing. */
+	}
+
+	/*
+	 * target SDTR check
+	 */
+	if (data->curtarget->sync_flag & SDTR_INITIATOR) {
+		/*
+		 * SDTR negotiation pulled by the initiator has not
+		 * finished yet. Fall back to ASYNC mode.
+		 */
+		nsp32_set_async(data, data->curtarget);
+		data->curtarget->sync_flag &= ~SDTR_INITIATOR;
+		data->curtarget->sync_flag |= SDTR_DONE;
+	} else if (data->curtarget->sync_flag & SDTR_TARGET) {
+		/*
+		 * SDTR negotiation pulled by the target has been
+		 * negotiating.
+		 */
+		if (execph & (MSGIN_00_VALID | MSGIN_04_VALID)) {
+			/* 
+			 * If valid message is received, then
+			 * negotiation is succeeded.
+			 */
+		} else {
+			/*
+			 * On the contrary, if unexpected bus free is
+			 * occured, then negotiation is failed. Fall
+			 * back to ASYNC mode.
+			 */
+			nsp32_set_async(data, data->curtarget);
+		}
+		data->curtarget->sync_flag &= ~SDTR_TARGET;
+		data->curtarget->sync_flag |= SDTR_DONE;
+	}
+	
+	/*
+	 * It is always ensured by SCSI standard that initiator
+	 * switches into Bus Free Phase after
+	 * receiving message 00 (Command Complete), 04 (Disconnect).
+	 * It's the reason that processing here is valid.
+	 */
+	if (execph & MSGIN_00_VALID) {
+		/* MsgIn 00: Command Complete */
+		nsp32_dbg(NSP32_DEBUG_BUSFREE, "command complete");
+
+		SCpnt->SCp.Status  = nsp32_read1(base, SCSI_CSB_IN);
+		SCpnt->SCp.Message = 0;
+		nsp32_dbg(NSP32_DEBUG_BUSFREE, 
+			  "normal end stat=0x%x resid=0x%x\n",
+			  SCpnt->SCp.Status, SCpnt->resid);
+		SCpnt->result = 
+			(DID_OK << 16) | (SCpnt->SCp.Message << 8) | (SCpnt->SCp.Status << 0);
+		nsp32_scsi_done(data, SCpnt);
+		/* All operation is done */
+		return (TRUE);
+	} else if (execph & MSGIN_04_VALID) {
+		/* MsgIn 04: Disconnect */
+		SCpnt->SCp.Status  = nsp32_read1(base, SCSI_CSB_IN);
+		SCpnt->SCp.Message = 4;
+		
+		nsp32_dbg(NSP32_DEBUG_BUSFREE, "disconnect");
+		return (TRUE);
+	} else {
+		/* Unexpected bus free */
+		nsp32_msg(KERN_WARNING, "unexpected bus free occured");
+
+		/* DID_ERROR? */
+		//SCpnt->result   = (DID_OK << 16) | (SCpnt->SCp.Message << 8) | (SCpnt->SCp.Status << 0);
+		SCpnt->result = DID_ERROR << 16;
+		nsp32_scsi_done(data, SCpnt);
+		return (TRUE);
+	}
+	return (FALSE);
+}
+
+
+/*
+ * nsp32_adjust_busfree - adjusting SG table
+ *
+ * Note: This driver adjust the SG table using SCSI ACK
+ *       counter instead of BMCNT counter!
+ */
+static void nsp32_adjust_busfree(nsp32_hw_data *data, unsigned int s_sacklen)
+{
+	int old_entry = data->cur_entry;
+	int new_entry;
+	struct nsp32_sgtable *sgt = data->curlunt->sglun->sgt;
+	unsigned int restlen, sentlen;
+	int sg_num = data->curlunt->sg_num;
+
+	/* adjust saved SACK count with 4 byte start address boundary */
+	s_sacklen -= sgt[old_entry].addr & 3;
+
+	/*
+	 * calculate new_entry from sack count and each sgt[].len 
+	 * calculate the byte which is intent to send
+	 */
+	sentlen = 0;
+	for (new_entry = old_entry; new_entry < sg_num; new_entry++) {
+		sentlen += (sgt[new_entry].len & ~NSP32_SG_END_SGT);
+		if (sentlen > s_sacklen) {
+			break;
+		}
+	}
+
+	/* all sgt is processed */
+	if (new_entry == sg_num) {
+		goto last;
+	}
+
+	if (sentlen == s_sacklen) {
+		/* XXX: confirm it's ok or not */
+		/* In this case, it's ok because we are at 
+		   the head element of the sg. restlen is correctly calculated. */
+	}
+
+	/* calculate the rest length for transfering */
+	restlen = sentlen - s_sacklen;
+	
+	/* update adjusting current SG table entry */
+	sgt[new_entry].addr += (sgt[new_entry].len - restlen);
+	sgt[new_entry].len = restlen;
+
+	/* set cur_entry with new_entry */
+	data->cur_entry = new_entry;
+	
+	return;
+
+ last:
+	/* update hostdata and lun */
+
+	return;
+}
+
+
+/*
+ * It's called MsgOut phase occur.
+ * NinjaSCSI-32Bi/UDE automatically processes up to 3 messages in
+ * message out phase. It, however, has more than 3 messages,
+ * HBA creates the interrupt and we have to process by hand.
+ */
+static void nsp32_msgout_occur(nsp32_hw_data *data)
+{
+	unsigned int base = data->BaseAddress;
+	//unsigned short command;
+	long new_sgtp;
+	int i;
+	
+	nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR,
+		  "enter: msgoutlen: 0x%x", data->msgoutlen);
+
+	/*
+	 * If MsgOut phase is occured without having any
+	 * message, then No_Operation is sent (SCSI-2).
+	 */
+	if (data->msgoutlen == 0) {
+		nsp32_build_nop(data);
+	}
+
+	/*
+	 * Set SGTP ADDR current entry for restarting AUTOSCSI, 
+	 * because SGTP is incremented next point.
+	 * There is few statement in the specification...
+	 */
+ 	new_sgtp = data->curlunt->sglun_paddr
+		+ data->curlunt->cur_entry * sizeof(struct nsp32_sgtable);
+
+	/*
+	 * send messages
+	 */
+	for (i=0; i<data->msgoutlen; i++) {
+		nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR,
+			  "%d : 0x%x", i, data->msgoutbuf[i]);
+
+		/*
+		 * Check REQ is asserted.
+		 */
+		nsp32_wait_req(data, ASSERT);
+
+		if (i == (data->msgoutlen - 1)) {
+			/*
+			 * If the last message, set the AutoSCSI restart
+			 * before send back the ack message. AutoSCSI
+			 * restart automatically negate ATN signal.
+			 */
+			//command = (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02);
+			//nsp32_restart_autoscsi(data, command);
+			nsp32_write2(base, COMMAND_CONTROL,
+					 (CLEAR_CDB_FIFO_POINTER |
+					  AUTO_COMMAND_PHASE |
+					  AUTOSCSI_RESTART |
+					  AUTO_MSGIN_00_OR_04 |
+					  AUTO_MSGIN_02 ));
+		}
+		/*
+		 * Write data with SACK, then wait sack is
+		 * automatically negated.
+		 */
+		nsp32_write1(base, SCSI_DATA_WITH_ACK, data->msgoutbuf[i]);
+		nsp32_wait_sack(data, NEGATE);
+
+		nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "bus: 0x%x\n",
+			  nsp32_read1(base, SCSI_BUS_MONITOR));
+	};
+
+	data->msgoutlen = 0;
+
+	nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "exit");
+}
+
+/*
+ * Restart AutoSCSI
+ *
+ * Note: Restarting AutoSCSI needs set:
+ *		SYNC_REG, ACK_WIDTH, SGT_ADR, TRANSFER_CONTROL
+ */
+static void nsp32_restart_autoscsi(nsp32_hw_data *data, unsigned short command)
+{
+	unsigned int base = data->BaseAddress;
+	unsigned short transfer = 0;
+	Scsi_Cmnd *SCpnt = data->curlunt->SCpnt;
+
+	nsp32_dbg(NSP32_DEBUG_RESTART, "enter");
+
+	if (data->curtarget == NULL || data->curlunt == NULL) {
+		nsp32_msg(KERN_ERR, "Target or Lun is invalid");
+	}
+
+	/*
+	 * set SYNC_REG
+	 * Don't set BM_START_ADR before setting this register.
+	 */
+	nsp32_write1(base, SYNC_REG, data->curtarget->syncreg);
+
+	/*
+	 * set ACKWIDTH
+	 */
+	nsp32_write1(base, ACK_WIDTH, data->curtarget->ackwidth);
+
+	/*
+	 * set SGT ADDR (physical address)
+	 */
+	nsp32_write4(base, SGT_ADR, data->curlunt->sglun_paddr);
+
+	/*
+	 * set TRANSFER CONTROL REG
+	 */
+	transfer = 0;
+	transfer |= (TRANSFER_GO | ALL_COUNTER_CLR);
+	if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
+		if (SCpnt->request_bufflen > 0) {
+			transfer |= BM_START;
+		}
+	} else if (data->trans_method & NSP32_TRANSFER_MMIO) {
+		transfer |= CB_MMIO_MODE;
+	} else if (data->trans_method & NSP32_TRANSFER_PIO) {
+		transfer |= CB_IO_MODE;
+	}
+	nsp32_write2(base, TRANSFER_CONTROL, transfer);
+
+	/*
+	 * restart AutoSCSI
+	 *
+	 * TODO: COMMANDCONTROL_AUTO_COMMAND_PHASE is needed ?
+	 */
+	command |= (CLEAR_CDB_FIFO_POINTER |
+		    AUTO_COMMAND_PHASE |
+		    AUTOSCSI_RESTART);
+	nsp32_write2(base, COMMAND_CONTROL, command);
+
+	nsp32_dbg(NSP32_DEBUG_RESTART, "exit");
+}
+
+
+/*
+ * cannot run automatically message in occur
+ */
+static void nsp32_msgin_occur(nsp32_hw_data *data, unsigned long irq_status,
+			unsigned short execph)
+{
+	unsigned int base = data->BaseAddress;
+	unsigned char msg;
+	unsigned char msgtype;
+	unsigned char newlun;
+	unsigned short command = 0;
+	int msgclear = TRUE;
+	long new_sgtp;
+	int ret;
+
+	/*
+	 * read first message
+	 *    Use SCSIDATA_W_ACK instead of SCSIDATAIN, because the procedure
+	 *    of Message-In have to be processed before sending back SCSI ACK.
+	 */
+	msg = nsp32_read1(base, SCSI_DATA_IN);
+	data->msginbuf[(unsigned char)data->msginlen] = msg;
+	msgtype = data->msginbuf[0];
+	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR,
+		  "enter: msglen: 0x%x msgin: 0x%x msgtype: 0x%x",
+		  data->msginlen, msg, msgtype);
+
+	/*
+	 * TODO: We need checking whether bus phase is message in?
+	 */
+
+	/*
+	 * assert SCSI ACK
+	 */
+	nsp32_sack_assert(data);
+
+	/*
+	 * processing IDENTIFY
+	 */
+	if (msgtype & 0x80) {
+		if (!(irq_status & IRQSTATUS_RESELECT_OCCUER)) {
+			/* Invalid (non reselect) phase */
+			goto reject;
+		}
+
+		newlun = msgtype & 0x1f; /* TODO: SPI-3 compliant? */
+		ret = nsp32_reselection(data, newlun);
+		if (ret == TRUE) {
+			goto restart;
+		} else {
+			goto reject;
+		}
+	}
+	
+	/*
+	 * processing messages except for IDENTIFY
+	 *
+	 * TODO: Messages are all SCSI-2 terminology. SCSI-3 compliance is TODO.
+	 */
+	switch (msgtype) {
+	/*
+	 * 1-byte message
+	 */
+	case COMMAND_COMPLETE:
+	case DISCONNECT:
+		/*
+		 * These messages should not be occured.
+		 * They should be processed on AutoSCSI sequencer.
+		 */
+		nsp32_msg(KERN_WARNING, 
+			   "unexpected message of AutoSCSI MsgIn: 0x%x", msg);
+		break;
+		
+	case RESTORE_POINTERS:
+		/*
+		 * AutoMsgIn03 is disabled, and HBA gets this message.
+		 */
+
+		if ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE)) {
+			unsigned int s_sacklen;
+
+			s_sacklen = nsp32_read4(base, SAVED_SACK_CNT);
+			if ((execph & MSGIN_02_VALID) && (s_sacklen > 0)) {
+				nsp32_adjust_busfree(data, s_sacklen);
+			} else {
+				/* No need to rewrite SGT */
+			}
+		}
+		data->curlunt->msgin03 = FALSE;
+
+		/* Update with the new value */
+
+		/* reset SACK/SavedACK counter (or ALL clear?) */
+		nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK);
+
+		/*
+		 * set new sg pointer
+		 */
+		new_sgtp = data->curlunt->sglun_paddr + 
+			data->curlunt->cur_entry * sizeof(struct nsp32_sgtable);
+		nsp32_write4(base, SGT_ADR, new_sgtp);
+
+		break;
+
+	case SAVE_POINTERS:
+		/*
+		 * These messages should not be occured.
+		 * They should be processed on AutoSCSI sequencer.
+		 */
+		nsp32_msg (KERN_WARNING, 
+			   "unexpected message of AutoSCSI MsgIn: SAVE_POINTERS");
+		
+		break;
+		
+	case MESSAGE_REJECT:
+		/* If previous message_out is sending SDTR, and get 
+		   message_reject from target, SDTR negotiation is failed */
+		if (data->curtarget->sync_flag &
+				(SDTR_INITIATOR | SDTR_TARGET)) {
+			/*
+			 * Current target is negotiating SDTR, but it's
+			 * failed.  Fall back to async transfer mode, and set
+			 * SDTR_DONE.
+			 */
+			nsp32_set_async(data, data->curtarget);
+			data->curtarget->sync_flag &= ~SDTR_INITIATOR;
+			data->curtarget->sync_flag |= SDTR_DONE;
+
+		}
+		break;
+
+	case LINKED_CMD_COMPLETE:
+	case LINKED_FLG_CMD_COMPLETE:
+		/* queue tag is not supported currently */
+		nsp32_msg (KERN_WARNING, 
+			   "unsupported message: 0x%x", msgtype);
+		break;
+
+	case INITIATE_RECOVERY:
+		/* staring ECA (Extended Contingent Allegiance) state. */
+		/* This message is declined in SPI2 or later. */
+
+		goto reject;
+
+	/*
+	 * 2-byte message
+	 */
+	case SIMPLE_QUEUE_TAG:
+	case 0x23:
+		/*
+		 * 0x23: Ignore_Wide_Residue is not declared in scsi.h.
+		 * No support is needed.
+		 */
+		if (data->msginlen >= 1) {
+			goto reject;
+		}
+
+		/* current position is 1-byte of 2 byte */
+		msgclear = FALSE;
+
+		break;
+
+	/*
+	 * extended message
+	 */
+	case EXTENDED_MESSAGE:
+		if (data->msginlen < 1) {
+			/*
+			 * Current position does not reach 2-byte
+			 * (2-byte is extended message length).
+			 */
+			msgclear = FALSE;
+			break;
+		}
+
+		if ((data->msginbuf[1] + 1) > data->msginlen) {
+			/*
+			 * Current extended message has msginbuf[1] + 2
+			 * (msginlen starts counting from 0, so buf[1] + 1).
+			 * If current message position is not finished,
+			 * continue receiving message.
+			 */
+			msgclear = FALSE;
+			break;
+		}
+
+		/*
+		 * Reach here means regular length of each type of 
+		 * extended messages.
+		 */
+		switch (data->msginbuf[2]) {
+		case EXTENDED_MODIFY_DATA_POINTER:
+			/* TODO */
+			goto reject; /* not implemented yet */
+			break;
+
+		case EXTENDED_SDTR:
+			/*
+			 * Exchange this message between initiator and target.
+			 */
+			if (data->msginlen != EXTENDED_SDTR_LEN + 1) {
+				/*
+				 * received inappropriate message.
+				 */
+				goto reject;
+				break;
+			}
+
+			nsp32_analyze_sdtr(data);
+
+			break;
+
+		case EXTENDED_EXTENDED_IDENTIFY:
+			/* SCSI-I only, not supported. */
+			goto reject; /* not implemented yet */
+
+			break;
+
+		case EXTENDED_WDTR:
+			goto reject; /* not implemented yet */
+
+			break;
+			
+		default:
+			goto reject;
+		}
+		break;
+		
+	default:
+		goto reject;
+	}
+
+ restart:
+	if (msgclear == TRUE) {
+		data->msginlen = 0;
+
+		/*
+		 * If restarting AutoSCSI, but there are some message to out
+		 * (msgoutlen > 0), set AutoATN, and set SCSIMSGOUT as 0
+		 * (MV_VALID = 0). When commandcontrol is written with
+		 * AutoSCSI restart, at the same time MsgOutOccur should be
+		 * happened (however, such situation is really possible...?).
+		 */
+		if (data->msgoutlen > 0) {	
+			nsp32_write4(base, SCSI_MSG_OUT, 0);
+			command |= AUTO_ATN;
+		}
+
+		/*
+		 * restart AutoSCSI
+		 * If it's failed, COMMANDCONTROL_AUTO_COMMAND_PHASE is needed.
+		 */
+		command |= (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02);
+
+		/*
+		 * If current msgin03 is TRUE, then flag on.
+		 */
+		if (data->curlunt->msgin03 == TRUE) {
+			command |= AUTO_MSGIN_03;
+		}
+		data->curlunt->msgin03 = FALSE;
+	} else {
+		data->msginlen++;
+	}
+
+	/*
+	 * restart AutoSCSI
+	 */
+	nsp32_restart_autoscsi(data, command);
+
+	/*
+	 * wait SCSI REQ negate for REQ-ACK handshake
+	 */
+	nsp32_wait_req(data, NEGATE);
+
+	/*
+	 * negate SCSI ACK
+	 */
+	nsp32_sack_negate(data);
+
+	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit");
+
+	return;
+
+ reject:
+	nsp32_msg(KERN_WARNING, 
+		  "invalid or unsupported MessageIn, rejected. "
+		  "current msg: 0x%x (len: 0x%x), processing msg: 0x%x",
+		  msg, data->msginlen, msgtype);
+	nsp32_build_reject(data);
+	data->msginlen = 0;
+
+	goto restart;
+}
+
+/*
+ * 
+ */
+static void nsp32_analyze_sdtr(nsp32_hw_data *data)
+{
+	struct nsp32_target *target = data->curtarget;
+	struct nsp32_sync_table *synct;
+	unsigned char get_period = data->msginbuf[3];
+	unsigned char get_offset = data->msginbuf[4];
+	int entry;
+	int syncnum;
+
+	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "enter");
+
+	synct = data->synct;
+	syncnum = data->syncnum;
+
+	/*
+	 * If this inititor sent the SDTR message, then target responds SDTR,
+	 * initiator SYNCREG, ACKWIDTH from SDTR parameter.
+	 * Messages are not appropriate, then send back reject message.
+	 * If initiator did not send the SDTR, but target sends SDTR, 
+	 * initiator calculator the appropriate parameter and send back SDTR.
+	 */	
+	if (target->sync_flag & SDTR_INITIATOR) {
+		/*
+		 * Initiator sent SDTR, the target responds and
+		 * send back negotiation SDTR.
+		 */
+		nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target responds SDTR");
+	
+		target->sync_flag &= ~SDTR_INITIATOR;
+		target->sync_flag |= SDTR_DONE;
+
+		/*
+		 * offset:
+		 */
+		if (get_offset > SYNC_OFFSET) {
+			/*
+			 * Negotiation is failed, the target send back
+			 * unexpected offset value.
+			 */
+			goto reject;
+		}
+		
+		if (get_offset == ASYNC_OFFSET) {
+			/*
+			 * Negotiation is succeeded, the target want
+			 * to fall back into asynchronous transfer mode.
+			 */
+			goto async;
+		}
+
+		/*
+		 * period:
+		 *    Check whether sync period is too short. If too short,
+		 *    fall back to async mode. If it's ok, then investigate
+		 *    the received sync period. If sync period is acceptable
+		 *    between sync table start_period and end_period, then
+		 *    set this I_T nexus as sent offset and period.
+		 *    If it's not acceptable, send back reject and fall back
+		 *    to async mode.
+		 */
+		if (get_period < data->synct[0].period_num) {
+			/*
+			 * Negotiation is failed, the target send back
+			 * unexpected period value.
+			 */
+			goto reject;
+		}
+
+		entry = nsp32_search_period_entry(data, target, get_period);
+
+		if (entry < 0) {
+			/*
+			 * Target want to use long period which is not 
+			 * acceptable NinjaSCSI-32Bi/UDE.
+			 */
+			goto reject;
+		}
+
+		/*
+		 * Set new sync table and offset in this I_T nexus.
+		 */
+		nsp32_set_sync_entry(data, target, entry, get_offset);
+	} else {
+		/* Target send SDTR to initiator. */
+		nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target send SDTR");
+	
+		target->sync_flag |= SDTR_INITIATOR;
+
+		/* offset: */
+		if (get_offset > SYNC_OFFSET) {
+			/* send back as SYNC_OFFSET */
+			get_offset = SYNC_OFFSET;
+		}
+
+		/* period: */
+		if (get_period < data->synct[0].period_num) {
+			get_period = data->synct[0].period_num;
+		}
+
+		entry = nsp32_search_period_entry(data, target, get_period);
+
+		if (get_offset == ASYNC_OFFSET || entry < 0) {
+			nsp32_set_async(data, target);
+			nsp32_build_sdtr(data, 0, ASYNC_OFFSET);
+		} else {
+			nsp32_set_sync_entry(data, target, entry, get_offset);
+			nsp32_build_sdtr(data, get_period, get_offset);
+		}
+	}
+	
+	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit");
+	return;
+
+ reject:
+	/*
+	 * If the current message is unacceptable, send back to the target
+	 * with reject message.
+	 */
+	nsp32_build_reject(data);
+
+ async:
+	nsp32_set_async(data, target);	/* set as ASYNC transfer mode */
+
+	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit: set async");
+	return;
+}
+
+
+/*
+ * Search config entry number matched in sync_table from given
+ * target and speed period value. If failed to search, return negative value.
+ */
+static int nsp32_search_period_entry(nsp32_hw_data *data,
+			      struct nsp32_target *target,
+			      unsigned char period)
+{
+	int i;
+
+	if (target->limit_entry >= data->syncnum) {
+		nsp32_msg(KERN_ERR, "limit_entry exceeds syncnum!");
+		target->limit_entry = 0;
+	}
+
+	for (i=target->limit_entry; i<data->syncnum; i++) {
+		if (period >= data->synct[i].start_period &&
+		    period <= data->synct[i].end_period) {
+				break;
+		}
+	}
+
+	/*
+	 * Check given period value is over the sync_table value.
+	 * If so, return max value.
+	 */
+	if (i == data->syncnum) {
+		i = -1;
+	}
+
+	return i;
+}
+
+
+/*
+ * target <-> initiator use ASYNC transfer
+ */
+static void nsp32_set_async(nsp32_hw_data *data, struct nsp32_target *target)
+{
+	unsigned char period = data->synct[target->limit_entry].period_num;
+
+	target->offset   = ASYNC_OFFSET;
+	target->syncreg  = TO_SYNCREG(period, ASYNC_OFFSET);
+	target->ackwidth = 0;
+
+	nsp32_dbg(NSP32_DEBUG_SYNC, "set async");
+}
+
+
+/*
+ * target <-> initiator use maximum SYNC transfer
+ */
+static void nsp32_set_max_sync(nsp32_hw_data *data,
+			       struct nsp32_target *target,
+			       unsigned char *period, unsigned char *offset)
+{
+	unsigned char period_num, ackwidth;
+
+	period_num = data->synct[target->limit_entry].period_num;
+	*period    = data->synct[target->limit_entry].start_period;
+	ackwidth   = data->synct[target->limit_entry].ackwidth;
+	*offset    = SYNC_OFFSET;
+
+	target->syncreg  = TO_SYNCREG(period_num, *offset);
+	target->ackwidth = ackwidth;
+	target->offset   = *offset;
+}
+
+
+/*
+ * target <-> initiator use entry number speed
+ */
+static void nsp32_set_sync_entry(nsp32_hw_data *data,
+				 struct nsp32_target *target,
+				 int entry, unsigned char offset)
+{
+	unsigned char period, ackwidth;
+
+	period   = data->synct[entry].period_num;
+	ackwidth = data->synct[entry].ackwidth;
+	offset  = offset;
+
+	target->syncreg  = TO_SYNCREG(period, offset);
+	target->ackwidth = ackwidth;
+	target->offset   = offset;
+
+	nsp32_dbg(NSP32_DEBUG_SYNC, "set sync");
+}
+
+
+/*
+ * It waits until SCSI REQ becomes assertion or negation state.
+ *
+ * Note: If nsp32_msgin_occur is called, we asserts SCSI ACK. Then
+ *     connected target responds SCSI REQ negation.  We have to wait
+ *     SCSI REQ becomes negation in order to negate SCSI ACK signal for
+ *     REQ-ACK handshake.
+ */
+static void nsp32_wait_req(nsp32_hw_data *data, int state)
+{
+	unsigned int base = data->BaseAddress;
+	int wait_time = 0;
+	unsigned char bus;
+
+	if (!((state == ASSERT) || (state == NEGATE))) {
+		nsp32_msg(KERN_ERR, "unknown state designation");
+	}
+	state <<= 5; /* REQ is BIT(5) */
+
+	do {
+		bus = nsp32_read1(base, SCSI_BUS_MONITOR);
+		if ((bus & BUSMON_REQ) == state) {
+			nsp32_dbg(NSP32_DEBUG_WAIT, 
+				  "wait_time: %d", wait_time);
+			return;
+		}
+		udelay(1);
+		wait_time++;
+	} while (wait_time < REQSACK_TIMEOUT_TIME);
+
+	nsp32_msg(KERN_WARNING, "wait REQ timeout, state: %d", state);
+}
+
+/*
+ * It waits until SCSI SACK becomes assertion or negation state.
+ */
+static void nsp32_wait_sack(nsp32_hw_data *data, int state)
+{
+	unsigned int base = data->BaseAddress;
+	int wait_time = 0;
+	unsigned char bus;
+
+	if (!((state == ASSERT) || (state == NEGATE))) {
+		nsp32_msg(KERN_ERR, "unknown state designation");
+	}
+	state <<= 4; /* ACK is BIT(4) */
+
+	do {
+		bus = nsp32_read1(base, SCSI_BUS_MONITOR);
+		if ((bus & BUSMON_ACK) == state) {
+			nsp32_dbg(NSP32_DEBUG_WAIT,
+				  "wait_time: %d", wait_time);
+			return;
+		}
+		udelay(1);
+		wait_time++;
+	} while (wait_time < REQSACK_TIMEOUT_TIME);
+
+	nsp32_msg(KERN_WARNING, "wait SACK timeout, state: %d", state);
+}
+
+/*
+ * assert SCSI ACK
+ *
+ * Note: SCSI ACK assertion needs with ACKENB=1, AUTODIRECTION=1.
+ */
+static void nsp32_sack_assert(nsp32_hw_data *data)
+{
+	unsigned char busctrl;
+	unsigned int base = data->BaseAddress;
+
+	busctrl  = nsp32_read1(base, SCSI_BUS_CONTROL);
+	busctrl	|= (BUSCTL_ACK | AUTODIRECTION | ACKENB);
+	nsp32_write1(base, SCSI_BUS_CONTROL,busctrl);
+}
+
+/*
+ * negate SCSI ACK
+ */
+static void nsp32_sack_negate(nsp32_hw_data *data)
+{
+	unsigned char busctrl;
+	unsigned int base = data->BaseAddress;
+
+	busctrl  = nsp32_read1(base, SCSI_BUS_CONTROL);
+	busctrl	&= ~BUSCTL_ACK;
+	nsp32_write1(base, SCSI_BUS_CONTROL, busctrl);
+}
+
+
+
+/*
+ * getting EEPROM parameter
+ */
+static int nsp32_getprom_param(nsp32_hw_data *data)
+{
+	int vendor = data->pci_devid->vendor;
+	int device = data->pci_devid->device;
+	int ret, val, i;
+
+	/*
+	 * EEPROM checking.
+	 */
+	ret = nsp32_prom_read(data, 0x7e);
+	if (ret != 0x55) {
+		nsp32_msg(KERN_INFO, "No EEPROM detected: 0x%x", ret);
+		return (FALSE);
+	}
+	ret = nsp32_prom_read(data, 0x7f);
+	if (ret != 0xaa) {
+		nsp32_msg(KERN_INFO, "Invalid number: 0x%x", ret);
+		return (FALSE);
+	}
+
+	/*
+	 * check EEPROM type
+	 */
+	if (vendor == PCI_VENDOR_ID_WORKBIT &&
+	    device == PCI_DEVICE_ID_WORKBIT_STANDARD) {
+		ret = nsp32_getprom_standard(data);
+	} else if (vendor == PCI_VENDOR_ID_WORKBIT &&
+		   device == PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC) {
+		ret = nsp32_getprom_new(data);
+	} else if (vendor == PCI_VENDOR_ID_WORKBIT &&
+		   device == PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO ) {
+		ret = nsp32_getprom_new(data);
+	} else {
+		nsp32_msg(KERN_WARNING, "Unknown EEPROM");
+		ret = FALSE;
+	}
+
+	/* for debug : SPROM data full checking */
+	for (i=0; i<=0x1f; i++) {
+		val = nsp32_prom_read(data, i);
+		nsp32_dbg(NSP32_DEBUG_EEPROM,
+			  "rom address 0x%x : 0x%x", i, val);
+	}
+
+	return (ret);
+}
+
+
+/*
+ * AT24C01A (Logitec: LHA-600S), AT24C02 (Melco Buffalo: IFC-USLP) data map:
+ *
+ *   ROMADDR
+ *   0x00 - 0x06 :  Device Synchronous Transfer Period (SCSI ID 0 - 6) 
+ *			Value 0x0: ASYNC, 0x0c: Ultra-20M, 0x19: Fast-10M
+ *   0x07        :  HBA Synchronous Transfer Period
+ *			Value 0: AutoSync, 1: Manual Setting
+ *   0x08 - 0x0f :  Not Used? (0x0)
+ *   0x10        :  Bus Termination
+ * 			Value 0: Auto[ON], 1: ON, 2: OFF
+ *   0x11        :  Not Used? (0)
+ *   0x12        :  Bus Reset Delay Time (0x03)
+ *   0x13        :  Bootable CD Support
+ *			Value 0: Disable, 1: Enable
+ *   0x14        :  Device Scan
+ *			Bit   7  6  5  4  3  2  1  0
+ *			      |  <----------------->
+ * 			      |    SCSI ID: Value 0: Skip, 1: YES
+ *			      |->  Value 0: ALL scan,  Value 1: Manual
+ *   0x15 - 0x1b :  Not Used? (0)
+ *   0x1c        :  Constant? (0x01) (clock div?)
+ *   0x1d - 0x7c :  Not Used (0xff)
+ *   0x7d	 :  Not Used? (0xff)
+ *   0x7e        :  Constant (0x55), HBA chip revision
+ *   0x7f        :  Constant (0xaa), HBA value
+ */
+static int nsp32_getprom_new(nsp32_hw_data *data)
+{
+	int ret, i;
+	int auto_sync;
+	struct nsp32_target *target;
+	int entry;
+
+	/*
+	 * Reset time which is designated by EEPROM.
+	 *
+	 * TODO: Not used yet.
+	 */
+	data->resettime = nsp32_prom_read(data, 0x12);
+
+	/*
+	 * HBA Synchronous Transfer Period
+	 *
+	 * Note: auto_sync = 0: auto, 1: manual.  Ninja SCSI HBA spec says
+	 *	that if auto_sync is 0 (auto), and connected SCSI devices are
+	 *	same or lower than 3, then transfer speed is set as ULTRA-20M.
+	 *	On the contrary if connected SCSI devices are same or higher
+	 *	than 4, then transfer speed is set as FAST-10M.
+	 *
+	 *	I break this rule. The number of connected SCSI devices are
+	 *	only ignored. If auto_sync is 0 (auto), then transfer speed is
+	 *	forced as ULTRA-20M.
+	 */
+	ret = nsp32_prom_read(data, 0x07);
+	switch (ret) {
+	case 0:
+		auto_sync = TRUE;
+		break;
+	case 1:
+		auto_sync = FALSE;
+		break;
+	default:
+		nsp32_msg(KERN_WARNING,
+			  "Unsupported Auto Sync mode."
+			  "Fall back to manual mode.");
+		auto_sync = TRUE;
+	}
+
+	if (trans_mode == ULTRA20M_MODE) {
+		auto_sync = TRUE;
+	}
+
+	/*
+	 * each device Synchronous Transfer Period
+	 */
+	for (i=0; i<NSP32_HOST_SCSIID; i++) {
+		target = &data->target[i];
+		if (auto_sync == TRUE) {
+			target->limit_entry = 0;   /* set as ULTRA20M */
+		} else {
+			ret = nsp32_prom_read(data, i);
+			entry = nsp32_search_period_entry(data, target, ret);
+			if (entry < 0) {
+				/* search failed... set maximum speed */
+				entry = 0;
+			}
+			target->limit_entry = entry;
+		}
+	}
+
+	return (TRUE);
+}
+
+
+/*
+ * ? (I-O Data: SC-NBD) data map:
+ *
+ *   ROMADDR
+ *   0x00 - 0x06 :  Device Synchronous Transfer Period (SCSI ID 0 - 6) 
+ *			Value 0x0: 20MB/S, 0x1: 10MB/S, 0x2: 5MB/S, 0x3: ASYNC
+ *   0x07        :  0 (HBA Synchronous Transfer Period: Auto Sync)
+ *   0x08 - 0x0f :  Not Used? (0x0)
+ *   0x10        :  Transfer Mode
+ *			Value 0: PIO, 1: Busmater
+ *   0x11        :  Bus Reset Delay Time (0x00-0x20)
+ *   0x12        :  Bus Termination
+ * 			Value 0: Disable, 1: Enable
+ *   0x13 - 0x19 :  Disconnection
+ *			Value 0: Disable, 1: Enable
+ *   0x1a - 0x7c :  Not Used? (0)
+ *   0x7d	 :  Not Used? (0xf8)
+ *   0x7e        :  Constant (0x55), HBA chip revision
+ *   0x7f        :  Constant (0xaa), HBA value
+ */
+static int nsp32_getprom_standard(nsp32_hw_data *data)
+{
+	int ret, i;
+	struct nsp32_target *target;
+	int entry, val;
+
+	/*
+	 * Reset time which is designated by EEPROM.
+	 *
+	 * TODO: Not used yet.
+	 */
+	data->resettime = nsp32_prom_read(data, 0x11);
+
+	/*
+	 * each device Synchronous Transfer Period
+	 */
+	for (i=0; i<NSP32_HOST_SCSIID; i++) {
+		target = &data->target[i];
+		ret = nsp32_prom_read(data, i);
+		switch (ret) {
+		case 0:		/* 20MB/s */
+			val = 0x0c;
+			break;
+		case 1:		/* 10MB/s */
+			val = 0x19;
+			break;
+		case 2:		/* 5MB/s */
+			val = 0x32;
+			break;
+		case 3:		/* ASYNC */
+			val = 0x0;
+			break;
+		default:	/* default 20MB/s */
+			val = 0x0c;
+		}
+		entry = nsp32_search_period_entry(data, target, val);
+		if (entry < 0 || trans_mode == ULTRA20M_MODE) {
+			/* search failed... set maximum speed */
+			entry = 0;
+		}
+		target->limit_entry = entry;
+	}
+
+	return (TRUE);
+}
+
+
+/*
+ * Atmel AT24C01A (drived in 5V) serial EEPROM routines
+ */
+static int nsp32_prom_read(nsp32_hw_data *data, int romaddr)
+{
+	int i, val;
+
+	/* start condition */
+	nsp32_prom_start(data);
+
+	/* device address */
+	nsp32_prom_write(data, 1);	/* 1 */
+	nsp32_prom_write(data, 0);	/* 0 */
+	nsp32_prom_write(data, 1);	/* 1 */
+	nsp32_prom_write(data, 0);	/* 0 */
+	nsp32_prom_write(data, 0);	/* A2: 0 (GND) */
+	nsp32_prom_write(data, 0);	/* A1: 0 (GND) */
+	nsp32_prom_write(data, 0);	/* A0: 0 (GND) */
+
+	/* R/W: W for dummy write */
+	nsp32_prom_write(data, 0);
+
+	/* ack */
+	nsp32_prom_write(data, 0);
+
+	/* word address */
+	for (i=7; i>=0; i--) {
+		nsp32_prom_write(data, ((romaddr >> i) & 1));
+	}
+
+	/* ack */
+	nsp32_prom_write(data, 0);
+
+	/* start condition */
+	nsp32_prom_start(data);
+
+	/* device address */
+	nsp32_prom_write(data, 1);	/* 1 */
+	nsp32_prom_write(data, 0);	/* 0 */
+	nsp32_prom_write(data, 1);	/* 1 */
+	nsp32_prom_write(data, 0);	/* 0 */
+	nsp32_prom_write(data, 0);	/* A2: 0 (GND) */
+	nsp32_prom_write(data, 0);	/* A1: 0 (GND) */
+	nsp32_prom_write(data, 0);	/* A0: 0 (GND) */
+
+	/* R/W: R */
+	nsp32_prom_write(data, 1);
+
+	/* ack */
+	nsp32_prom_write(data, 0);
+
+	/* data... */
+	val = 0;
+	for (i=7; i>=0; i--) {
+		val += (nsp32_prom_fetch(data) << i);
+	}
+	
+	/* no ack */
+	nsp32_prom_write(data, 1);
+
+	/* stop condition */
+	nsp32_prom_stop(data);
+
+	return (val);
+}
+
+static void nsp32_prom_start (nsp32_hw_data *data)
+{
+	/* start condition */
+	nsp32_prom_set(data, SCL, 1);
+	nsp32_prom_set(data, SDA, 1);
+	nsp32_prom_set(data, ENA, 1);	/* output mode */
+	nsp32_prom_set(data, SDA, 0);	/* keeping SCL=1 and transiting
+					 * SDA 1->0 is start condition */
+	nsp32_prom_set(data, SCL, 0);
+}
+
+static void nsp32_prom_stop (nsp32_hw_data *data)
+{
+	/* stop condition */
+	nsp32_prom_set(data, SCL, 1);
+	nsp32_prom_set(data, SDA, 0);
+	nsp32_prom_set(data, ENA, 1);	/* output mode */
+	nsp32_prom_set(data, SDA, 1);
+	nsp32_prom_set(data, SCL, 0);
+}
+
+static void nsp32_prom_write (nsp32_hw_data *data, int val)
+{
+	/* write */
+	nsp32_prom_set(data, SDA, val);
+	nsp32_prom_set(data, SCL, 1);
+	nsp32_prom_set(data, SCL, 0);
+}
+
+static int nsp32_prom_fetch (nsp32_hw_data *data)
+{
+	int val;
+
+	/* read */
+	nsp32_prom_set(data, ENA, 0);	/* input mode */
+	nsp32_prom_set(data, SCL, 1);
+	val = nsp32_prom_get(data, SDA);
+	nsp32_prom_set(data, SCL, 0);
+	nsp32_prom_set(data, ENA, 1);	/* output mode */
+	return (val);
+}
+
+static inline void nsp32_prom_set(nsp32_hw_data *data, int bit, int val)
+{
+	int cur;
+	int base = data->BaseAddress;
+
+	switch(val) {
+	case 0:
+		cur = nsp32_index_read1(base, SERIAL_ROM_CTL);
+		nsp32_index_write1(base, SERIAL_ROM_CTL, cur & ~bit);
+		break;
+	case 1:
+		cur = nsp32_index_read1(base, SERIAL_ROM_CTL);
+		nsp32_index_write1(base, SERIAL_ROM_CTL, cur | bit);
+		break;
+	default:
+		nsp32_msg(KERN_ERR, "val must be 0 or 1");
+		return;
+	}
+
+	udelay(10);
+}
+
+static inline int nsp32_prom_get(nsp32_hw_data *data, int bit)
+{
+	int ret;
+	int base = data->BaseAddress;
+
+	ret = nsp32_index_read1(base, SERIAL_ROM_CTL) & bit;
+	switch (ret) {
+	case 0:
+		ret = 0;
+		break;
+	case SDA:
+		ret = 1;
+		break;
+	default:
+		nsp32_msg(KERN_ERR, "return value is not appropriate");
+	}
+
+	udelay(10);
+
+	return (ret);
+}
+
+/* end */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/nsp32.h linux-2.4.21/drivers/scsi/nsp32.h
--- linux-2.4.20/drivers/scsi/nsp32.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/scsi/nsp32.h	2002-12-18 18:58:08.000000000 +0000
@@ -0,0 +1,429 @@
+/*
+ * Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus SCSI Host Bus Adapter driver
+ * Basic data header
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+*/
+
+#ifndef _NSP32_H
+#define _NSP32_H
+
+
+//#define NSP32_DEBUG 9
+
+
+/*
+ * VENDOR/DEVICE ID
+ */
+#define PCI_VENDOR_ID_IODATA  0x10fc
+#define PCI_VENDOR_ID_WORKBIT 0x1145
+
+#define PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II  0x0005
+#define PCI_DEVICE_ID_NINJASCSI_32BI_KME      0xf007
+#define PCI_DEVICE_ID_NINJASCSI_32BI_WBT      0x8007
+#define PCI_DEVICE_ID_WORKBIT_STANDARD        0xf010
+#define PCI_DEVICE_ID_WORKBIT_DUALEDGE        0xf011
+#define PCI_DEVICE_ID_NINJASCSI_32BI_LOGITEC  0xf012
+#define PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC 0xf013
+#define PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO   0xf015
+
+/*
+ * MODEL
+ */
+enum {
+	MODEL_IODATA        = 0,
+	MODEL_KME           = 1,
+	MODEL_WORKBIT       = 2,
+	MODEL_EXT_ROM       = 3,
+	MODEL_PCI_WORKBIT   = 4,
+	MODEL_PCI_LOGITEC   = 5,
+	MODEL_PCI_MELCO     = 6,
+};
+
+static char * nsp32_model[] = {
+	"I-O DATA CBSC-II",
+	"KME SCSI card",
+	"Workbit duo SCSI card",
+	"External ROM",
+	"Workbit Standard/IO Data PCI card",
+	"Logitec PCI card",
+	"Melco PCI card",
+};
+
+
+/*
+ * SCSI Generic Definitions
+ */
+#define EXTENDED_SDTR_LEN	0x03
+
+
+/*
+ * MACRO
+ */
+#define BIT(x)    (1UL << (x))
+#ifndef MIN
+# define MIN(a,b)  ((a) > (b) ? (b) : (a))
+#endif
+
+/*
+ * BASIC Definitions
+ */
+#ifndef TRUE
+# define TRUE  1
+#endif
+#ifndef FALSE
+# define FALSE 0
+#endif
+#define ASSERT 1
+#define NEGATE 0
+
+
+/*******************/
+/* normal register */
+/*******************/
+/*
+ * Don't access below register with Double Word:
+ * +00, +04, +08, +0c, +64, +80, +84, +88, +90, +c4, +c8, +cc, +d0.
+ */
+#define IRQ_CONTROL 0x00	/* BASE+00, W, W */
+#define IRQ_STATUS  0x00	/* BASE+00, W, R */
+# define IRQSTATUS_LATCHED_MSG      BIT(0)
+# define IRQSTATUS_LATCHED_IO       BIT(1)
+# define IRQSTATUS_LATCHED_CD       BIT(2)
+# define IRQSTATUS_LATCHED_BUS_FREE BIT(3)
+# define IRQSTATUS_RESELECT_OCCUER  BIT(4)
+# define IRQSTATUS_PHASE_CHANGE_IRQ BIT(5)
+# define IRQSTATUS_SCSIRESET_IRQ    BIT(6)
+# define IRQSTATUS_TIMER_IRQ        BIT(7)
+# define IRQSTATUS_FIFO_SHLD_IRQ    BIT(8)
+# define IRQSTATUS_PCI_IRQ	    BIT(9)
+# define IRQSTATUS_BMCNTERR_IRQ     BIT(10)
+# define IRQSTATUS_AUTOSCSI_IRQ     BIT(11)
+# define PCI_IRQ_MASK               BIT(12)
+# define TIMER_IRQ_MASK             BIT(13)
+# define FIFO_IRQ_MASK              BIT(14)
+# define SCSI_IRQ_MASK              BIT(15)
+# define IRQ_CONTROL_ALL_IRQ_MASK   0xf000
+# define IRQSTATUS_ANY_IRQ          (IRQSTATUS_RESELECT_OCCUER	| \
+				     IRQSTATUS_PHASE_CHANGE_IRQ	| \
+				     IRQSTATUS_SCSIRESET_IRQ	| \
+				     IRQSTATUS_TIMER_IRQ	| \
+				     IRQSTATUS_FIFO_SHLD_IRQ	| \
+				     IRQSTATUS_PCI_IRQ		| \
+				     IRQSTATUS_BMCNTERR_IRQ	| \
+				     IRQSTATUS_AUTOSCSI_IRQ	)
+
+#define TRANSFER_CONTROL 0x02	/* BASE+02, W, W */
+#define TRANSFER_STATUS  0x02	/* BASE+02, W, R */
+# define CB_MMIO_MODE        BIT(0)
+# define CB_IO_MODE          BIT(1)
+# define BM_TEST             BIT(2)
+# define BM_TEST_DIR         BIT(3)
+# define DUAL_EDGE_ENABLE    BIT(4)
+# define NO_TRANSFER_TO_HOST BIT(5)
+# define TRANSFER_GO         BIT(7)
+# define BLIEND_MODE         BIT(8)
+# define BM_START            BIT(9)
+# define ADVANCED_BM_WRITE   BIT(10)
+# define BM_SINGLE_MODE      BIT(11)
+# define FIFO_TRUE_FULL      BIT(12)
+# define FIFO_TRUE_EMPTY     BIT(13)
+# define ALL_COUNTER_CLR     BIT(14)
+# define FIFOTEST            BIT(15)
+
+#define INDEX_REG 0x04		/* BASE+04, Byte(R/W), Word(R) */
+
+#define TIMER_SET 0x06		/* BASE+06, W, R/W */
+# define TIMER_CNT_MASK 0xff
+# define TIMER_STOP     BIT(8)
+
+#define DATA_REG_LOW 0x08	/* BASE+08, LowW, R/W */
+#define DATA_REG_HI  0x0a	/* BASE+0a, Hi-W, R/W */
+
+#define FIFO_REST_CNT 0x0c	/* BASE+0c, W, R/W */
+# define FIFO_REST_MASK       0x1ff
+# define FIFO_EMPTY_SHLD_FLAG BIT(14)
+# define FIFO_FULL_SHLD_FLAG  BIT(15)
+
+#define SREQ_SMPL_RATE 0x0f	/* BASE+0f, B, R/W */
+# define SREQSMPLRATE_RATE0 BIT(0)
+# define SREQSMPLRATE_RATE1 BIT(1)
+# define SAMPLING_ENABLE    BIT(2)
+
+#define SCSI_BUS_CONTROL 0x10	/* BASE+10, B, R/W */
+# define BUSCTL_SEL         BIT(0)
+# define BUSCTL_RST         BIT(1)
+# define BUSCTL_DATAOUT_ENB BIT(2)
+# define BUSCTL_ATN         BIT(3)
+# define BUSCTL_ACK         BIT(4)
+# define BUSCTL_BSY         BIT(5)
+# define AUTODIRECTION      BIT(6)
+# define ACKENB             BIT(7)
+
+#define CLR_COUNTER 0x12	/* BASE+12, B, W */
+# define ACK_COUNTER_CLR       BIT(0)
+# define SREQ_COUNTER_CLR      BIT(1)
+# define FIFO_HOST_POINTER_CLR BIT(2)
+# define FIFO_REST_COUNT_CLR   BIT(3)
+# define BM_COUNTER_CLR        BIT(4)
+# define SAVED_ACK_CLR         BIT(5)
+# define CLRCOUNTER_ALLMASK    (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5))
+
+#define SCSI_BUS_MONITOR 0x12	/* BASE+12, B, R */
+# define BUSMON_MSG BIT(0)
+# define BUSMON_IO  BIT(1)
+# define BUSMON_CD  BIT(2)
+# define BUSMON_BSY BIT(3)
+# define BUSMON_ACK BIT(4)
+# define BUSMON_REQ BIT(5)
+# define BUSMON_SEL BIT(6)
+# define BUSMON_ATN BIT(7)
+
+#define COMMAND_DATA 0x14	/* BASE+14, B, R/W */
+
+#define PARITY_CONTROL 0x16	/* BASE+16, B, R/W */
+# define PARITY_CHECK_ENABLE BIT(0)
+# define PARITY_ERROR_CLEAR  BIT(1)
+#define PARITY_STATUS  0x16
+//# define PARITY_CHECK_ENABLE BIT(0)
+# define PARITY_ERROR_NORMAL BIT(1)
+# define PARITY_ERROR_LSB    BIT(1)
+# define PARITY_ERROR_MSB    BIT(2)
+
+#define RESELECT_ID 0x18	/* BASE+18, B, R */
+
+#define COMMAND_CONTROL 0x18	/* BASE+18, W, W */
+# define CLEAR_CDB_FIFO_POINTER BIT(0)
+# define AUTO_COMMAND_PHASE     BIT(1)
+# define AUTOSCSI_START         BIT(2)
+# define AUTOSCSI_RESTART       BIT(3)
+# define AUTO_PARAMETER         BIT(4)
+# define AUTO_ATN               BIT(5)
+# define AUTO_MSGIN_00_OR_04    BIT(6)
+# define AUTO_MSGIN_02          BIT(7)
+# define AUTO_MSGIN_03          BIT(8)
+
+#define SET_ARBIT 0x1a		/* BASE+1a, B, W */
+# define ARBIT_GO    BIT(0)
+# define ARBIT_CLEAR BIT(1)
+
+#define ARBIT_STATUS 0x1a	/* BASE+1a, B, R */
+//# define ARBIT_GO             BIT(0)
+# define ARBIT_WIN            BIT(1)
+# define ARBIT_FAIL           BIT(2)
+# define AUTO_PARAMETER_VALID BIT(3)
+# define SGT_VALID            BIT(4)
+
+#define SYNC_REG 0x1c	/* BASE+1c, B, R/W */
+
+#define ACK_WIDTH 0x1d	/* BASE+1d, B, R/W */
+
+#define SCSI_DATA_WITH_ACK 0x20	/* BASE+20, B, R/W */
+#define SCSI_OUT_LATCH_TARGET_ID 0x22	/* BASE+22, B, W */
+#define SCSI_DATA_IN 0x22	/* BASE+22, B, R */
+
+#define SCAM_CONTROL 0x24	/* BASE+24, B, W */
+#define SCAM_STATUS  0x24	/* BASE+24, B, R */
+# define SCAM_MSG    BIT(0)
+# define SCAM_IO     BIT(1)
+# define SCAM_CD     BIT(2)
+# define SCAM_BSY    BIT(3)
+# define SCAM_SEL    BIT(4)
+# define SCAM_XFEROK BIT(5)
+
+#define SCAM_DATA 0x26	/* BASE+26, B, R/W */
+# define SD0					BIT(0)
+# define SD1					BIT(1)
+# define SD2					BIT(2)
+# define SD3					BIT(3)
+# define SD4					BIT(4)
+# define SD5					BIT(5)
+# define SD6					BIT(6)
+# define SD7					BIT(7)
+
+#define SACK_CNT 0x28	/* BASE+28, DW, R/W */
+#define SREQ_CNT 0x2c	/* BASE+2c, DW, R/W */
+
+#define FIFO_DATA_LOW 0x30	/* BASE+30, B/W/DW, R/W */
+#define FIFO_DATA_HIGH 0x32	/* BASE+32, B/W, R/W */
+#define BM_START_ADR 0x34	/* BASE+34, DW, R/W */
+
+#define BM_CNT 0x38	/* BASE+38, DW, R/W */
+# define BM_COUNT_MASK 0x0001ffff
+# define SGTEND        BIT(31)
+
+#define SGT_ADR 0x3c	/* BASE+3c, DW, R/W */
+#define WAIT_REG 0x40	/* Bi only */
+
+#define SCSI_EXECUTE_PHASE 0x40	/* BASE+40, W, R */
+# define COMMAND_PHASE     BIT(0)
+# define DATA_IN_PHASE     BIT(1)
+# define DATA_OUT_PHASE    BIT(2)
+# define MSGOUT_PHASE      BIT(3)
+# define STATUS_PHASE      BIT(4)
+# define ILLEGAL_PHASE     BIT(5)
+# define BUS_FREE_OCCUER   BIT(6)
+# define MSG_IN_OCCUER     BIT(7)
+# define MSG_OUT_OCCUER    BIT(8)
+# define SELECTION_TIMEOUT BIT(9)
+# define MSGIN_00_VALID    BIT(10)
+# define MSGIN_02_VALID    BIT(11)
+# define MSGIN_03_VALID    BIT(12)
+# define MSGIN_04_VALID    BIT(13)
+# define AUTOSCSI_BUSY     BIT(15)
+
+#define SCSI_CSB_IN 0x42	/* BASE+42, B, R */
+
+#define SCSI_MSG_OUT 0x44	/* BASE+44, DW, R/W */
+# define MSGOUT_COUNT_MASK (BIT(0)|BIT(1))
+# define MV_VALID	      BIT(7)
+
+#define SEL_TIME_OUT 0x48	/* BASE+48, W, R/W */
+#define SAVED_SACK_CNT 0x4c	/* BASE+4c, DW, R */
+
+#define HTOSDATADELAY		0x50	/* BASE+50, B, R/W */
+#define STOHDATADELAY		0x54	/* BASE+54, B, R/W */
+#define ACKSUMCHECKRD		0x58	/* BASE+58, W, R */
+#define REQSUMCHECKRD		0x5c	/* BASE+5c, W, R */
+
+
+/********************/
+/* indexed register */
+/********************/
+
+#define CLOCK_DIV 0x00	/* BASE+08, IDX+00, B, R/W */
+# define CLOCK_2		BIT(0)	/* MCLK/2 */
+# define CLOCK_4		BIT(1)	/* MCLK/4 */
+# define PCICLK			BIT(7)	/* PCICLK (33MHz) */
+
+#define TERM_PWR_CONTROL 0x01	/* BASE+08, IDX+01, B, R/W */
+# define BPWR  BIT(0)
+# define SENSE BIT(1)	/* Read Only */
+
+#define EXT_PORT_DDR 0x02	/* BASE+08, IDX+02, B, R/W */
+#define EXT_PORT     0x03	/* BASE+08, IDX+03, B, R/W */
+# define LED_ON	 0
+# define LED_OFF 1
+
+#define IRQ_SELECT 0x04	/* BASE+08, IDX+04, W, R/W */
+# define IRQSELECT_RESELECT_IRQ      BIT(0)
+# define IRQSELECT_PHASE_CHANGE_IRQ  BIT(1)
+# define IRQSELECT_SCSIRESET_IRQ     BIT(2)
+# define IRQSELECT_TIMER_IRQ         BIT(3)
+# define IRQSELECT_FIFO_SHLD_IRQ     BIT(4)
+# define IRQSELECT_TARGET_ABORT_IRQ  BIT(5)
+# define IRQSELECT_MASTER_ABORT_IRQ  BIT(6)
+# define IRQSELECT_SERR_IRQ          BIT(7)
+# define IRQSELECT_PERR_IRQ          BIT(8)
+# define IRQSELECT_BMCNTERR_IRQ      BIT(9)
+# define IRQSELECT_AUTO_SCSI_SEQ_IRQ BIT(10)
+
+#define OLD_SCSI_PHASE 0x05	/* BASE+08, IDX+05, B, R */
+# define OLD_MSG  BIT(0)
+# define OLD_IO   BIT(1)
+# define OLD_CD   BIT(2)
+# define OLD_BUSY BIT(3)
+
+#define FIFO_FULL_SHLD_COUNT 0x06	/* BASE+08, IDX+06, B, R/W */
+#define FIFO_EMPTY_SHLD_COUNT 0x07	/* BASE+08, IDX+07, B, R/W */
+
+#define EXP_ROM_CONTROL 0x08	/* BASE+08, IDX+08, B, R/W */
+
+#define EXP_ROM_ADRL		0x09	/* BASE+08, IDX+09, W, R/W */
+
+#define EXP_ROM_DATA		0x0a	/* BASE+08, IDX+0a, B, R/W */
+
+#define CHIP_MODE 0x0b	/* Bi only */
+# define OEM0 BIT(1)
+# define OEM1 BIT(2)
+# define OPTB BIT(3)
+# define OPTC BIT(4)
+# define OPTD BIT(5)
+# define OPTE BIT(6)
+# define OPTF BIT(7)
+
+#define MISC_WR 0x0c	/* BASE+08, IDX+0c, W, R/W */
+#define MISC_RD 0x0c
+# define SCSI_DIRECTION_DETECTOR_SELECT BIT(0)
+# define SCSI2_HOST_DIRECTION_VALID	BIT(1)	/* Read only */
+# define HOST2_SCSI_DIRECTION_VALID	BIT(2)	/* Read only */
+# define DELAYED_BMSTART                BIT(3)
+# define MASTER_TERMINATION_SELECT      BIT(4)
+# define BMREQ_NEGATE_TIMING_SEL        BIT(5)
+# define AUTOSEL_TIMING_SEL             BIT(6)
+# define MISC_MABORT_MASK		BIT(7)
+# define BMSTOP_CHANGE2_NONDATA_PHASE	BIT(8)
+
+#define BM_CYCLE 0x0d	/* BASE+08, IDX+0d, B, R/W */
+# define BM_CYCLE0		 BIT(0)
+# define BM_CYCLE1		 BIT(1)
+# define BM_FRAME_ASSERT_TIMING	 BIT(2)
+# define BM_IRDY_ASSERT_TIMING	 BIT(3)
+# define BM_SINGLE_BUS_MASTER	 BIT(4)
+# define MEMRD_CMD0              BIT(5)
+# define SGT_AUTO_PARA_MEMED_CMD BIT(6)
+# define MEMRD_CMD1              BIT(7)
+
+
+#define SREQ_EDGH 0x0e	/* BASE+08, IDX+0e, B, W */
+# define SREQ_EDGH_SELECT BIT(0)
+
+#define UP_CNT		0x0f	/* BASE+08, IDX+0f, B, W */
+#define CFG_CMD_STR      0x10	/* BASE+08, IDX+10, W, R */
+#define CFG_LATE_CACHE   0x11	/* BASE+08, IDX+11, W, R/W */
+#define CFG_BASE_ADR_1   0x12	/* BASE+08, IDX+12, W, R */
+#define CFG_BASE_ADR_2   0x13	/* BASE+08, IDX+13, W, R */
+#define CFG_INLINE       0x14	/* BASE+08, IDX+14, W, R */
+
+#define SERIAL_ROM_CTL	0x15	/* BASE+08, IDX+15, B, R */
+# define SCL 					BIT(0)
+# define ENA					BIT(1)
+# define SDA					BIT(2)
+
+#define FIFO_HST_POINTER	0x16	/* BASE+08, IDX+16, B, R/W */
+#define SREQ_DELAY		0x17	/* BASE+08, IDX+17, B, R/W */
+#define SACK_DELAY		0x18	/* BASE+08, IDX+18, B, R/W */
+#define SREQ_NOISE_CANCEL	0x19	/* BASE+08, IDX+19, B, R/W */
+#define SDP_NOISE_CANCEL	0x1a	/* BASE+08, IDX+1a, B, R/W */
+#define DELAY_TEST		0x1b	/* BASE+08, IDX+1b, B, R/W */
+#define SD0_NOISE_CANCEL	0x20	/* BASE+08, IDX+20, B, R/W */
+#define SD1_NOISE_CANCEL	0x21	/* BASE+08, IDX+21, B, R/W */
+#define SD2_NOISE_CANCEL	0x22	/* BASE+08, IDX+22, B, R/W */
+#define SD3_NOISE_CANCEL	0x23	/* BASE+08, IDX+23, B, R/W */
+#define SD4_NOISE_CANCEL	0x24	/* BASE+08, IDX+24, B, R/W */
+#define SD5_NOISE_CANCEL	0x25	/* BASE+08, IDX+25, B, R/W */
+#define SD6_NOISE_CANCEL	0x26	/* BASE+08, IDX+26, B, R/W */
+#define SD7_NOISE_CANCEL	0x27	/* BASE+08, IDX+27, B, R/W */
+
+
+/*
+ * Useful Bus Monitor status combinations.
+ */
+#define BUSMON_BUS_FREE    0
+#define BUSMON_COMMAND     ( BUSMON_BSY |                          BUSMON_CD | BUSMON_REQ )
+#define BUSMON_MESSAGE_IN  ( BUSMON_BSY | BUSMON_MSG | BUSMON_IO | BUSMON_CD | BUSMON_REQ )
+#define BUSMON_MESSAGE_OUT ( BUSMON_BSY | BUSMON_MSG |             BUSMON_CD | BUSMON_REQ )
+#define BUSMON_DATA_IN     ( BUSMON_BSY |              BUSMON_IO |             BUSMON_REQ )
+#define BUSMON_DATA_OUT    ( BUSMON_BSY |                                      BUSMON_REQ )
+#define BUSMON_STATUS      ( BUSMON_BSY |              BUSMON_IO | BUSMON_CD | BUSMON_REQ )
+#define BUSMON_RESELECT    (                           BUSMON_IO                          | BUSMON_SEL)
+#define BUSMON_PHASE_MASK  (              BUSMON_MSG | BUSMON_IO | BUSMON_CD              | BUSMON_SEL)
+
+#define BUSPHASE_COMMAND     ( BUSMON_COMMAND     & BUSMON_PHASE_MASK )
+#define BUSPHASE_MESSAGE_IN  ( BUSMON_MESSAGE_IN  & BUSMON_PHASE_MASK )
+#define BUSPHASE_MESSAGE_OUT ( BUSMON_MESSAGE_OUT & BUSMON_PHASE_MASK )
+#define BUSPHASE_DATA_IN     ( BUSMON_DATA_IN     & BUSMON_PHASE_MASK )
+#define BUSPHASE_DATA_OUT    ( BUSMON_DATA_OUT    & BUSMON_PHASE_MASK )
+#define BUSPHASE_STATUS      ( BUSMON_STATUS      & BUSMON_PHASE_MASK )
+#define BUSPHASE_SELECT      ( BUSMON_SEL | BUSMON_IO )
+
+#endif _NSP32_H
+/* end */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/nsp32_debug.c linux-2.4.21/drivers/scsi/nsp32_debug.c
--- linux-2.4.20/drivers/scsi/nsp32_debug.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/scsi/nsp32_debug.c	2002-12-18 18:58:07.000000000 +0000
@@ -0,0 +1,262 @@
+/*
+ * Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus SCSI Host Bus Adapter driver
+ * Debug routine
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License.
+ */
+
+/*
+ * Show the command data of a command
+ */
+static const char unknown[] = "UNKNOWN";
+
+static const char * group_0_commands[] = {
+/* 00-03 */ "Test Unit Ready", "Rezero Unit", unknown, "Request Sense",
+/* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reasssign Blocks",
+/* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown,
+/* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry",  
+/* 13-16 */ unknown, "Recover Buffered Data", "Mode Select", "Reserve",
+/* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit",
+/* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", 
+/* 1e-1f */ "Prevent/Allow Medium Removal", unknown,
+};
+
+
+static const char *group_1_commands[] = {
+/* 20-22 */  unknown, unknown, unknown,
+/* 23-28 */ unknown, unknown, "Read Capacity", unknown, unknown, "Read (10)",
+/* 29-2d */ unknown, "Write (10)", "Seek (10)", unknown, unknown,
+/* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal",
+/* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", 
+/* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data",
+/* 38-3c */ "Medium Scan", "Compare","Copy Verify", "Write Buffer", "Read Buffer",
+/* 3d-3f */ "Update Block", "Read Long",  "Write Long",
+};
+
+
+static const char *group_2_commands[] = {
+/* 40-41 */ "Change Definition", "Write Same", 
+/* 42-48 */ "Read Sub-Ch(cd)", "Read TOC", "Read Header(cd)", "Play Audio(cd)", unknown, "Play Audio MSF(cd)", "Play Audio Track/Index(cd)", 
+/* 49-4f */ "Play Track Relative(10)(cd)", unknown, "Pause/Resume(cd)", "Log Select", "Log Sense", unknown, unknown,
+/* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)",
+/* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown,
+/* 5c-5f */ unknown, unknown, unknown,
+};
+
+#define group(opcode) (((opcode) >> 5) & 7)
+
+#define RESERVED_GROUP  0
+#define VENDOR_GROUP    1
+#define NOTEXT_GROUP    2
+
+static const char **commands[] = {
+    group_0_commands, group_1_commands, group_2_commands, 
+    (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, 
+    (const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP, 
+    (const char **) VENDOR_GROUP
+};
+
+static const char reserved[] = "RESERVED";
+static const char vendor[] = "VENDOR SPECIFIC";
+
+static void print_opcodek(unsigned char opcode)
+{
+	const char **table = commands[ group(opcode) ];
+
+	switch ((unsigned long) table) {
+	case RESERVED_GROUP:
+		printk("%s[%02x] ", reserved, opcode); 
+		break;
+	case NOTEXT_GROUP:
+		printk("%s(notext)[%02x] ", unknown, opcode); 
+		break;
+	case VENDOR_GROUP:
+		printk("%s[%02x] ", vendor, opcode); 
+		break;
+	default:
+		if (table[opcode & 0x1f] != unknown)
+			printk("%s[%02x] ", table[opcode & 0x1f], opcode);
+		else
+			printk("%s[%02x] ", unknown, opcode);
+		break;
+	}
+}
+
+static void print_commandk (unsigned char *command)
+{
+	int i,s;
+//	printk(KERN_DEBUG);
+	print_opcodek(command[0]);
+	/*printk(KERN_DEBUG __func__ " ");*/
+	if ((command[0] >> 5) == 6 ||
+	    (command[0] >> 5) == 7 ) {
+		s = 12; /* vender specific */
+	} else {
+		s = COMMAND_SIZE(command[0]);
+	}
+
+	for ( i = 1; i < s; ++i) {
+		printk("%02x ", command[i]);
+	}
+
+	switch (s) {
+	case 6:
+		printk("LBA=%d len=%d",
+		       (((unsigned int)command[1] & 0x0f) << 16) |
+		       ( (unsigned int)command[2]         <<  8) |
+		       ( (unsigned int)command[3]              ),
+		       (unsigned int)command[4]
+			);
+		break;
+	case 10:
+		printk("LBA=%d len=%d",
+		       ((unsigned int)command[2] << 24) |
+		       ((unsigned int)command[3] << 16) |
+		       ((unsigned int)command[4] <<  8) |
+		       ((unsigned int)command[5]      ),
+		       ((unsigned int)command[7] <<  8) |
+		       ((unsigned int)command[8]      )
+		       );
+		break;
+	case 12:
+		printk("LBA=%d len=%d",
+		       ((unsigned int)command[2] << 24) |
+		       ((unsigned int)command[3] << 16) |
+		       ((unsigned int)command[4] <<  8) |
+		       ((unsigned int)command[5]      ),
+		       ((unsigned int)command[6] << 24) |
+		       ((unsigned int)command[7] << 16) |
+		       ((unsigned int)command[8] <<  8) |
+		       ((unsigned int)command[9]      )
+		       );
+		break;
+	default:
+		break;
+	}
+	printk("\n");
+}
+
+static void show_command(Scsi_Cmnd *ptr)
+{
+	print_commandk(ptr->cmnd);
+}
+
+static void show_busphase(unsigned char stat)
+{
+	switch(stat) {
+	case BUSPHASE_COMMAND:
+		printk( "BUSPHASE_COMMAND\n");
+		break;
+	case BUSPHASE_MESSAGE_IN:
+		printk( "BUSPHASE_MESSAGE_IN\n");
+		break;
+	case BUSPHASE_MESSAGE_OUT:
+		printk( "BUSPHASE_MESSAGE_OUT\n");
+		break;
+	case BUSPHASE_DATA_IN:
+		printk( "BUSPHASE_DATA_IN\n");
+		break;
+	case BUSPHASE_DATA_OUT:
+		printk( "BUSPHASE_DATA_OUT\n");
+		break;
+	case BUSPHASE_STATUS:
+		printk( "BUSPHASE_STATUS\n");
+		break;
+	case BUSPHASE_SELECT:
+		printk( "BUSPHASE_SELECT\n");
+		break;
+	default:
+		printk( "BUSPHASE_other: 0x%x\n", stat);
+		break;
+	}
+}
+
+static void show_autophase(unsigned short i)
+{
+	printk("auto: 0x%x,", i);
+
+	if(i & COMMAND_PHASE) {
+		printk(" cmd");
+	}
+	if(i & DATA_IN_PHASE) {
+		printk(" din");
+	}
+	if(i & DATA_OUT_PHASE) {
+		printk(" dout");
+	}
+	if(i & MSGOUT_PHASE) {
+		printk(" mout");
+	}
+	if(i & STATUS_PHASE) {
+		printk(" stat");
+	}
+	if(i & ILLEGAL_PHASE) {
+		printk(" ill");
+	}
+	if(i & BUS_FREE_OCCUER) {
+		printk(" bfree-o");
+	}
+	if(i & MSG_IN_OCCUER) {
+		printk(" min-o");
+	}
+	if(i & MSG_OUT_OCCUER) {
+		printk(" mout-o");
+	}
+	if(i & SELECTION_TIMEOUT) {
+		printk(" sel");
+	}
+	if(i & MSGIN_00_VALID) {
+		printk(" m0");
+	}
+	if(i & MSGIN_02_VALID) {
+		printk(" m2");
+	}
+	if(i & MSGIN_03_VALID) {
+		printk(" m3");
+	}
+	if(i & MSGIN_04_VALID) {
+		printk(" m4");
+	}
+	if(i & AUTOSCSI_BUSY) {
+		printk(" busy");
+	}
+
+	printk("\n");
+}
+
+static void nsp32_print_register(int base)
+{
+	if (!(NSP32_DEBUG_MASK & NSP32_SPECIAL_PRINT_REGISTER))
+		return;
+
+	printk("Phase=0x%x, ", nsp32_read1(base, SCSI_BUS_MONITOR));
+	printk("OldPhase=0x%x, ", nsp32_index_read1(base, OLD_SCSI_PHASE));
+	printk("syncreg=0x%x, ", nsp32_read1(base, SYNC_REG));
+	printk("ackwidth=0x%x, ", nsp32_read1(base, ACK_WIDTH));
+	printk("sgtpaddr=0x%lx, ", nsp32_read4(base, SGT_ADR));
+	printk("scsioutlatch=0x%x, ", nsp32_read1(base, SCSI_OUT_LATCH_TARGET_ID));
+	printk("msgout=0x%lx, ", nsp32_read4(base, SCSI_MSG_OUT));
+	printk("miscrd=0x%x, ", nsp32_index_read2(base, MISC_WR));
+	printk("seltimeout=0x%x, ", nsp32_read2(base, SEL_TIME_OUT));
+	printk("sreqrate=0x%x, ", nsp32_read1(base, SREQ_SMPL_RATE));
+	printk("transStatus=0x%x, ", nsp32_read2(base, TRANSFER_STATUS));
+	printk("reselectid=0x%x, ", nsp32_read2(base, COMMAND_CONTROL));
+	printk("arbit=0x%x, ", nsp32_read1(base, ARBIT_STATUS));
+	printk("BmStart=0x%lx, ", nsp32_read4(base, BM_START_ADR));
+	printk("BmCount=0x%lx, ", nsp32_read4(base, BM_CNT));
+	printk("SackCnt=0x%lx, ", nsp32_read4(base, SACK_CNT));
+	printk("SReqCnt=0x%lx, ", nsp32_read4(base, SREQ_CNT));
+	printk("SavedSackCnt=0x%lx, ", nsp32_read4(base, SAVED_SACK_CNT));
+	printk("ScsiBusControl=0x%x, ", nsp32_read1(base, SCSI_BUS_CONTROL));
+	printk("FifoRestCnt=0x%x, ", nsp32_read2(base, FIFO_REST_CNT));
+	printk("CdbIn=0x%x, ", nsp32_read1(base, SCSI_CSB_IN));
+	printk("\n");
+
+	if (0) {
+		printk("execph=0x%x, ", nsp32_read2(base, SCSI_EXECUTE_PHASE));
+		printk("IrqStatus=0x%x, ", nsp32_read2(base, IRQ_STATUS));
+		printk("\n");
+	}
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/nsp32_io.h linux-2.4.21/drivers/scsi/nsp32_io.h
--- linux-2.4.20/drivers/scsi/nsp32_io.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/scsi/nsp32_io.h	2002-12-18 18:58:05.000000000 +0000
@@ -0,0 +1,269 @@
+/*
+ * Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus SCSI Host Bus Adapter driver
+ * I/O routine
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License.
+ */
+
+#ifndef _NSP32_IO_H
+#define _NSP32_IO_H
+
+static inline void nsp32_write1(unsigned int  base,
+				unsigned int  index,
+				unsigned char val)
+{
+	outb(val, (base + index));
+}
+
+static inline unsigned char nsp32_read1(unsigned int base,
+					unsigned int index)
+{
+	return inb(base + index);
+}
+
+static inline void nsp32_write2(unsigned int  base,
+				unsigned int  index,
+				unsigned short val)
+{
+	outw(cpu_to_le16(val), (base + index));
+}
+
+static inline unsigned short nsp32_read2(unsigned int base,
+					 unsigned int index)
+{
+	return le16_to_cpu(inw(base + index));
+}
+
+static inline void nsp32_write4(unsigned int  base,
+				unsigned int  index,
+				unsigned long val)
+{
+	outl(cpu_to_le32(val), (base + index));
+}
+
+static inline unsigned long nsp32_read4(unsigned int base,
+					unsigned int index)
+{
+	return le32_to_cpu(inl(base + index));
+}
+
+/*==============================================*/
+
+static inline void nsp32_mmio_write1(unsigned long base,
+				     unsigned int  index,
+				     unsigned char val)
+{
+	volatile unsigned char *ptr;
+
+	ptr = (unsigned char *)(base + NSP32_MMIO_OFFSET + index);
+
+	*ptr = val;
+}
+
+static inline unsigned char nsp32_mmio_read1(unsigned long base,
+					     unsigned int  index)
+{
+	volatile unsigned char *ptr;
+
+	ptr = (unsigned char *)(base + NSP32_MMIO_OFFSET + index);
+
+	return *ptr;
+}
+
+static inline void nsp32_mmio_write2(unsigned long base,
+				     unsigned int  index,
+				     unsigned short val)
+{
+	volatile unsigned short *ptr;
+
+	ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + index);
+
+	*ptr = cpu_to_le16(val);
+}
+
+static inline unsigned short nsp32_mmio_read2(unsigned long base,
+					      unsigned int  index)
+{
+	volatile unsigned short *ptr;
+
+	//printk(__FUNCTION__ "\n");
+
+	ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + index);
+
+	return le16_to_cpu(*ptr);
+}
+
+static inline void nsp32_mmio_write4(unsigned long base,
+				     unsigned int  index,
+				     unsigned long val)
+{
+	volatile unsigned long *ptr;
+
+	ptr = (unsigned long *)(base + NSP32_MMIO_OFFSET + index);
+
+	*ptr = cpu_to_le32(val);
+}
+
+static inline unsigned long nsp32_mmio_read4(unsigned long base,
+					     unsigned int  index)
+{
+	volatile unsigned long *ptr;
+
+	//printk(__FUNCTION__ "\n");
+
+	ptr = (unsigned long *)(base + NSP32_MMIO_OFFSET + index);
+
+	return le32_to_cpu(*ptr);
+}
+
+
+/*=============================================*/
+
+
+static inline unsigned char nsp32_index_read1(unsigned int base,
+					      unsigned int reg)
+{
+	outb(reg, base + INDEX_REG);
+	return inb(base + DATA_REG_LOW);
+}
+
+static inline void nsp32_index_write1(unsigned int  base,
+				      unsigned int  reg,
+				      unsigned char val)
+{
+	outb(reg, base + INDEX_REG);
+	outb(val, base + DATA_REG_LOW);
+}
+
+static inline unsigned short nsp32_index_read2(unsigned int base,
+					       unsigned int reg)
+{
+	outb(reg, base + INDEX_REG);
+	return le16_to_cpu(inw(base + DATA_REG_LOW));
+}
+
+static inline void nsp32_index_write2(unsigned int  base,
+				      unsigned int  reg,
+				      unsigned short val)
+{
+	outb(reg, base + INDEX_REG);
+	outw(cpu_to_le16(val), base + DATA_REG_LOW);
+}
+
+static inline unsigned long nsp32_index_read4(unsigned int base,
+					      unsigned int reg)
+{
+	unsigned long h,l;
+
+	outb(reg, base + INDEX_REG);
+	l = le16_to_cpu(inw(base + DATA_REG_LOW));
+	h = le16_to_cpu(inw(base + DATA_REG_HI ));
+
+	return ((h << 16) | l);
+}
+
+static inline void nsp32_index_write4(unsigned int  base,
+				      unsigned int  reg,
+				      unsigned long val)
+{
+	unsigned long h,l;
+
+	h = (val & 0xffff0000) >> 16;
+	l = (val & 0x0000ffff) >> 0;
+
+	outb(reg, base + INDEX_REG);
+	outw(cpu_to_le16(l), base + DATA_REG_LOW);
+	outw(cpu_to_le16(h), base + DATA_REG_HI);
+}
+
+
+/* ===================================*/
+
+static inline unsigned char nsp32_mmio_index_read1(unsigned int base,
+						   unsigned int reg)
+{
+	volatile unsigned short *index_ptr, *data_ptr;
+
+	index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG);
+	data_ptr  = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW);
+
+	*index_ptr = reg;
+
+	return ((*data_ptr) & 0xff);
+}
+
+static inline void nsp32_mmio_index_write1(unsigned int base,
+					   unsigned int reg,
+					   unsigned char val)
+{
+	volatile unsigned short *index_ptr, *data_ptr;
+
+	index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG);
+	data_ptr  = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW);
+
+	*index_ptr = reg;
+	*data_ptr  = (unsigned short)val;
+}
+
+static inline unsigned short nsp32_mmio_index_read2(unsigned int base,
+						    unsigned int reg)
+{
+	volatile unsigned short *index_ptr, *data_ptr;
+
+	index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG);
+	data_ptr  = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW);
+
+	*index_ptr = reg;
+
+	return le16_to_cpu(*data_ptr);
+}
+
+static inline void nsp32_mmio_index_write2(unsigned int base,
+					   unsigned int reg,
+					   unsigned short val)
+{
+	volatile unsigned short *index_ptr, *data_ptr;
+
+	index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG);
+	data_ptr  = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW);
+
+	*index_ptr = reg;
+	*data_ptr  = val;
+}
+
+/*-------------------------------------------------------------------*/
+
+static inline void nsp32_multi_read4(unsigned int   BaseAddr,
+				     unsigned int   Register,
+				     void          *buf,
+				     unsigned long  count)
+{
+	insl(BaseAddr + Register, buf, count);
+}
+
+static inline void nsp32_fifo_read(unsigned int   base,
+				   void          *buf,
+				   unsigned long  count)
+{
+	//DEBUG(0, __FUNCTION__ "() buf=0x%p, count=0x%lx*4\n", buf, count);
+	nsp32_multi_read4(base, FIFO_DATA_LOW, buf, count);
+}
+
+static inline void nsp32_multi_write4(unsigned int   BaseAddr,
+				      unsigned int   Register,
+				      void          *buf,
+				      unsigned long  count)
+{
+	outsl(BaseAddr + Register, buf, count);
+}
+
+static inline void nsp32_fifo_write(unsigned int   base,
+				    void          *buf,
+				    unsigned long  count)
+{
+	nsp32_multi_write4(base, FIFO_DATA_LOW, buf, count);
+}
+
+#endif _NSP32_IO_H
+/* end */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/scsi_proc.c linux-2.4.21/drivers/scsi/scsi_proc.c
--- linux-2.4.20/drivers/scsi/scsi_proc.c	2001-06-28 00:10:55.000000000 +0000
+++ linux-2.4.21/drivers/scsi/scsi_proc.c	2002-12-18 18:58:02.000000000 +0000
@@ -308,22 +308,3 @@
 }
 
 #endif				/* CONFIG_PROC_FS */
-
-/*
- * Overrides for Emacs so that we get a uniform tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/scsi_scan.c linux-2.4.21/drivers/scsi/scsi_scan.c
--- linux-2.4.20/drivers/scsi/scsi_scan.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/scsi/scsi_scan.c	2002-12-18 18:58:11.000000000 +0000
@@ -162,10 +162,10 @@
 	{"DELL", "PV530F",    "*", BLIST_SPARSELUN | BLIST_LARGELUN}, // Dell PV 530F
 	{"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
 	{"HP", "A6189A", "*", BLIST_SPARSELUN |  BLIST_LARGELUN}, // HP VA7400, by Alar Aun
-	{"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},			/* HP XP Arrays */
+	{"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},	/* HP XP Arrays */
 	{"CMD", "CRA-7280", "*", BLIST_SPARSELUN | BLIST_LARGELUN},   // CMD RAID Controller
 	{"CNSI", "G7324", "*", BLIST_SPARSELUN | BLIST_LARGELUN},     // Chaparral G7324 RAID
-	{"CNSi", "G8324", "*", BLIST_SPARSELUN},     // Chaparral G8324 RAID
+	{"CNSi", "G8324", "*", BLIST_SPARSELUN | BLIST_LARGELUN},     // Chaparral G8324 RAID
 	{"Zzyzx", "RocketStor 500S", "*", BLIST_SPARSELUN},
 	{"Zzyzx", "RocketStor 2000", "*", BLIST_SPARSELUN},
 	{"SONY", "TSL",       "*", BLIST_FORCELUN},  // DDS3 & DDS4 autoloaders
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/sd.c linux-2.4.21/drivers/scsi/sd.c
--- linux-2.4.20/drivers/scsi/sd.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/scsi/sd.c	2002-12-18 18:58:11.000000000 +0000
@@ -668,7 +668,7 @@
 			 * hard error.
 			 */
 			print_sense("sd", SCpnt);
-			result = 0;
+			SCpnt->result = 0;
 			SCpnt->sense_buffer[0] = 0x0;
 			good_sectors = this_count;
 			break;
@@ -1439,10 +1439,8 @@
 		kfree(sd_blocksizes);
 		kfree(sd_hardsizes);
 		for (i = 0; i < N_USED_SD_MAJORS; i++) {
-#if 0 /* XXX aren't we forgetting to deallocate something? */
 			kfree(sd_gendisks[i].de_arr);
 			kfree(sd_gendisks[i].flags);
-#endif
 			kfree(sd_gendisks[i].part);
 		}
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/sim710.h linux-2.4.21/drivers/scsi/sim710.h
--- linux-2.4.20/drivers/scsi/sim710.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/scsi/sim710.h	2002-12-18 18:58:09.000000000 +0000
@@ -14,7 +14,6 @@
 int sim710_bus_reset(Scsi_Cmnd * SCpnt);
 int sim710_dev_reset(Scsi_Cmnd * SCpnt);
 int sim710_host_reset(Scsi_Cmnd * SCpnt);
-int sim710_biosparam(Disk *, kdev_t, int*);
 #ifdef MODULE
 int sim710_release(struct Scsi_Host *);
 #else
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/t128.c linux-2.4.21/drivers/scsi/t128.c
--- linux-2.4.20/drivers/scsi/t128.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.21/drivers/scsi/t128.c	2002-12-18 18:58:11.000000000 +0000
@@ -142,7 +142,7 @@
 
 #define NO_BASES (sizeof (bases) / sizeof (struct base))
 
-static const struct signature {
+static struct signature {
 	const char *string;
 	int offset;
 } signatures[] __initdata = {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/Config.in linux-2.4.21/drivers/sound/Config.in
--- linux-2.4.20/drivers/sound/Config.in	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/sound/Config.in	2002-12-18 18:58:10.000000000 +0000
@@ -133,6 +133,7 @@
 
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       dep_tristate '    AD1816(A) based cards (EXPERIMENTAL)' CONFIG_SOUND_AD1816 $CONFIG_SOUND_OSS
+      dep_tristate '    AD1889 based cards (AD1819 codec) (EXPERIMENTAL)' CONFIG_SOUND_AD1889 $CONFIG_SOUND_OSS
    fi
    dep_tristate '    Aztech Sound Galaxy (non-PnP) cards' CONFIG_SOUND_SGALAXY $CONFIG_SOUND_OSS
    dep_tristate '    Adlib Cards' CONFIG_SOUND_ADLIB $CONFIG_SOUND_OSS
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/Makefile linux-2.4.21/drivers/sound/Makefile
--- linux-2.4.20/drivers/sound/Makefile	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/sound/Makefile	2002-12-18 18:58:05.000000000 +0000
@@ -45,6 +45,7 @@
 obj-$(CONFIG_SOUND_WAVEARTIST)	+= waveartist.o
 obj-$(CONFIG_SOUND_SGALAXY)	+= sgalaxy.o ad1848.o
 obj-$(CONFIG_SOUND_AD1816)	+= ad1816.o
+obj-$(CONFIG_SOUND_AD1889)      += ad1889.o ac97_codec.o
 obj-$(CONFIG_SOUND_ACI_MIXER)	+= aci.o
 obj-$(CONFIG_SOUND_AWE32_SYNTH)	+= awe_wave.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/ac97_codec.c linux-2.4.21/drivers/sound/ac97_codec.c
--- linux-2.4.20/drivers/sound/ac97_codec.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/sound/ac97_codec.c	2002-12-18 18:58:03.000000000 +0000
@@ -52,6 +52,8 @@
 #include <linux/ac97_codec.h>
 #include <asm/uaccess.h>
 
+#define CODEC_ID_BUFSZ 14
+
 static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel);
 static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel, 
 			     unsigned int left, unsigned int right);
@@ -657,7 +659,7 @@
  *	codec_id	-  Turn id1/id2 into a PnP string
  *	@id1: Vendor ID1
  *	@id2: Vendor ID2
- *	@buf: 10 byte buffer
+ *	@buf: CODEC_ID_BUFSZ byte buffer
  *
  *	Fills buf with a zero terminated PnP ident string for the id1/id2
  *	pair. For convenience the return is the passed in buffer pointer.
@@ -665,12 +667,14 @@
  
 static char *codec_id(u16 id1, u16 id2, char *buf)
 {
-	if(id1&0x8080)
-		snprintf(buf, 10, "%0x4X:%0x4X", id1, id2);
-	buf[0] = (id1 >> 8);
-	buf[1] = (id1 & 0xFF);
-	buf[2] = (id2 >> 8);
-	snprintf(buf+3, 7, "%d", id2&0xFF);
+	if(id1&0x8080) {
+		snprintf(buf, CODEC_ID_BUFSZ, "0x%04x:0x%04x", id1, id2);
+	} else {
+		buf[0] = (id1 >> 8);
+		buf[1] = (id1 & 0xFF);
+		buf[2] = (id2 >> 8);
+		snprintf(buf+3, CODEC_ID_BUFSZ - 3, "%d", id2&0xFF);
+	}
 	return buf;
 }
  
@@ -702,7 +706,7 @@
 	u16 id1, id2;
 	u16 audio, modem;
 	int i;
-	char cidbuf[10];
+	char cidbuf[CODEC_ID_BUFSZ];
 
 	/* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should 
 	 * be read zero.
@@ -746,7 +750,7 @@
 	}
 	if (codec->name == NULL)
 		codec->name = "Unknown";
-	printk(KERN_INFO "ac97_codec: AC97 %s codec, id: %s(%s)\n", 
+	printk(KERN_INFO "ac97_codec: AC97 %s codec, id: %s (%s)\n", 
 		modem ? "Modem" : (audio ? "Audio" : ""),
 	       codec_id(id1, id2, cidbuf), codec->name);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/ad1889.c linux-2.4.21/drivers/sound/ad1889.c
--- linux-2.4.20/drivers/sound/ad1889.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/sound/ad1889.c	2002-12-18 18:58:11.000000000 +0000
@@ -0,0 +1,1077 @@
+/*
+ *  Copyright 2001 Randolph Chung <tausq@debian.org>
+ *
+ *  Analog Devices 1889 PCI audio driver (AD1819 AC97-compatible codec)
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *   Notes:
+ *   1. Only flat DMA is supported; s-g is not supported right now
+ *
+ *
+<jsm> tausq: Anyway, to set up sample rates for D to A, you just use the sample rate on the codec. For A to D, you need to set the codec always to 48K (using the split sample rate feature on the codec) and then set the resampler on the AD1889 to the sample rate you want.
+<jsm> Also, when changing the sample rate on the codec you need to power it down and re power it up for the change to take effect!
+ *
+ * $Id: ad1889.c,v 1.2 2002/10/16 04:14:12 grundler Exp $
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/soundcard.h>
+#include <linux/ac97_codec.h>
+#include <linux/sound.h>
+#include <linux/wrapper.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+
+#include "ad1889.h"
+
+#define DBG(fmt, arg...) printk(fmt, ##arg)
+#define DEVNAME "ad1889"
+
+#define NR_HW_CH	4
+#define DAC_RUNNING	1
+#define ADC_RUNNING	2
+
+#define UNDERRUN(dev)	(0)
+
+#define AD1889_READW(dev,reg) readw(dev->regbase + reg)
+#define AD1889_WRITEW(dev,reg,val) writew((val), dev->regbase + reg)
+#define AD1889_READL(dev,reg) readl(dev->regbase + reg)
+#define AD1889_WRITEL(dev,reg,val) writel((val), dev->regbase + reg)
+
+//now 100ms
+#define WAIT_10MS()	do { int __i; for (__i = 0; __i < 100; __i++) udelay(1000); } while(0)
+
+/* currently only support a single device */
+static ad1889_dev_t *ad1889_dev = NULL;
+
+/************************* helper routines ***************************** */
+static inline void ad1889_set_wav_rate(ad1889_dev_t *dev, int rate)
+{
+	dev->state[AD_WAV_STATE].dmabuf.rate = rate;
+	AD1889_WRITEW(dev, AD_DSWAS, rate);
+}
+
+static inline void ad1889_set_adc_rate(ad1889_dev_t *dev, int rate)
+{
+	dev->state[AD_ADC_STATE].dmabuf.rate = rate;
+	AD1889_WRITEW(dev, AD_DSRES, rate);
+}
+
+static inline void ad1889_set_wav_fmt(ad1889_dev_t *dev, int fmt)
+{
+	u16 tmp;
+
+	tmp = AD1889_READW(ad1889_dev, AD_DSWSMC);
+	if (fmt == AFMT_S16_LE) {
+		//tmp |= 0x0100; /* set WA16 */
+		tmp |= 0x0300; /* set WA16 stereo */
+	} else if (fmt == AFMT_U8) {
+		tmp &= ~0x0100; /* clear WA16 */
+	} 
+	AD1889_WRITEW(ad1889_dev, AD_DSWSMC, tmp);
+}
+
+static inline void ad1889_set_adc_fmt(ad1889_dev_t *dev, int fmt)
+{
+	u16 tmp;
+
+	tmp = AD1889_READW(ad1889_dev, AD_DSRAMC);
+	if (fmt == AFMT_S16_LE) {
+		tmp |= 0x0100; /* set WA16 */
+	} else if (fmt == AFMT_U8) {
+		tmp &= ~0x0100; /* clear WA16 */
+	} 
+	AD1889_WRITEW(ad1889_dev, AD_DSRAMC, tmp);
+}
+
+static void ad1889_start_wav(ad1889_state_t *state)
+{
+	unsigned long flags;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	int cnt;
+	u16 tmp;
+
+	spin_lock_irqsave(&state->card->lock, flags);
+
+	if (dmabuf->dma_len)	/* DMA already in flight */
+		goto skip_dma;
+
+	/* setup dma */
+	cnt = dmabuf->wr_ptr - dmabuf->rd_ptr;
+	if (cnt == 0)		/* done - don't need to do anything */
+		goto skip_dma;
+
+	/* If the wr_ptr has wrapped, only map to the end */
+	if (cnt < 0)
+		cnt = DMA_SIZE - dmabuf->rd_ptr;
+
+	dmabuf->dma_handle = pci_map_single(ad1889_dev->pci,
+					dmabuf->rawbuf + dmabuf->rd_ptr,
+					cnt, PCI_DMA_TODEVICE);
+	dmabuf->dma_len = cnt;
+	dmabuf->ready = 1;
+
+        /* load up the current register set */
+	AD1889_WRITEL(ad1889_dev, AD_DMAWAVCC, cnt);
+	AD1889_WRITEL(ad1889_dev, AD_DMAWAVICC, cnt);
+	AD1889_WRITEL(ad1889_dev, AD_DMAWAVCA, dmabuf->dma_handle);
+
+	/* TODO: for now we load the base registers with the same thing */
+	AD1889_WRITEL(ad1889_dev, AD_DMAWAVBC, cnt);
+	AD1889_WRITEL(ad1889_dev, AD_DMAWAVIBC, cnt);
+	AD1889_WRITEL(ad1889_dev, AD_DMAWAVBA, dmabuf->dma_handle);
+
+	/* and we're off to the races... */
+	AD1889_WRITEL(ad1889_dev, AD_DMACHSS, 0x8);
+	tmp = AD1889_READW(ad1889_dev, AD_DSWSMC);
+	tmp |= 0x0400; /* set WAEN */
+	AD1889_WRITEW(ad1889_dev, AD_DSWSMC, tmp);
+	(void) AD1889_READW(ad1889_dev, AD_DSWSMC); /* flush posted PCI write */
+
+	dmabuf->enable |= DAC_RUNNING;
+
+skip_dma:
+	spin_unlock_irqrestore(&state->card->lock, flags);
+}
+
+
+static void ad1889_stop_wav(ad1889_state_t *state)
+{
+	unsigned long flags;
+	struct dmabuf *dmabuf = &state->dmabuf;
+
+	spin_lock_irqsave(&state->card->lock, flags);
+
+	if (dmabuf->enable & DAC_RUNNING) {
+		u16 tmp;
+		unsigned long cnt = dmabuf->dma_len;
+
+		tmp = AD1889_READW(ad1889_dev, AD_DSWSMC);
+		tmp &= ~0x0400; /* clear WAEN */
+		AD1889_WRITEW(ad1889_dev, AD_DSWSMC, tmp);
+		(void) AD1889_READW(ad1889_dev, AD_DSWSMC); /* flush posted PCI write */
+		pci_unmap_single(ad1889_dev->pci, dmabuf->dma_handle, 
+				cnt, PCI_DMA_TODEVICE);
+
+		dmabuf->enable &= ~DAC_RUNNING;
+
+		/* update dma pointers */
+		dmabuf->rd_ptr += cnt;
+		dmabuf->rd_ptr &= (DMA_SIZE - 1);
+
+		dmabuf->dma_handle = 0;
+		dmabuf->dma_len = 0;
+		dmabuf->ready = 0;
+
+		wake_up(&dmabuf->wait);
+	}
+
+	spin_unlock_irqrestore(&state->card->lock, flags);
+}
+
+
+#if 0
+static void ad1889_startstop_adc(ad1889_state_t *state, int start)
+{
+	u16 tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&state->card->lock, flags);
+	
+	tmp = AD1889_READW(ad1889_dev, AD_DSRAMC);
+	if (start) {
+		state->dmabuf.enable |= ADC_RUNNING;
+		tmp |= 0x0004; /* set ADEN */
+	} else {
+		state->dmabuf.enable &= ~ADC_RUNNING;
+		tmp &= ~0x0004; /* clear ADEN */
+	}
+	AD1889_WRITEW(ad1889_dev, AD_DSRAMC, tmp);
+
+	spin_unlock_irqrestore(&state->card->lock, flags);
+}
+#endif
+
+static ad1889_dev_t *ad1889_alloc_dev(struct pci_dev *pci)
+{
+	ad1889_dev_t *dev;
+	struct dmabuf *dmabuf;
+	int i;
+
+	if ((dev = kmalloc(sizeof(ad1889_dev_t), GFP_KERNEL)) == NULL) 
+		return NULL;
+	memset(dev, 0, sizeof(ad1889_dev_t));
+	spin_lock_init(&dev->lock);
+	dev->pci = pci;
+
+	for (i = 0; i < AD_MAX_STATES; i++) {
+		dev->state[i].card = dev;
+		init_MUTEX(&dev->state[i].sem);
+		init_waitqueue_head(&dev->state[i].dmabuf.wait);
+	}
+
+	/* allocate dma buffer */
+
+	for (i = 0; i < AD_MAX_STATES; i++) {
+		dmabuf = &dev->state[i].dmabuf;
+		if ((dmabuf->rawbuf = kmalloc(DMA_SIZE, GFP_KERNEL|GFP_DMA)) == NULL)
+			return NULL;
+		dmabuf->rawbuf_size = DMA_SIZE;
+		dmabuf->dma_handle = 0;
+		dmabuf->rd_ptr = dmabuf->wr_ptr = dmabuf->dma_len = 0UL;
+		dmabuf->ready = 0;
+		dmabuf->rate = 44100;
+	}
+
+	return dev;
+}
+
+static void ad1889_free_dev(ad1889_dev_t *dev)
+{
+	int j;
+	struct dmabuf *dmabuf;
+
+	if (dev == NULL) 
+		return;
+
+	if (dev->ac97_codec)
+		kfree(dev->ac97_codec);
+
+	for (j = 0; j < AD_MAX_STATES; j++) {
+		dmabuf = &dev->state[j].dmabuf;
+		if (dmabuf->rawbuf != NULL) 
+			kfree(dmabuf->rawbuf);
+	}
+
+	kfree(dev);
+}
+
+static inline void ad1889_trigger_playback(ad1889_dev_t *dev)
+{
+#if 0
+	u32 val;
+	struct dmabuf *dmabuf = &dev->state[AD_WAV_STATE].dmabuf;
+#endif
+
+	ad1889_start_wav(&dev->state[AD_WAV_STATE]);
+}
+
+int ad1889_read_proc (char *page, char **start, off_t off,
+		      int count, int *eof, void *data)
+{
+	char *out = page;
+	int len, i;
+	ad1889_dev_t *dev = data;
+	ad1889_reg_t regs[] = {
+		{ "WSMC", AD_DSWSMC, 16 },
+		{ "RAMC", AD_DSRAMC, 16 },
+		{ "WADA", AD_DSWADA, 16 },
+		{ "SYDA", AD_DSSYDA, 16 },
+		{ "WAS", AD_DSWAS, 16 },
+		{ "RES", AD_DSRES, 16 },
+		{ "CCS", AD_DSCCS, 16 },
+		{ "ADCBA", AD_DMAADCBA, 32 },
+		{ "ADCCA", AD_DMAADCCA, 32 },
+		{ "ADCBC", AD_DMAADCBC, 32 },
+		{ "ADCCC", AD_DMAADCCC, 32 },
+		{ "ADCIBC", AD_DMAADCIBC, 32 },
+		{ "ADCICC", AD_DMAADCICC, 32 },
+		{ "ADCCTRL", AD_DMAADCCTRL, 16 },
+		{ "WAVBA", AD_DMAWAVBA, 32 },
+		{ "WAVCA", AD_DMAWAVCA, 32 },
+		{ "WAVBC", AD_DMAWAVBC, 32 },
+		{ "WAVCC", AD_DMAWAVCC, 32 },
+		{ "WAVIBC", AD_DMAWAVIBC, 32 },
+		{ "WAVICC", AD_DMAWAVICC, 32 },
+		{ "WAVCTRL", AD_DMAWAVCTRL, 16 },
+		{ "DISR", AD_DMADISR, 32 },
+		{ "CHSS", AD_DMACHSS, 32 },
+		{ "IPC", AD_GPIOIPC, 16 },
+		{ "OP", AD_GPIOOP, 16 },
+		{ "IP", AD_GPIOIP, 16 },
+		{ "ACIC", AD_ACIC, 16 },
+		{ "AC97_RESET", 0x100 + AC97_RESET, 16 },
+		{ "AC97_MASTER_VOL_STEREO", 0x100 + AC97_MASTER_VOL_STEREO, 16 },
+		{ "AC97_HEADPHONE_VOL", 0x100 + AC97_HEADPHONE_VOL, 16 },
+		{ "AC97_MASTER_VOL_MONO", 0x100 + AC97_MASTER_VOL_MONO, 16 },
+		{ "AC97_MASTER_TONE", 0x100 + AC97_MASTER_TONE, 16 },
+		{ "AC97_PCBEEP_VOL", 0x100 + AC97_PCBEEP_VOL, 16 },
+		{ "AC97_PHONE_VOL", 0x100 + AC97_PHONE_VOL, 16 },
+		{ "AC97_MIC_VOL", 0x100 + AC97_MIC_VOL, 16 },
+		{ "AC97_LINEIN_VOL", 0x100 + AC97_LINEIN_VOL, 16 },
+		{ "AC97_CD_VOL", 0x100 + AC97_CD_VOL, 16 },
+		{ "AC97_VIDEO_VOL", 0x100 + AC97_VIDEO_VOL, 16 },
+		{ "AC97_AUX_VOL", 0x100 + AC97_AUX_VOL, 16 },
+		{ "AC97_PCMOUT_VOL", 0x100 + AC97_PCMOUT_VOL, 16 },
+		{ "AC97_RECORD_SELECT", 0x100 + AC97_RECORD_SELECT, 16 },
+		{ "AC97_RECORD_GAIN", 0x100 + AC97_RECORD_GAIN, 16 },
+		{ "AC97_RECORD_GAIN_MIC", 0x100 + AC97_RECORD_GAIN_MIC, 16 },
+		{ "AC97_GENERAL_PURPOSE", 0x100 + AC97_GENERAL_PURPOSE, 16 },
+		{ "AC97_3D_CONTROL", 0x100 + AC97_3D_CONTROL, 16 },
+		{ "AC97_MODEM_RATE", 0x100 + AC97_MODEM_RATE, 16 },
+		{ "AC97_POWER_CONTROL", 0x100 + AC97_POWER_CONTROL, 16 },
+		{ 0 }
+	};
+
+	if (dev == NULL)
+		return -ENODEV;
+
+	for (i = 0; regs[i].name != 0; i++)
+		out += sprintf(out, "%s: 0x%0*x\n", regs[i].name, 
+			regs[i].width >> 2, 
+			(regs[i].width == 16 
+			 	? AD1889_READW(dev, regs[i].offset)
+				: AD1889_READL(dev, regs[i].offset)));
+
+	for (i = 0; i < AD_MAX_STATES; i++) {
+		out += sprintf(out, "DMA status for %s:\n", 
+			(i == AD_WAV_STATE ? "WAV" : "ADC")); 
+		out += sprintf(out, "\t\t0x%p (IOVA: 0x%u)\n", 
+			dev->state[i].dmabuf.rawbuf,
+			dev->state[i].dmabuf.dma_handle);
+
+		out += sprintf(out, "\tread ptr: offset %u\n", 
+			(unsigned int)dev->state[i].dmabuf.rd_ptr);
+		out += sprintf(out, "\twrite ptr: offset %u\n", 
+			(unsigned int)dev->state[i].dmabuf.wr_ptr);
+		out += sprintf(out, "\tdma len: offset %u\n", 
+			(unsigned int)dev->state[i].dmabuf.dma_len);
+	}
+
+	len = out - page - off;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0) return 0;
+	} else {
+		len = count;
+	}
+	*start = page + off;
+	return len;
+}
+
+/***************************** DMA interfaces ************************** */
+#if 0
+static inline unsigned long ad1889_get_dma_addr(ad1889_state_t *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	u32 offset;
+
+	if (!(dmabuf->enable & (DAC_RUNNING | ADC_RUNNING))) {
+		printk(KERN_ERR DEVNAME ": get_dma_addr called without dma enabled\n");
+		return 0;
+	}
+	
+	if (dmabuf->enable & DAC_RUNNING)
+		offset = le32_to_cpu(AD1889_READL(state->card, AD_DMAWAVBA));
+	else
+		offset = le32_to_cpu(AD1889_READL(state->card, AD_DMAADCBA));
+
+	return (unsigned long)bus_to_virt((unsigned long)offset) - (unsigned long)dmabuf->rawbuf;
+}
+
+static void ad1889_update_ptr(ad1889_dev_t *dev, int wake)
+{
+	ad1889_state_t *state;
+	struct dmabuf *dmabuf;
+	unsigned long hwptr;
+	int diff;
+
+	/* check ADC first */
+	state = &dev->adc_state;
+	dmabuf = &state->dmabuf;
+	if (dmabuf->enable & ADC_RUNNING) {
+		hwptr = ad1889_get_dma_addr(state);
+		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+
+		dmabuf->hwptr = hwptr;
+		dmabuf->total_bytes += diff;
+		dmabuf->count += diff;
+		if (dmabuf->count > dmabuf->dmasize)
+			dmabuf->count = dmabuf->dmasize;
+
+		if (dmabuf->mapped) {
+			if (wake & dmabuf->count >= dmabuf->fragsize)
+				wake_up(&dmabuf->wait);
+		} else {
+			if (wake & dmabuf->count > 0)
+				wake_up(&dmabuf->wait);
+		}
+	}
+
+	/* check DAC */
+	state = &dev->wav_state;
+	dmabuf = &state->dmabuf;
+	if (dmabuf->enable & DAC_RUNNING) {
+XXX
+
+}
+#endif
+
+/************************* /dev/dsp interfaces ************************* */
+
+static ssize_t ad1889_read(struct file *file, char *buffer, size_t count,
+	loff_t *ppos)
+{
+	return 0;
+}
+
+static ssize_t ad1889_write(struct file *file, const char *buffer, size_t count,
+	loff_t *ppos)
+{
+	ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;
+	ad1889_state_t *state = &dev->state[AD_WAV_STATE];
+	volatile struct dmabuf *dmabuf = &state->dmabuf;
+	ssize_t ret = 0;
+	DECLARE_WAITQUEUE(wait, current);
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	down(&state->sem);
+#if 0
+	if (dmabuf->mapped) {
+		ret = -ENXIO;
+		goto err1;
+	}
+#endif
+	if (!access_ok(VERIFY_READ, buffer, count)) {
+		ret = -EFAULT;
+		goto err1;
+	}
+
+	add_wait_queue(&state->dmabuf.wait, &wait);
+
+	/* start filling dma buffer.... */
+	while (count > 0) {
+		long rem;
+		long cnt = count;
+		unsigned long flags;
+
+
+		for (;;) {
+			long used_bytes;
+			long timeout;	/* max time for DMA in jiffies */
+
+			/* buffer is full if wr catches up to rd */
+			spin_lock_irqsave(&state->card->lock, flags);
+			used_bytes = dmabuf->wr_ptr - dmabuf->rd_ptr;
+			timeout = (dmabuf->dma_len * HZ) / dmabuf->rate;
+			spin_unlock_irqrestore(&state->card->lock, flags);
+
+			/* adjust for buffer wrap around */
+			used_bytes = (used_bytes + DMA_SIZE) & (DMA_SIZE - 1);
+
+			/* If at least one page unused */
+			if (used_bytes < (DMA_SIZE - 0x1000))
+				break;
+
+			/* dma buffer full */
+
+			if (file->f_flags & O_NONBLOCK) {
+				ret = -EAGAIN;
+				goto err2;
+			}
+
+			set_current_state(TASK_INTERRUPTIBLE);
+			if (!schedule_timeout(timeout + 1))
+				printk(KERN_WARNING "AD1889 timeout(%ld) r/w %lx/%lx len %lx\n",
+				    timeout+1,
+				    dmabuf->rd_ptr, dmabuf->wr_ptr,
+				    dmabuf->dma_len);
+
+			if (signal_pending(current)) {
+				ret = -ERESTARTSYS;
+				goto err2;
+			}
+
+		}
+
+		/* watch out for wrapping around static buffer */
+		spin_lock_irqsave(&state->card->lock, flags);
+		rem = DMA_SIZE - dmabuf->wr_ptr;
+		if (cnt > rem)
+			cnt = rem;
+
+		rem = dmabuf->wr_ptr;
+
+		/* update dma pointers */
+		dmabuf->wr_ptr += cnt;
+		dmabuf->wr_ptr &= DMA_SIZE - 1;	/* wrap ptr if necessary */
+		spin_unlock_irqrestore(&state->card->lock, flags);
+
+		/* transfer unwrapped chunk */
+		if (copy_from_user(dmabuf->rawbuf + rem, buffer, cnt)) {
+			ret = -EFAULT;
+			goto err2;
+		}
+
+		DBG("Writing 0x%lx bytes to +0x%lx\n", cnt, rem);
+
+		/* update counters */
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+
+		/* we have something to play - go play it! */
+		ad1889_trigger_playback(dev);
+	}
+
+err2:
+	remove_wait_queue(&state->dmabuf.wait, &wait);
+err1:
+	up(&state->sem);
+	return ret;
+}
+
+static unsigned int ad1889_poll(struct file *file, struct poll_table_struct *wait)
+{
+	unsigned int mask = 0;
+#if 0
+	ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;
+	ad1889_state_t *state = NULL;
+	struct dmabuf *dmabuf;
+	unsigned long flags;
+	
+	if (!(file->f_mode & (FMODE_READ | FMODE_WRITE)))
+		return -EINVAL;
+
+	if (file->f_mode & FMODE_WRITE) {
+		state = &dev->state[AD_WAV_STATE];
+		if (!state) return 0;
+		dmabuf = &state->dmabuf;
+		poll_wait(file, &dmabuf->wait, wait);
+	}
+
+	if (file->f_mode & FMODE_READ) {
+		state = &dev->state[AD_ADC_STATE];
+		if (!state) return 0;
+		dmabuf = &state->dmabuf;
+		poll_wait(file, &dmabuf->wait, wait);
+	}
+
+	spin_lock_irqsave(&dev->lock, flags);
+	ad1889_update_ptr(dev, 0);
+
+	if (file->f_mode & FMODE_WRITE) {
+		state = &dev->state[WAV_STATE];
+		dmabuf = &state->dmabuf;
+		if (dmabuf->mapped) {
+			if (dmabuf->count >= (int)dmabuf->fragsize)
+				mask |= POLLOUT | POLLWRNORM;
+		} else {
+			if ((int)dmabuf->dmasize >= dmabuf->count + 
+				(int)dmabuf->fragsize)
+				mask |= POLLOUT | POLLWRNORM;
+		}
+	}
+
+	if (file ->f_mode & FMODE_READ) {
+		state = &dev->state[AD_ADC_STATE];
+		dmabuf = &state->dmabuf;
+		if (dmabuf->count >= (int)dmabuf->fragsize)
+			mask |= POLLIN | POLLRDNORM;
+	}
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+#endif
+	return mask;
+}
+
+static int ad1889_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	return 0;
+}
+
+static int ad1889_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	int val = 0;
+	ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;
+	struct dmabuf *dmabuf;
+	audio_buf_info abinfo;
+
+	switch (cmd)
+	{
+	case OSS_GETVERSION:
+		return put_user(SOUND_VERSION, (int *)arg);
+
+	case SNDCTL_DSP_RESET:
+		break;
+
+	case SNDCTL_DSP_SYNC:
+		break;
+
+	case SNDCTL_DSP_SPEED:
+		/* set sampling rate */
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+		if (val > 5400 && val < 48000)
+		{
+			if (file->f_mode & FMODE_WRITE)
+				AD1889_WRITEW(ad1889_dev, AD_DSWAS, val);
+			if (file->f_mode & FMODE_READ)
+				AD1889_WRITEW(ad1889_dev, AD_DSRES, val);
+		}
+		return 0;
+
+	case SNDCTL_DSP_STEREO: /* undocumented? */
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+		if (file->f_mode & FMODE_READ) {
+			val = AD1889_READW(ad1889_dev, AD_DSWSMC);
+			if (val) {
+				val |= 0x0200;  /* set WAST */
+			} else {
+				val &= ~0x0200; /* clear WAST */
+			}
+			AD1889_WRITEW(ad1889_dev, AD_DSWSMC, val);
+		}
+		if (file->f_mode & FMODE_WRITE) {
+			val = AD1889_READW(ad1889_dev, AD_DSRAMC);
+			if (val) {
+				val |= 0x0002;  /* set ADST */
+			} else {
+				val &= ~0x0002; /* clear ADST */
+			}
+			AD1889_WRITEW(ad1889_dev, AD_DSRAMC, val);
+		}
+
+		return 0;
+
+	case SNDCTL_DSP_GETBLKSIZE:
+		return put_user(DMA_SIZE, (int *)arg);
+
+	case SNDCTL_DSP_GETFMTS:
+		return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
+
+	case SNDCTL_DSP_SETFMT:
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+
+		if (file->f_mode & FMODE_READ) 
+			ad1889_set_adc_fmt(dev, val);
+
+		if (file->f_mode & FMODE_WRITE) 
+			ad1889_set_wav_fmt(dev, val);
+
+		return put_user(val, (int *)arg);
+
+	case SNDCTL_DSP_CHANNELS:
+		break;
+
+	case SNDCTL_DSP_POST:
+		/* send all data to device */
+		break;
+
+	case SNDCTL_DSP_SUBDIVIDE:
+		break;
+
+	case SNDCTL_DSP_SETFRAGMENT:
+		/* not supported; uses fixed fragment sizes */
+		return put_user(DMA_SIZE, (int *)arg);
+
+	case SNDCTL_DSP_GETOSPACE:
+	case SNDCTL_DSP_GETISPACE:
+		/* space left in dma buffers */
+		if (cmd == SNDCTL_DSP_GETOSPACE)
+			dmabuf = &dev->state[AD_WAV_STATE].dmabuf;
+		else
+			dmabuf = &dev->state[AD_ADC_STATE].dmabuf;
+		abinfo.fragments = 1;
+		abinfo.fragstotal = 1;
+		abinfo.fragsize = DMA_SIZE;
+		abinfo.bytes = DMA_SIZE;
+		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+	case SNDCTL_DSP_NONBLOCK:
+		file->f_flags |= O_NONBLOCK;
+		return 0;
+
+	case SNDCTL_DSP_GETCAPS:
+		return put_user(0, (int *)arg);
+
+	case SNDCTL_DSP_GETTRIGGER:
+	case SNDCTL_DSP_SETTRIGGER:
+		break;
+
+	case SNDCTL_DSP_GETIPTR:
+	case SNDCTL_DSP_GETOPTR:
+		break;
+
+	case SNDCTL_DSP_SETDUPLEX:
+		break;
+	
+	case SNDCTL_DSP_GETODELAY:
+		break;
+
+	case SOUND_PCM_READ_RATE:
+		return put_user(AD1889_READW(ad1889_dev, AD_DSWAS), (int *)arg);
+
+	case SOUND_PCM_READ_CHANNELS:
+	case SOUND_PCM_READ_BITS:
+		break;
+
+	case SNDCTL_DSP_MAPINBUF:
+	case SNDCTL_DSP_MAPOUTBUF:
+	case SNDCTL_DSP_SETSYNCRO:
+	case SOUND_PCM_WRITE_FILTER:
+	case SOUND_PCM_READ_FILTER:
+		break;
+
+	default:
+		break;
+	}
+
+	return -ENOTTY;
+}
+
+static int ad1889_open(struct inode *inode, struct file *file)
+{
+	/* check minor; only support /dev/dsp atm */
+	if (MINOR(inode->i_rdev) != 3)
+		return -ENXIO;
+	
+	file->private_data = ad1889_dev;
+
+	ad1889_set_wav_rate(ad1889_dev, 44100);
+	ad1889_set_wav_fmt(ad1889_dev, AFMT_S16_LE);
+	AD1889_WRITEW(ad1889_dev, AD_DSWADA, 0x0404); /* attenuation */
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int ad1889_release(struct inode *inode, struct file *file)
+{
+	/* if we have state free it here */
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static struct file_operations ad1889_fops = {
+	llseek:         no_llseek,
+	read:           ad1889_read,
+	write:          ad1889_write,
+	poll:           ad1889_poll,
+	ioctl:          ad1889_ioctl,
+	mmap:           ad1889_mmap,
+	open:           ad1889_open,
+	release:        ad1889_release,
+};
+
+/************************* /dev/mixer interfaces ************************ */
+static int ad1889_mixer_open(struct inode *inode, struct file *file)
+{
+	if (ad1889_dev->ac97_codec->dev_mixer != MINOR(inode->i_rdev))
+		return -ENODEV;
+
+	file->private_data = ad1889_dev->ac97_codec;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int ad1889_mixer_release(struct inode *inode, struct file *file)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int ad1889_mixer_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
+	return codec->mixer_ioctl(codec, cmd, arg);
+}
+
+static struct file_operations ad1889_mixer_fops = {
+	llseek:         no_llseek,
+	ioctl:		ad1889_mixer_ioctl,
+	open:		ad1889_mixer_open,
+	release:	ad1889_mixer_release,
+};
+
+/************************* AC97 interfaces ****************************** */
+static void ad1889_codec_write(struct ac97_codec *ac97, u8 reg, u16 val)
+{
+	ad1889_dev_t *dev = ac97->private_data;
+
+	//DBG("Writing 0x%x to 0x%lx\n", val, dev->regbase + 0x100 + reg);
+	return AD1889_WRITEW(dev, 0x100 + reg, val);
+}
+
+static u16 ad1889_codec_read(struct ac97_codec *ac97, u8 reg)
+{
+	ad1889_dev_t *dev = ac97->private_data;
+	//DBG("Reading from 0x%lx\n", dev->regbase + 0x100 + reg);
+	return AD1889_READW(dev, 0x100 + reg);
+}	
+
+static int ad1889_ac97_init(ad1889_dev_t *dev, int id)
+{
+	struct ac97_codec *ac97;
+	u16 eid;
+
+	if ((ac97 = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL) 
+		return -ENOMEM;
+	memset(ac97, 0, sizeof(struct ac97_codec));
+
+	ac97->private_data = dev;
+	ac97->id = id;
+
+	ac97->codec_read = ad1889_codec_read;
+	ac97->codec_write = ad1889_codec_write;
+
+	if (ac97_probe_codec(ac97) == 0) {
+		printk(DEVNAME ": ac97_probe_codec failed\n");
+		goto out_free;
+	}
+
+	eid = ad1889_codec_read(ac97, AC97_EXTENDED_ID);
+	if (eid == 0xffffff) {
+		printk(KERN_WARNING DEVNAME ": no codec attached?\n");
+		goto out_free;
+	}
+
+	dev->ac97_features = eid;
+
+	if ((ac97->dev_mixer = register_sound_mixer(&ad1889_mixer_fops, -1)) < 0) {
+		printk(KERN_ERR DEVNAME ": cannot register mixer\n");
+		goto out_free;
+	}
+
+	dev->ac97_codec = ac97;
+	return 0;
+
+out_free:
+	kfree(ac97);
+	return -ENODEV;
+}
+
+static int ad1889_aclink_reset(struct pci_dev * pcidev)
+{
+	u16 stat;
+	int retry = 200;
+	ad1889_dev_t *dev = pci_get_drvdata(pcidev);
+
+	AD1889_WRITEW(dev, AD_DSCCS, 0x8000); /* turn on clock */
+	AD1889_READW(dev, AD_DSCCS); 
+
+	WAIT_10MS();
+
+	stat = AD1889_READW(dev, AD_ACIC);
+	stat |= 0x0002;				/* Reset Disable */
+	AD1889_WRITEW(dev, AD_ACIC, stat);
+	(void) AD1889_READW(dev, AD_ACIC);	/* flush posted write */
+
+	udelay(10);
+
+	stat = AD1889_READW(dev, AD_ACIC);
+	stat |= 0x0001;				/* Interface Enable */
+	AD1889_WRITEW(dev, AD_ACIC, stat);
+
+	do {
+		if (AD1889_READW(dev, AD_ACIC) & 0x8000)	/* Ready */
+			break;
+		WAIT_10MS();
+		retry--;
+	} while (retry > 0);
+
+	if (!retry) {
+		printk(KERN_ERR "ad1889_aclink_reset: codec is not ready [0x%x]\n",
+			    AD1889_READW(dev, AD_ACIC));
+		return -EBUSY;
+	}
+
+	/* TODO reset AC97 codec */
+	/* TODO set wave/adc pci ctrl status */
+
+	stat = AD1889_READW(dev, AD_ACIC);
+	stat |= 0x0004;				/* Audio Stream Output Enable */
+	AD1889_WRITEW(dev, AD_ACIC, stat);
+	return 0;
+}
+
+/************************* PCI interfaces ****************************** */
+/* PCI device table */
+static struct pci_device_id ad1889_id_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_ANALOG_DEVICES, PCI_DEVICE_ID_AD1889JS, PCI_ANY_ID, 
+	  PCI_ANY_ID, 0, 0, (unsigned long)DEVNAME },
+	{ },
+};
+MODULE_DEVICE_TABLE(pci, ad1889_id_tbl);
+
+static void ad1889_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	u32 stat;
+	ad1889_dev_t *dev = (ad1889_dev_t *)dev_id;
+
+	stat = AD1889_READL(dev, AD_DMADISR);
+
+	/* clear ISR */
+	AD1889_WRITEL(dev, AD_DMADISR, stat);
+
+	if (stat & 0x8) {		/* WAVI */
+		DBG("WAV interrupt\n");
+		dev->stats.wav_intrs++;
+		if (dev->state[AD_WAV_STATE].dmabuf.ready) {
+			ad1889_stop_wav(&dev->state[AD_WAV_STATE]);	/* clean up */
+			ad1889_start_wav(&dev->state[AD_WAV_STATE]);	/* start new */
+		}
+
+	}
+
+	if (stat & 0x2 && dev->state[AD_ADC_STATE].dmabuf.ready) { /* ADCI */
+		DBG("ADC interrupt\n");
+		dev->stats.adc_intrs++;
+	}
+}
+
+static void ad1889_initcfg(ad1889_dev_t *dev)
+{
+	u16 tmp;
+
+	/* make sure the interrupt bits are setup the way we want */
+	tmp = AD1889_READW(dev, AD_DMAWAVCTRL);
+	tmp &= ~0x00ff; /* flat dma, no sg, mask out the intr bits */
+	tmp |= 0x0004;  /* intr on count, loop */
+	AD1889_WRITEW(dev, AD_DMAWAVCTRL, tmp);
+
+	/* unmute... */
+	tmp = AD1889_READW(dev, AD_DSWADA);
+	tmp &= ~0x8080;
+	AD1889_WRITEW(dev, AD_DSWADA, tmp);
+}
+
+static int __devinit ad1889_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
+{
+	int err;
+	ad1889_dev_t *dev;
+	unsigned long bar;
+	struct proc_dir_entry *proc_root = NULL;
+
+	if ((err = pci_enable_device(pcidev)) != 0) {
+		printk(KERN_ERR DEVNAME ": pci_enable_device failed\n");
+		return err;
+	}
+
+	pci_set_master(pcidev);
+	if ((dev = ad1889_alloc_dev(pcidev)) == NULL) {
+		printk(KERN_ERR DEVNAME ": cannot allocate memory for device\n");
+		return -ENOMEM;
+	}
+	pci_set_drvdata(pcidev, dev);
+	bar = pci_resource_start(pcidev, 0);
+	
+        if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_MEM)) {
+		printk(KERN_ERR DEVNAME ": memory region not assigned\n");
+		goto err_free_mem;
+	}
+
+	if (request_irq(pcidev->irq, ad1889_interrupt, SA_SHIRQ, DEVNAME, dev) != 0) {
+		printk(KERN_ERR DEVNAME ": unable to request interrupt\n");
+		goto err_free_mem;
+	}
+
+	request_mem_region(bar, AD_DSIOMEMSIZE, DEVNAME);
+	dev->regbase = (unsigned long)ioremap_nocache(bar, AD_DSIOMEMSIZE);
+
+	printk(KERN_INFO DEVNAME ": %s at 0x%lx IRQ %d\n",
+		(char *)ent->driver_data, dev->regbase, pcidev->irq);
+
+	if (ad1889_aclink_reset(pcidev) != 0)
+		goto err_free_mem;
+
+	/* register /dev/dsp */
+	if ((dev->dev_audio = register_sound_dsp(&ad1889_fops, -1)) < 0) {
+		printk(KERN_ERR DEVNAME ": cannot register /dev/dsp\n");
+		goto err_free_irq;
+	}
+
+	if ((err = ad1889_ac97_init(dev, 0)) != 0)
+		goto err_free_dsp;
+
+	if (((proc_root = proc_mkdir("driver/ad1889", 0)) == NULL) ||
+	    create_proc_read_entry("ac97", S_IFREG|S_IRUGO, proc_root, ac97_read_proc, dev->ac97_codec) == NULL ||
+	    create_proc_read_entry("info", S_IFREG|S_IRUGO, proc_root, ad1889_read_proc, dev) == NULL) 
+		goto err_free_dsp;
+	
+	ad1889_initcfg(dev);
+
+	//DBG(DEVNAME ": Driver initialization done!\n");
+
+	ad1889_dev = dev;
+
+	return 0;
+
+err_free_dsp:
+	unregister_sound_dsp(dev->dev_audio);
+
+err_free_irq:
+	free_irq(pcidev->irq, dev);
+
+err_free_mem:
+	ad1889_free_dev(dev);
+	pci_set_drvdata(pcidev, 0);
+
+	return -ENODEV;
+}
+
+static void __devexit ad1889_remove(struct pci_dev *pcidev)
+{
+	ad1889_dev_t *dev = pci_get_drvdata(pcidev);
+
+	if (dev == NULL) return;
+	
+	unregister_sound_mixer(dev->ac97_codec->dev_mixer);
+	unregister_sound_dsp(dev->dev_audio);
+	free_irq(pcidev->irq, dev);
+	release_mem_region(dev->regbase, AD_DSIOMEMSIZE);
+
+	/* any hw programming needed? */
+	ad1889_free_dev(dev);
+}
+
+MODULE_AUTHOR("Randolph Chung");
+MODULE_DESCRIPTION("Analog Devices AD1889 PCI Audio");
+MODULE_LICENSE("GPL");
+
+static struct pci_driver ad1889_driver = {
+	name:		DEVNAME,
+	id_table:	ad1889_id_tbl,
+	probe:		ad1889_probe,
+	remove:		ad1889_remove,
+};
+
+static int __init ad1889_init_module(void)
+{
+	return pci_module_init(&ad1889_driver);
+}
+
+static void ad1889_exit_module(void)
+{
+	pci_unregister_driver(&ad1889_driver);
+	return;
+}
+
+module_init(ad1889_init_module);
+module_exit(ad1889_exit_module);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/ad1889.h linux-2.4.21/drivers/sound/ad1889.h
--- linux-2.4.20/drivers/sound/ad1889.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/sound/ad1889.h	2002-12-18 18:58:10.000000000 +0000
@@ -0,0 +1,134 @@
+#ifndef _AD1889_H_
+#define _AD1889_H_
+
+#define AD_DSWSMC	0x00	/* DMA input wave/syn mixer control */
+#define AD_DSRAMC	0x02	/* DMA output resamp/ADC mixer control */
+#define AD_DSWADA	0x04	/* DMA input wave attenuation */
+#define AD_DSSYDA	0x06	/* DMA input syn attentuation */
+#define AD_DSWAS	0x08	/* wave input sample rate */
+#define AD_DSRES	0x0a	/* resampler output sample rate */
+#define AD_DSCCS	0x0c	/* chip control/status */
+
+#define AD_DMARESBA	0x40	/* RES base addr */
+#define AD_DMARESCA	0x44	/* RES current addr */
+#define AD_DMARESBC	0x48	/* RES base cnt */
+#define AD_DMARESCC	0x4c	/* RES current count */
+#define AD_DMAADCBA	0x50	/* ADC */
+#define AD_DMAADCCA	0x54
+#define AD_DMAADCBC	0x58
+#define AD_DMAADCCC	0x5c
+#define AD_DMASYNBA	0x60	/* SYN */
+#define AD_DMASYNCA	0x64
+#define AD_DMASYNBC	0x68
+#define AD_DMASYNCC	0x6c
+#define AD_DMAWAVBA	0x70	/* WAV */
+#define AD_DMAWAVCA	0x74
+#define AD_DMAWAVBC	0x78
+#define AD_DMAWAVCC	0x7c
+#define AD_DMARESICC	0x80	/* RES interrupt current count */
+#define AD_DMARESIBC	0x84	/* RES interrupt base count */
+#define AD_DMAADCICC	0x88	/* ADC interrupt current count */
+#define AD_DMAADCIBC	0x8c	/* ADC interrupt base count */
+#define AD_DMASYNICC	0x90	/* SYN interrupt current count */
+#define AD_DMASYNIBC	0x94	/* SYN interrupt base count */
+#define AD_DMAWAVICC	0x98	/* WAV interrupt current count */
+#define AD_DMAWAVIBC	0x9c	/* WAV interrupt base count */
+#define AD_DMARESCTRL	0xa0	/* RES PCI control/status */
+#define AD_DMAADCCTRL	0xa8	/* RES PCI control/status */
+#define AD_DMASYNCTRL	0xb0	/* RES PCI control/status */
+#define AD_DMAWAVCTRL	0xb8	/* RES PCI control/status */
+#define AD_DMADISR	0xc0	/* PCI DMA intr status */
+#define AD_DMACHSS	0xc4	/* PCI DMA channel stop status */
+
+#define AD_GPIOIPC	0xc8	/* IO port ctrl */
+#define AD_GPIOOP	0xca	/* IO output status */
+#define AD_GPIOIP	0xcc	/* IO input status */
+
+/* AC97 registers, 0x100 - 0x17f; see ac97.h */
+#define AD_ACIC		0x180	/* AC Link interface ctrl */
+
+/* OPL3; BAR1 */
+#define AD_OPLM0AS	0x00	/* Music0 address/status */
+#define AD_OPLM0DATA	0x01	/* Music0 data */
+#define AD_OPLM1A	0x02	/* Music1 address */
+#define AD_OPLM1DATA	0x03	/* Music1 data */
+/* 0x04-0x0f reserved */
+
+/* MIDI; BAR2 */
+#define AD_MIDA		0x00	/* MIDI data */
+#define AD_MISC		0x01	/* MIDI status/cmd */
+/* 0x02-0xff reserved */
+
+#define AD_DSIOMEMSIZE	512
+#define AD_OPLMEMSIZE	16
+#define AD_MIDIMEMSIZE	16
+
+#define AD_WAV_STATE	0
+#define AD_ADC_STATE	1
+#define AD_MAX_STATES	2
+
+#define DMA_SIZE	(128*1024)
+
+#define DMA_FLAG_MAPPED	1
+
+struct ad1889_dev;
+
+typedef struct ad1889_state {
+	struct ad1889_dev *card;
+
+	mode_t open_mode;
+	struct dmabuf {
+		unsigned int rate;
+		unsigned char fmt, enable;
+
+		/* buf management */
+		size_t rawbuf_size;
+		void *rawbuf;
+		dma_addr_t dma_handle;	/* mapped address */
+		unsigned long dma_len;	/* number of bytes mapped */
+
+		/* indexes into rawbuf for setting up DMA engine */
+		volatile unsigned long rd_ptr, wr_ptr;
+
+		wait_queue_head_t wait; /* to wait for buf servicing */
+
+		/* OSS bits */
+		unsigned int mapped:1;
+		unsigned int ready:1;
+		unsigned int ossfragshift;
+		int ossmaxfrags;
+		unsigned int subdivision;
+	} dmabuf;
+
+	struct semaphore sem;
+} ad1889_state_t;
+
+typedef struct ad1889_dev {
+	unsigned long regbase;
+	struct pci_dev *pci;
+	
+	spinlock_t lock;
+
+	int dev_audio;
+
+	/* states; one per channel; right now only WAV and ADC */
+	struct ad1889_state state[AD_MAX_STATES];
+
+	/* AC97 codec */
+	struct ac97_codec *ac97_codec;
+	u16 ac97_features;
+
+	/* debugging stuff */
+	struct stats {
+		unsigned int wav_intrs, adc_intrs;
+		unsigned int blocks, underrun, error;
+	} stats;
+} ad1889_dev_t;
+
+typedef struct ad1889_reg {
+	const char *name;
+	int offset;
+	int width;
+} ad1889_reg_t;
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/dmasound/dmasound_core.c linux-2.4.21/drivers/sound/dmasound/dmasound_core.c
--- linux-2.4.20/drivers/sound/dmasound/dmasound_core.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/sound/dmasound/dmasound_core.c	2002-12-18 18:58:03.000000000 +0000
@@ -1212,7 +1212,7 @@
 		return result ;
 		break ;
 	case SNDCTL_DSP_SPEED:
-		/* changing this on the fly will have wierd effects on the sound.
+		/* Changing this on the fly will have weird effects on the sound.
 		   Where there are rate conversions implemented in soft form - it
 		   will cause the _ctx_xxx() functions to be substituted.
 		   However, there doesn't appear to be any reason to dis-allow it from
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/i810_audio.c linux-2.4.21/drivers/sound/i810_audio.c
--- linux-2.4.20/drivers/sound/i810_audio.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/sound/i810_audio.c	2002-12-18 18:58:11.000000000 +0000
@@ -65,6 +65,17 @@
  *	If you need to force a specific rate set the clocking= option
  *
  *	This driver is cursed. (Ben LaHaise)
+ *
+ *
+ *  ICH 4 caveats
+ *
+ *      The ICH4 has the feature, that the codec ID doesn't have to be 
+ *      congruent with the IO connection.
+ * 
+ *      Therefore, from driver version 0.23 on, there is a "codec ID" <->
+ *      "IO register base offset" mapping (card->ac97_id_map) field.
+ *   
+ *      Juergen "George" Sawinski (jsaw) 
  */
  
 #include <linux/module.h>
@@ -122,6 +133,9 @@
 #ifndef PCI_DEVICE_ID_AMD_768_AUDIO
 #define PCI_DEVICE_ID_AMD_768_AUDIO	0x7445
 #endif
+#ifndef PCI_DEVICE_ID_AMD_8111_AC97
+#define PCI_DEVICE_ID_AMD_8111_AC97	0x746d
+#endif
 
 static int ftsodell=0;
 static int strict_clocking=0;
@@ -132,6 +146,7 @@
 //#define DEBUG2
 //#define DEBUG_INTERRUPTS
 //#define DEBUG_MMAP
+//#define DEBUG_MMIO
 
 #define ADC_RUNNING	1
 #define DAC_RUNNING	2
@@ -174,6 +189,11 @@
  * each dma engine has controlling registers.  These goofy
  * names are from the datasheet, but make it easy to write
  * code while leafing through it.
+ *
+ * ICH4 has 6 dma engines, pcm in, pcm out, mic, pcm in 2, 
+ * mic in 2, s/pdif.   Of special interest is the fact that
+ * the upper 3 DMA engines on the ICH4 *must* be accessed
+ * via mmio access instead of pio access.
  */
 
 #define ENUM_ENGINE(PRE,DIG) 									\
@@ -198,6 +218,14 @@
 	CAS	 = 	0x34			/* Codec Write Semaphore Register */
 };
 
+ENUM_ENGINE(MC2,4);     /* Mic In 2 */
+ENUM_ENGINE(PI2,5);     /* PCM In 2 */
+ENUM_ENGINE(SP,6);      /* S/PDIF */
+
+enum {
+	SDM =           0x80                    /* SDATA_IN Map Register */
+};
+
 /* interrupts for a dma engine */
 #define DMA_INT_FIFO		(1<<4)  /* fifo under/over flow */
 #define DMA_INT_COMPLETE	(1<<3)  /* buffer read/write complete and ioc set */
@@ -217,8 +245,7 @@
 #define INT_GPI		(1<<0)
 #define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI)
 
-
-#define DRIVER_VERSION "0.21"
+#define DRIVER_VERSION "0.24"
 
 /* magic numbers to protect our data structures */
 #define I810_CARD_MAGIC		0x5072696E /* "Prin" */
@@ -227,7 +254,7 @@
 #define NR_HW_CH		3
 
 /* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
-#define NR_AC97		2
+#define NR_AC97                 4
 
 /* Please note that an 8bit mono stream is not valid on this card, you must have a 16bit */
 /* stream at a minimum for this card to be happy */
@@ -262,6 +289,25 @@
 	"AMD-8111 IOHub"
 };
 
+/* These are capabilities (and bugs) the chipsets _can_ have */
+static struct {
+	int16_t      nr_ac97;
+#define CAP_MMIO                 0x0001
+#define CAP_20BIT_AUDIO_SUPPORT  0x0002
+	u_int16_t flags;
+} card_cap[] = {
+	{  1, 0x0000 }, /* ICH82801AA */
+	{  1, 0x0000 }, /* ICH82901AB */
+	{  1, 0x0000 }, /* INTEL440MX */
+	{  1, 0x0000 }, /* INTELICH2 */
+	{  2, 0x0000 }, /* INTELICH3 */
+        {  3, 0x0003 }, /* INTELICH4 */
+	/*@FIXME to be verified*/	{  2, 0x0000 }, /* SI7012 */
+	/*@FIXME to be verified*/	{  2, 0x0000 }, /* NVIDIA_NFORCE */
+	/*@FIXME to be verified*/	{  2, 0x0000 }, /* AMD768 */
+	/*@FIXME to be verified*/	{  3, 0x0001 }, /* AMD8111 */
+};
+
 static struct pci_device_id i810_pci_tbl [] __initdata = {
 	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801,
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82801AA},
@@ -363,7 +409,6 @@
 
 
 struct i810_card {
-	struct i810_channel channel[3];
 	unsigned int magic;
 
 	/* We keep i810 cards in a linked list */
@@ -376,6 +421,7 @@
 	/* PCI device stuff */
 	struct pci_dev * pci_dev;
 	u16 pci_id;
+	u16 pci_id_internal; /* used to access card_cap[] */
 #ifdef CONFIG_PM	
 	u16 pm_suspended;
 	u32 pm_save_state[64/sizeof(u32)];
@@ -385,17 +431,27 @@
 	int dev_audio;
 
 	/* structures for abstraction of hardware facilities, codecs, banks and channels*/
+	u16    ac97_id_map[NR_AC97];
 	struct ac97_codec *ac97_codec[NR_AC97];
 	struct i810_state *states[NR_HW_CH];
+	struct i810_channel *channel;	/* 1:1 to states[] but diff. lifetime */
+	dma_addr_t chandma;
 
 	u16 ac97_features;
 	u16 ac97_status;
 	u16 channels;
 	
 	/* hardware resources */
-	unsigned long iobase;
 	unsigned long ac97base;
+	unsigned long iobase;
 	u32 irq;
+
+	unsigned long ac97base_mmio_phys;
+	unsigned long iobase_mmio_phys;
+	u_int8_t *ac97base_mmio;
+	u_int8_t *iobase_mmio;
+
+	int           use_mmio;
 	
 	/* Function support */
 	struct i810_channel *(*alloc_pcm_channel)(struct i810_card *);
@@ -408,6 +464,12 @@
 	int initializing;
 };
 
+/* extract register offset from codec struct */
+#define IO_REG_OFF(codec) (((struct i810_card *) codec->private_data)->ac97_id_map[codec->id])
+
+/* set LVI from CIV */
+#define CIV_TO_LVI(port, off) outb((inb(port+OFF_CIV)+off) & 31, port+OFF_LVI)
+
 static struct i810_card *devs = NULL;
 
 static int i810_open_mixdev(struct inode *inode, struct file *file);
@@ -415,6 +477,10 @@
 			     unsigned int cmd, unsigned long arg);
 static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg);
 static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
+static u16 i810_ac97_get_mmio(struct ac97_codec *dev, u8 reg);
+static void i810_ac97_set_mmio(struct ac97_codec *dev, u8 reg, u16 data);
+static u16 i810_ac97_get_io(struct ac97_codec *dev, u8 reg);
+static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data);
 
 static struct i810_channel *i810_alloc_pcm_channel(struct i810_card *card)
 {
@@ -766,7 +832,8 @@
 	if (dmabuf->count < dmabuf->dmasize && dmabuf->ready && !dmabuf->enable &&
 	    (dmabuf->trigger & PCM_ENABLE_INPUT)) {
 		dmabuf->enable |= ADC_RUNNING;
-		outb((1<<4) | (1<<2) | 1, state->card->iobase + PI_CR);
+		// Interrupt enable, LVI enable, DMA enable
+		outb(0x10 | 0x04 | 0x01, state->card->iobase + PI_CR);
 	}
 }
 
@@ -815,7 +882,8 @@
 	if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
 	    (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
 		dmabuf->enable |= DAC_RUNNING;
-		outb((1<<4) | (1<<2) | 1, state->card->iobase + PO_CR);
+		// Interrupt enable, LVI enable, DMA enable
+		outb(0x10 | 0x04 | 0x01, state->card->iobase + PO_CR);
 	}
 }
 static void start_dac(struct i810_state *state)
@@ -967,7 +1035,7 @@
 	  
 		for(i=0;i<dmabuf->numfrag;i++)
 		{
-			sg->busaddr=virt_to_bus(dmabuf->rawbuf+dmabuf->fragsize*i);
+			sg->busaddr=(u32)dmabuf->dma_handle+dmabuf->fragsize*i;
 			// the card will always be doing 16bit stereo
 			sg->control=dmabuf->fragsamples;
 			if(state->card->pci_id == PCI_DEVICE_ID_SI_7012)
@@ -982,9 +1050,11 @@
 		}
 		spin_lock_irqsave(&state->card->lock, flags);
 		outb(2, state->card->iobase+c->port+OFF_CR);   /* reset DMA machine */
-		outl(virt_to_bus(&c->sg[0]), state->card->iobase+c->port+OFF_BDBAR);
-		outb(0, state->card->iobase+c->port+OFF_CIV);
-		outb(0, state->card->iobase+c->port+OFF_LVI);
+		while( inb(state->card->iobase+c->port+OFF_CR) & 0x02 ) ;
+		outl((u32)state->card->chandma +
+		    c->num*sizeof(struct i810_channel),
+		    state->card->iobase+c->port+OFF_BDBAR);
+		CIV_TO_LVI(state->card->iobase+c->port, 0);
 
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
@@ -1030,13 +1100,13 @@
 		if(rec && dmabuf->count < dmabuf->dmasize &&
 		   (dmabuf->trigger & PCM_ENABLE_INPUT))
 		{
-			outb((inb(port+OFF_CIV)+1)&31, port+OFF_LVI);
+			CIV_TO_LVI(port, 1);
 			__start_adc(state);
 			while( !(inb(port + OFF_CR) & ((1<<4) | (1<<2))) ) ;
 		} else if (!rec && dmabuf->count &&
 			   (dmabuf->trigger & PCM_ENABLE_OUTPUT))
 		{
-			outb((inb(port+OFF_CIV)+1)&31, port+OFF_LVI);
+			CIV_TO_LVI(port, 1);
 			__start_dac(state);
 			while( !(inb(port + OFF_CR) & ((1<<4) | (1<<2))) ) ;
 		}
@@ -1304,7 +1374,6 @@
 				if (dmabuf->enable & ADC_RUNNING)
 					__stop_adc(state);
 				dmabuf->enable = 0;
-				wake_up(&dmabuf->wait);
 #ifdef DEBUG_INTERRUPTS
 				printk(" STOP ");
 #endif
@@ -1750,9 +1819,11 @@
 		}
 		if (c != NULL) {
 			outb(2, state->card->iobase+c->port+OFF_CR);   /* reset DMA machine */
-			outl(virt_to_bus(&c->sg[0]), state->card->iobase+c->port+OFF_BDBAR);
-			outb(0, state->card->iobase+c->port+OFF_CIV);
-			outb(0, state->card->iobase+c->port+OFF_LVI);
+			while ( inb(state->card->iobase+c->port+OFF_CR) & 2 );
+			outl((u32)state->card->chandma +
+			    c->num*sizeof(struct i810_channel),
+			    state->card->iobase+c->port+OFF_BDBAR);
+			CIV_TO_LVI(state->card->iobase+c->port, 0);
 		}
 
 		spin_unlock_irqrestore(&state->card->lock, flags);
@@ -1874,7 +1945,8 @@
 		}
 
 		/* ICH and ICH0 only support 2 channels */
-		if ( state->card->pci_id == 0x2415 || state->card->pci_id == 0x2425 ) 
+		if ( state->card->pci_id == PCI_DEVICE_ID_INTEL_82801 
+		     || state->card->pci_id == PCI_DEVICE_ID_INTEL_82901) 
 			return put_user(2, (int *)arg);
 	
 		/* Multi-channel support was added with ICH2. Bits in */
@@ -1893,12 +1965,14 @@
 
 		switch ( val ) {
 			case 2: /* 2 channels is always supported */
-				outl(state->card->iobase + GLOB_CNT, (i_glob_cnt & 0xcfffff));
+				outl(i_glob_cnt & 0xffcfffff,
+				     state->card->iobase + GLOB_CNT);
 				/* Do we need to change mixer settings????  */
 				break;
 			case 4: /* Supported on some chipsets, better check first */
 				if ( state->card->channels >= 4 ) {
-					outl(state->card->iobase + GLOB_CNT, ((i_glob_cnt & 0xcfffff) | 0x0100000));
+					outl((i_glob_cnt & 0xffcfffff) | 0x100000,
+					      state->card->iobase + GLOB_CNT);
 					/* Do we need to change mixer settings??? */
 				} else {
 					val = ret;
@@ -1906,7 +1980,8 @@
 				break;
 			case 6: /* Supported on some chipsets, better check first */
 				if ( state->card->channels >= 6 ) {
-					outl(state->card->iobase + GLOB_CNT, ((i_glob_cnt & 0xcfffff) | 0x0200000));
+					outl((i_glob_cnt & 0xffcfffff) | 0x200000,
+					      state->card->iobase + GLOB_CNT);
 					/* Do we need to change mixer settings??? */
 				} else {
 					val = ret;
@@ -2111,14 +2186,14 @@
 #if defined(DEBUG) || defined(DEBUG_MMAP)
 		printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val);
 #endif
-		if( !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
+		if((file->f_mode & FMODE_READ) && !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
 			stop_adc(state);
 		}
-		if( !(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) {
+		if((file->f_mode & FMODE_WRITE) && !(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) {
 			stop_dac(state);
 		}
 		dmabuf->trigger = val;
-		if(val & PCM_ENABLE_OUTPUT && !(dmabuf->enable & DAC_RUNNING)) {
+		if((file->f_mode & FMODE_WRITE) && (val & PCM_ENABLE_OUTPUT) && !(dmabuf->enable & DAC_RUNNING)) {
 			if (!dmabuf->write_channel) {
 				dmabuf->ready = 0;
 				dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
@@ -2139,7 +2214,7 @@
 			} else
 				start_dac(state);
 		}
-		if(val & PCM_ENABLE_INPUT && !(dmabuf->enable & ADC_RUNNING)) {
+		if((file->f_mode & FMODE_READ) && (val & PCM_ENABLE_INPUT) && !(dmabuf->enable & ADC_RUNNING)) {
 			if (!dmabuf->read_channel) {
 				dmabuf->ready = 0;
 				dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
@@ -2424,6 +2499,9 @@
 			i810_set_spdif_output(state, AC97_EA_SPSA_3_4, spdif_locked);
 		} else {
 			i810_set_dac_rate(state, 8000);
+			/* Put the ACLink in 2 channel mode by default */
+			i = inl(card->iobase + GLOB_CNT);
+			outl(i & 0xffcfffff, card->iobase + GLOB_CNT);
 		}
 	}
 		
@@ -2488,27 +2566,86 @@
 
 /* Write AC97 codec registers */
 
-static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg)
+static u16 i810_ac97_get_mmio(struct ac97_codec *dev, u8 reg)
 {
 	struct i810_card *card = dev->private_data;
 	int count = 100;
-	u8 reg_set = ((dev->id)?((reg&0x7f)|0x80):(reg&0x7f));
+	u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
+	
+	while(count-- && (readb(card->iobase_mmio + CAS) & 1)) 
+		udelay(1);
+	
+#ifdef DEBUG_MMIO
+	{
+		u16 ans = readw(card->ac97base_mmio + reg_set);
+		printk(KERN_DEBUG "i810_audio: ac97_get_mmio(%d) -> 0x%04X\n", ((int) reg_set) & 0xffff, (u32) ans);
+		return ans;
+	}
+#else
+	return readw(card->ac97base_mmio + reg_set);
+#endif
+}
 
+static u16 i810_ac97_get_io(struct ac97_codec *dev, u8 reg)
+{
+	struct i810_card *card = dev->private_data;
+	int count = 100;
+	u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
+	
 	while(count-- && (inb(card->iobase + CAS) & 1)) 
 		udelay(1);
 	
 	return inw(card->ac97base + reg_set);
 }
 
-static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
+static void i810_ac97_set_mmio(struct ac97_codec *dev, u8 reg, u16 data)
 {
 	struct i810_card *card = dev->private_data;
 	int count = 100;
-	u8 reg_set = ((dev->id)?((reg&0x7f)|0x80):(reg&0x7f));
+	u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
+	
+	while(count-- && (readb(card->iobase_mmio + CAS) & 1)) 
+		udelay(1);
+	
+	writew(data, card->ac97base_mmio + reg_set);
 
+#ifdef DEBUG_MMIO
+	printk(KERN_DEBUG "i810_audio: ac97_set_mmio(0x%04X, %d)\n", (u32) data, ((int) reg_set) & 0xffff);
+#endif
+}
+
+static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data)
+{
+	struct i810_card *card = dev->private_data;
+	int count = 100;
+	u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
+	
 	while(count-- && (inb(card->iobase + CAS) & 1)) 
 		udelay(1);
-	outw(data, card->ac97base + reg_set);
+	
+        outw(data, card->ac97base + reg_set);
+}
+
+static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg)
+{
+	struct i810_card *card = dev->private_data;
+	if (card->use_mmio) {
+		return i810_ac97_get_mmio(dev, reg);
+	}
+	else {
+		return i810_ac97_get_io(dev, reg);
+	}
+}
+
+static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
+{
+	struct i810_card *card = dev->private_data;
+	if (card->use_mmio) {
+		i810_ac97_set_mmio(dev, reg, data);
+	}
+	else {
+		i810_ac97_set_io(dev, reg, data);
+	}
 }
 
 
@@ -2533,7 +2670,7 @@
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule_timeout(HZ/20);
 		}
-		for (i = 0; i < NR_AC97 && card && !card->initializing; i++)
+		for (i = 0; i < NR_AC97 && card && !card->initializing; i++) 
 			if (card->ac97_codec[i] != NULL &&
 			    card->ac97_codec[i]->dev_mixer == minor) {
 				file->private_data = card->ac97_codec[i];
@@ -2561,10 +2698,18 @@
 /* AC97 codec initialisation.  These small functions exist so we don't
    duplicate code between module init and apm resume */
 
-static inline int i810_ac97_exists(struct i810_card *card,int ac97_number)
+static inline int i810_ac97_exists(struct i810_card *card, int ac97_number)
 {
 	u32 reg = inl(card->iobase + GLOB_STA);
-	return (reg & (0x100 << ac97_number));
+	switch (ac97_number) {
+	case 0:
+		return reg & (1<<8);
+	case 1: 
+		return reg & (1<<9);
+	case 2:
+		return reg & (1<<28);
+	}
+	return 0;
 }
 
 static inline int i810_ac97_enable_variable_rate(struct ac97_codec *codec)
@@ -2587,10 +2732,9 @@
 	/* power it all up */
 	i810_ac97_set(codec, AC97_POWER_CONTROL,
 		      i810_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00);
+
 	/* wait for analog ready */
-	for (i=10;
-	     i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf);
-	     i--)
+	for (i=10; i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--)
 	{
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout(HZ/20);
@@ -2598,11 +2742,18 @@
 	return i;
 }
 
-/* if I knew what this did, I'd give it a better name */
-static int i810_ac97_random_init_stuff(struct i810_card *card)
+/**
+ *	i810_ac97_power_up_bus	-	bring up AC97 link
+ *	@card : ICH audio device to power up
+ *
+ *	Bring up the ACLink AC97 codec bus
+ */
+ 
+static int i810_ac97_power_up_bus(struct i810_card *card)
 {	
 	u32 reg = inl(card->iobase + GLOB_CNT);
 	int i;
+	int primary_codec_id = 0;
 
 	if((reg&2)==0)	/* Cold required */
 		reg|=2;
@@ -2610,8 +2761,13 @@
 		reg|=4;	/* Warm */
 		
 	reg&=~8;	/* ACLink on */
-	outl(reg , card->iobase + GLOB_CNT);
 	
+	/* At this point we deassert AC_RESET # */
+	outl(reg , card->iobase + GLOB_CNT);
+
+	/* We must now allow time for the Codec initialisation.
+	   600mS is the specified time */
+	   	
 	for(i=0;i<10;i++)
 	{
 		if((inl(card->iobase+GLOB_CNT)&4)==0)
@@ -2628,7 +2784,31 @@
 
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(HZ/2);
-	reg = inl(card->iobase + GLOB_STA);
+
+	/*
+	 *	See if the primary codec comes ready. This must happen
+	 *	before we start doing DMA stuff
+	 */	
+	/* see i810_ac97_init for the next 7 lines (jsaw) */
+	inw(card->ac97base);
+	if ((card->pci_id == PCI_DEVICE_ID_INTEL_ICH4)
+	    && (card->use_mmio)) {
+		primary_codec_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
+		printk(KERN_INFO "i810_audio: Primary codec has ID %d\n",
+		       primary_codec_id);
+	}
+
+	if(! i810_ac97_exists(card, primary_codec_id))
+	{
+		printk(KERN_INFO "i810_audio: Codec not ready.. wait.. ");
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ);	/* actually 600mS by the spec */
+
+		if(i810_ac97_exists(card, primary_codec_id))
+			printk("OK\n");
+		else 
+			printk("no response.\n");
+	}
 	inw(card->ac97base);
 	return 1;
 }
@@ -2636,12 +2816,14 @@
 static int __init i810_ac97_init(struct i810_card *card)
 {
 	int num_ac97 = 0;
+	int ac97_id;
 	int total_channels = 0;
+	int nr_ac97_max = card_cap[card->pci_id_internal].nr_ac97;
 	struct ac97_codec *codec;
 	u16 eid;
 	u32 reg;
 
-	if(!i810_ac97_random_init_stuff(card)) return 0;
+	if(!i810_ac97_power_up_bus(card)) return 0;
 
 	/* Number of channels supported */
 	/* What about the codec?  Just because the ICH supports */
@@ -2657,26 +2839,47 @@
 		card->channels = 6;
 	else if ( reg & 0x0100000 )
 		card->channels = 4;
-	printk("i810_audio: Audio Controller supports %d channels.\n", card->channels);
+	printk(KERN_INFO "i810_audio: Audio Controller supports %d channels.\n", card->channels);
+	printk(KERN_INFO "i810_audio: Defaulting to base 2 channel mode.\n");
+	reg = inl(card->iobase + GLOB_CNT);
+	outl(reg & 0xffcfffff, card->iobase + GLOB_CNT);
 		
-	inw(card->ac97base);
+	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) 
+		card->ac97_codec[num_ac97] = NULL;
 
-	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
+	/*@FIXME I don't know, if I'm playing to safe here... (jsaw) */
+	if ((nr_ac97_max > 2) && !card->use_mmio) nr_ac97_max = 2;
 
-		/* Assume codec isn't available until we go through the
-		 * gauntlet below */
-		card->ac97_codec[num_ac97] = NULL;
+	for (num_ac97 = 0; num_ac97 < nr_ac97_max; num_ac97++) {
+		/* codec reset */
+		printk(KERN_INFO "i810_audio: Resetting connection %d\n", num_ac97);
+		if (card->use_mmio) readw(card->ac97base_mmio + 0x80*num_ac97);
+		else inw(card->ac97base + 0x80*num_ac97);
+
+		/* If we have the SDATA_IN Map Register, as on ICH4, we
+		   do not loop thru all possible codec IDs but thru all 
+		   possible IO channels. Bit 0:1 of SDM then holds the 
+		   last codec ID spoken to. 
+		*/
+		if ((card->pci_id == PCI_DEVICE_ID_INTEL_ICH4)
+		    && (card->use_mmio)) {
+			ac97_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
+			printk(KERN_INFO "i810_audio: Connection %d with codec id %d\n",
+			       num_ac97, ac97_id);
+		}
+		else {
+			ac97_id = num_ac97;
+		}
 
 		/* The ICH programmer's reference says you should   */
 		/* check the ready status before probing. So we chk */
 		/*   What do we do if it's not ready?  Wait and try */
 		/*   again, or abort?                               */
-		if (!i810_ac97_exists(card,num_ac97)) {
+		if (!i810_ac97_exists(card, ac97_id)) {
 			if(num_ac97 == 0)
 				printk(KERN_ERR "i810_audio: Primary codec not ready.\n");
-			break; /* I think this works, if not ready stop */
 		}
-
+		
 		if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL)
 			return -ENOMEM;
 		memset(codec, 0, sizeof(struct ac97_codec));
@@ -2684,13 +2887,20 @@
 		/* initialize some basic codec information, other fields will be filled
 		   in ac97_probe_codec */
 		codec->private_data = card;
-		codec->id = num_ac97;
+		codec->id = ac97_id;
+		card->ac97_id_map[ac97_id] = num_ac97 * 0x80;
 
-		codec->codec_read = i810_ac97_get;
-		codec->codec_write = i810_ac97_set;
+		if (card->use_mmio) {	
+			codec->codec_read = i810_ac97_get_mmio;
+			codec->codec_write = i810_ac97_set_mmio;
+		}
+		else {
+			codec->codec_read = i810_ac97_get_io;
+			codec->codec_write = i810_ac97_set_io;
+		}
 	
 		if(!i810_ac97_probe_and_powerup(card,codec)) {
-			printk("i810_audio: timed out waiting for codec %d analog ready.\n", num_ac97);
+			printk(KERN_ERR "i810_audio: timed out waiting for codec %d analog ready.\n", ac97_id);
 			kfree(codec);
 			break;	/* it didn't work */
 		}
@@ -2699,7 +2909,7 @@
 		
 		/* Don't attempt to get eid until powerup is complete */
 		eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
-		
+
 		if(eid==0xFFFFFF)
 		{
 			printk(KERN_WARNING "i810_audio: no codec attached ?\n");
@@ -2707,16 +2917,27 @@
 			break;
 		}
 		
+		/* Check for an AC97 1.0 soft modem (ID1) */
+		
+		if(codec->codec_read(codec, AC97_RESET) & 2)
+		{
+			printk(KERN_WARNING "i810_audio: codec %d is an AC97 1.0 softmodem - skipping.\n", ac97_id);
+			kfree(codec);
+			continue;
+		}
+		
+		/* Check for an AC97 2.x soft modem */
+		
 		codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0L);
-		if(codec->codec_read(codec, AC97_EXTENDED_MODEM_ID))
+		if(codec->codec_read(codec, AC97_EXTENDED_MODEM_ID) & 1)
 		{
-			printk(KERN_WARNING "i810_audio: codec %d is a softmodem - skipping.\n", num_ac97);
+			printk(KERN_WARNING "i810_audio: codec %d is an AC97 2.x softmodem - skipping.\n", ac97_id);
 			kfree(codec);
 			continue;
 		}
 	
 		card->ac97_features = eid;
-				
+
 		/* Now check the codec for useful features to make up for
 		   the dumbness of the 810 hardware engine */
 
@@ -2730,6 +2951,11 @@
 			}			
 		}
    		
+		/* Turn on the amplifier */
+
+		codec->codec_write(codec, AC97_POWER_CONTROL, 
+			 codec->codec_read(codec, AC97_POWER_CONTROL) & ~0x8000);
+				
 		/* Determine how many channels the codec(s) support   */
 		/*   - The primary codec always supports 2            */
 		/*   - If the codec supports AMAP, surround DACs will */
@@ -2755,7 +2981,7 @@
 				total_channels += 2;
 			if (eid & 0x0140) /* LFE and Center channels */
 				total_channels += 2;
-			printk("i810_audio: AC'97 codec %d supports AMAP, total channels = %d\n", num_ac97, total_channels);
+			printk("i810_audio: AC'97 codec %d supports AMAP, total channels = %d\n", ac97_id, total_channels);
 		} else if (eid & 0x0400) {  /* this only works on 2.2 compliant codecs */
 			eid &= 0xffcf;
 			if((eid & 0xc000) != 0)	{
@@ -2777,14 +3003,14 @@
 			}
 			i810_ac97_set(codec, AC97_EXTENDED_ID, eid);
 			eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
-			printk("i810_audio: AC'97 codec %d, new EID value = 0x%04x\n", num_ac97, eid);
+			printk("i810_audio: AC'97 codec %d, new EID value = 0x%04x\n", ac97_id, eid);
 			if (eid & 0x0080) /* L/R Surround channels */
 				total_channels += 2;
 			if (eid & 0x0140) /* LFE and Center channels */
 				total_channels += 2;
-			printk("i810_audio: AC'97 codec %d, DAC map configured, total channels = %d\n", num_ac97, total_channels);
+			printk("i810_audio: AC'97 codec %d, DAC map configured, total channels = %d\n", ac97_id, total_channels);
 		} else {
-			printk("i810_audio: AC'97 codec %d Unable to map surround DAC's (or DAC's not present), total channels = %d\n", num_ac97, total_channels);
+			printk("i810_audio: AC'97 codec %d Unable to map surround DAC's (or DAC's not present), total channels = %d\n", ac97_id, total_channels);
 		}
 
 		if ((codec->dev_mixer = register_sound_mixer(&i810_mixer_fops, -1)) < 0) {
@@ -2833,6 +3059,8 @@
 		init_MUTEX(&state->open_sem);
 		dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT;
 		dmabuf->trigger = PCM_ENABLE_OUTPUT;
+		i810_set_spdif_output(state, -1, 0);
+		i810_set_dac_channels(state, 2);
 		i810_set_dac_rate(state, 48000);
 		if(prog_dmabuf(state, 0) != 0) {
 			goto config_out_nodmabuf;
@@ -2841,7 +3069,7 @@
 			goto config_out;
 		}
 		dmabuf->count = dmabuf->dmasize;
-		outb(31,card->iobase+dmabuf->write_channel->port+OFF_LVI);
+		CIV_TO_LVI(card->iobase+dmabuf->write_channel->port, 31);
 		save_flags(flags);
 		cli();
 		start_dac(state);
@@ -2849,10 +3077,9 @@
 		mdelay(50);
 		new_offset = i810_get_dma_addr(state, 0);
 		stop_dac(state);
-		outb(2,card->iobase+dmabuf->write_channel->port+OFF_CR);
 		restore_flags(flags);
 		i = new_offset - offset;
-#ifdef DEBUG
+#ifdef DEBUG_INTERRUPTS
 		printk("i810_audio: %d bytes in 50 milliseconds\n", i);
 #endif
 		if(i == 0)
@@ -2894,10 +3121,25 @@
 	memset(card, 0, sizeof(*card));
 
 	card->initializing = 1;
-	card->iobase = pci_resource_start (pci_dev, 1);
-	card->ac97base = pci_resource_start (pci_dev, 0);
 	card->pci_dev = pci_dev;
 	card->pci_id = pci_id->device;
+	card->ac97base = pci_resource_start (pci_dev, 0);
+	card->iobase = pci_resource_start (pci_dev, 1);
+
+	/* if chipset could have mmio capability, check it */ 
+	if (card_cap[pci_id->driver_data].flags & CAP_MMIO) {
+		card->ac97base_mmio_phys = pci_resource_start (pci_dev, 2);
+		card->iobase_mmio_phys = pci_resource_start (pci_dev, 3);
+
+		if ((card->ac97base_mmio_phys) && (card->iobase_mmio_phys)) {
+			card->use_mmio = 1;
+		}
+		else {
+			card->ac97base_mmio_phys = 0;
+			card->iobase_mmio_phys = 0;
+		}
+	}
+
 	card->irq = pci_dev->irq;
 	card->next = devs;
 	card->magic = I810_CARD_MAGIC;
@@ -2909,23 +3151,37 @@
 
 	pci_set_master(pci_dev);
 
-	printk(KERN_INFO "i810: %s found at IO 0x%04lx and 0x%04lx, IRQ %d\n",
-	       card_names[pci_id->driver_data], card->iobase, card->ac97base, 
+	printk(KERN_INFO "i810: %s found at IO 0x%04lx and 0x%04lx, "
+	       "MEM 0x%04lx and 0x%04lx, IRQ %d\n",
+	       card_names[pci_id->driver_data], 
+	       card->iobase, card->ac97base, 
+	       card->ac97base_mmio_phys, card->iobase_mmio_phys,
 	       card->irq);
 
 	card->alloc_pcm_channel = i810_alloc_pcm_channel;
 	card->alloc_rec_pcm_channel = i810_alloc_rec_pcm_channel;
 	card->alloc_rec_mic_channel = i810_alloc_rec_mic_channel;
 	card->free_pcm_channel = i810_free_pcm_channel;
-	card->channel[0].offset = 0;
-	card->channel[0].port = 0x00;
-	card->channel[0].num=0;
-	card->channel[1].offset = 0;
-	card->channel[1].port = 0x10;
-	card->channel[1].num=1;
-	card->channel[2].offset = 0;
-	card->channel[2].port = 0x20;
-	card->channel[2].num=2;
+
+	if ((card->channel = pci_alloc_consistent(pci_dev,
+	    sizeof(struct i810_channel)*NR_HW_CH, &card->chandma)) == NULL) {
+		printk(KERN_ERR "i810: cannot allocate channel DMA memory\n");
+		goto out_mem;
+	}
+
+	{ /* We may dispose of this altogether some time soon, so... */
+		struct i810_channel *cp = card->channel;
+
+		cp[0].offset = 0;
+		cp[0].port = 0x00;
+		cp[0].num = 0;
+		cp[1].offset = 0;
+		cp[1].port = 0x10;
+		cp[1].num = 1;
+		cp[2].offset = 0;
+		cp[2].port = 0x20;
+		cp[2].num = 2;
+	}
 
 	/* claim our iospace and irq */
 	request_region(card->iobase, 64, card_names[pci_id->driver_data]);
@@ -2934,19 +3190,42 @@
 	if (request_irq(card->irq, &i810_interrupt, SA_SHIRQ,
 			card_names[pci_id->driver_data], card)) {
 		printk(KERN_ERR "i810_audio: unable to allocate irq %d\n", card->irq);
-		release_region(card->iobase, 64);
-		release_region(card->ac97base, 256);
-		kfree(card);
-		return -ENODEV;
+		goto out_pio;
+	}
+
+	if (card->use_mmio) {
+		if (request_mem_region(card->ac97base_mmio_phys, 512, "ich_audio MMBAR")) {
+			if ((card->ac97base_mmio = ioremap(card->ac97base_mmio_phys, 512))) { /*@FIXME can ioremap fail? don't know (jsaw) */
+				if (request_mem_region(card->iobase_mmio_phys, 256, "ich_audio MBBAR")) {
+					if ((card->iobase_mmio = ioremap(card->iobase_mmio_phys, 256))) {
+						printk(KERN_INFO "i810: %s mmio at 0x%04lx and 0x%04lx\n",
+						       card_names[pci_id->driver_data], 
+						       (unsigned long) card->ac97base_mmio, 
+						       (unsigned long) card->iobase_mmio); 
+					}
+					else {
+						iounmap(card->ac97base_mmio);
+						release_mem_region(card->ac97base_mmio_phys, 512);
+						release_mem_region(card->iobase_mmio_phys, 512);
+						card->use_mmio = 0;
+					}
+				}
+				else {
+					iounmap(card->ac97base_mmio);
+					release_mem_region(card->ac97base_mmio_phys, 512);
+					card->use_mmio = 0;
+				}
+			}
+		}
+		else {
+			card->use_mmio = 0;
+		}
 	}
 
 	/* initialize AC97 codec and register /dev/mixer */
 	if (i810_ac97_init(card) <= 0) {
-		release_region(card->iobase, 64);
-		release_region(card->ac97base, 256);
 		free_irq(card->irq, card);
-		kfree(card);
-		return -ENODEV;
+		goto out_iospace;
 	}
 	pci_set_drvdata(pci_dev, card);
 
@@ -2959,19 +3238,34 @@
 	if ((card->dev_audio = register_sound_dsp(&i810_audio_fops, -1)) < 0) {
 		int i;
 		printk(KERN_ERR "i810_audio: couldn't register DSP device!\n");
-		release_region(card->iobase, 64);
-		release_region(card->ac97base, 256);
 		free_irq(card->irq, card);
 		for (i = 0; i < NR_AC97; i++)
 		if (card->ac97_codec[i] != NULL) {
 			unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
 			kfree (card->ac97_codec[i]);
 		}
-		kfree(card);
-		return -ENODEV;
+		goto out_iospace;
 	}
+
  	card->initializing = 0;
 	return 0;
+
+out_iospace:
+	if (card->use_mmio) {
+		iounmap(card->ac97base_mmio);
+		iounmap(card->iobase_mmio);
+		release_mem_region(card->ac97base_mmio_phys, 512);
+		release_mem_region(card->iobase_mmio_phys, 256);
+	}
+out_pio:	
+	release_region(card->iobase, 64);
+	release_region(card->ac97base, 256);
+out_chan:
+	pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH,
+	    card->channel, card->chandma);
+out_mem:
+	kfree(card);
+	return -ENODEV;
 }
 
 static void __devexit i810_remove(struct pci_dev *pci_dev)
@@ -2982,6 +3276,12 @@
 	free_irq(card->irq, devs);
 	release_region(card->iobase, 64);
 	release_region(card->ac97base, 256);
+	if (card->use_mmio) {
+		iounmap(card->ac97base_mmio);
+		iounmap(card->iobase_mmio);
+		release_mem_region(card->ac97base_mmio_phys, 512);
+		release_mem_region(card->iobase_mmio_phys, 256);
+	}
 
 	/* unregister audio devices */
 	for (i = 0; i < NR_AC97; i++)
@@ -3064,7 +3364,7 @@
 	   hardware has to be more or less completely reinitialized from
 	   scratch after an apm suspend.  Works For Me.   -dan */
 
-	i810_ac97_random_init_stuff(card);
+	i810_ac97_power_up_bus(card);
 
 	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
 		struct ac97_codec *codec = card->ac97_codec[num_ac97];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/mad16.c linux-2.4.21/drivers/sound/mad16.c
--- linux-2.4.20/drivers/sound/mad16.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/sound/mad16.c	2002-12-18 18:58:11.000000000 +0000
@@ -367,6 +367,8 @@
 {
 	unsigned char cfg = 0;
 
+	cfg |= (0x0f & mad16_conf);
+
 	if(c931_detected)
 	{
 		/* Bit 0 has reversd meaning. Bits 1 and 2 sese
@@ -404,7 +406,10 @@
 	   and the C931. */
 	cfg = c931_detected ? 0x04 : 0x00;
 
-	mad_write(MC4_PORT, 0x52|cfg);
+	if(mad16_cdsel & 0x20)
+		mad_write(MC4_PORT, 0x62|cfg);  /* opl4 */
+	else
+		mad_write(MC4_PORT, 0x52|cfg);  /* opl3 */
 
 	mad_write(MC5_PORT, 0x3C);	/* Init it into mode2 */
 	mad_write(MC6_PORT, 0x02);	/* Enable WSS, Disable MPU and SB */
@@ -561,10 +566,10 @@
 	 */
 
 	tmp &= ~0x0f;
+	tmp |= (mad16_conf & 0x0f);   /* CD-ROM and joystick bits */
 	mad_write(MC1_PORT, tmp);
 
-	tmp = mad_read(MC2_PORT);
-
+	tmp = mad16_cdsel;
 	mad_write(MC2_PORT, tmp);
 	mad_write(MC3_PORT, 0xf0);	/* Disable SB */
 
@@ -1051,6 +1056,12 @@
 {
 	if (found_mpu)
 		unload_mad16_mpu(&cfg_mpu);
+	if (gameport.io) {
+		/* the gameport was initialized so we must free it up */
+		gameport_unregister_port(&gameport);
+		gameport.io = 0;
+		release_region(0x201, 1);
+	}
 	unload_mad16(&cfg);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/midibuf.c linux-2.4.21/drivers/sound/midibuf.c
--- linux-2.4.20/drivers/sound/midibuf.c	2001-09-30 19:26:08.000000000 +0000
+++ linux-2.4.21/drivers/sound/midibuf.c	2002-12-18 18:58:07.000000000 +0000
@@ -129,15 +129,16 @@
 		for (dev = 0; dev < num_midis; dev++)
 			if (midi_devs[dev] != NULL && midi_out_buf[dev] != NULL)
 			{
-				int ok = 1;
-
-				while (DATA_AVAIL(midi_out_buf[dev]) && ok)
+				while (DATA_AVAIL(midi_out_buf[dev]))
 				{
+					int ok;
 					int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head];
 
 					restore_flags(flags);	/* Give some time to others */
 					ok = midi_devs[dev]->outputc(dev, c);
 					cli();
+					if (!ok)
+						break;
 					midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
 					midi_out_buf[dev]->len--;
 				}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/sb_card.c linux-2.4.21/drivers/sound/sb_card.c
--- linux-2.4.20/drivers/sound/sb_card.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/sound/sb_card.c	2002-12-18 18:58:10.000000000 +0000
@@ -17,7 +17,7 @@
  *  CMI 8330 support - Alessandro Zummo <azummo@ita.flashnet.it>
  *
  * 18-01-2000 Separated sb_card and sb_common
- *  Jeff Garzik <jgarzik@mandrakesoft.com>
+ *  Jeff Garzik <jgarzik@pobox.com>
  *
  * 04-02-2000 Added Soundblaster AWE 64 PnP support, isapnpjump
  *  Alessandro Zummo <azummo@ita.flashnet.it>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/sb_common.c linux-2.4.21/drivers/sound/sb_common.c
--- linux-2.4.20/drivers/sound/sb_common.c	2001-09-30 19:26:08.000000000 +0000
+++ linux-2.4.21/drivers/sound/sb_common.c	2002-12-18 18:58:02.000000000 +0000
@@ -17,7 +17,7 @@
  * (fokkensr@vertis.nl)	 Which means: You can adjust the recording levels.
  *
  * 2000/01/18 - separated sb_card and sb_common -
- * Jeff Garzik <jgarzik@mandrakesoft.com>
+ * Jeff Garzik <jgarzik@pobox.com>
  *
  * 2000/09/18 - got rid of attach_uart401
  * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/trident.c linux-2.4.21/drivers/sound/trident.c
--- linux-2.4.20/drivers/sound/trident.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/sound/trident.c	2002-12-18 18:58:11.000000000 +0000
@@ -3936,9 +3936,11 @@
 		wReg = ali_ac97_get(card, 0, AC97_POWER_CONTROL);
 		if((wReg & 0x000f) == 0x000f)
 			return 0;
-		udelay(500);
+		udelay(5000);
 	}
-	return 0;
+
+	printk(KERN_ERR "ALi 5451 did not come out of reset.\n");
+	return 1;
 }
 
 /* AC97 codec initialisation. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/CDCEther.c linux-2.4.21/drivers/usb/CDCEther.c
--- linux-2.4.20/drivers/usb/CDCEther.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/CDCEther.c	2002-12-18 18:58:02.000000000 +0000
@@ -313,7 +313,7 @@
 	// into an integer number of USB packets, we force it to send one 
 	// more byte so the device will get a runt USB packet signalling the 
 	// end of the ethernet frame
-	if ( (skb->len) ^ (ether_dev->data_ep_out_size) ) {
+	if ( skb->len % ether_dev->data_ep_out_size) {
 		// It was not an exact multiple
 		// no need to add anything extra
 		count = skb->len;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/Config.in linux-2.4.21/drivers/usb/Config.in
--- linux-2.4.20/drivers/usb/Config.in	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/Config.in	2002-12-18 18:58:07.000000000 +0000
@@ -15,7 +15,6 @@
    else
       define_bool CONFIG_USB_BANDWIDTH n
    fi
-   bool '  Long timeout for slow-responding devices (some MGE Ellipse UPSes)' CONFIG_USB_LONG_TIMEOUT
 
    comment 'USB Host Controller Drivers'
    source drivers/usb/hcd/Config.in
@@ -32,8 +31,14 @@
    comment 'USB Device Class drivers'
    dep_tristate '  USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
    dep_tristate '    EMI 2|6 USB Audio interface support' CONFIG_USB_EMI26 $CONFIG_USB_AUDIO
-   dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL
-   dep_tristate '  USB MIDI support' CONFIG_USB_MIDI $CONFIG_USB
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      if [ "$CONFIG_BLUEZ" = "n" ]; then
+         dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB
+      else
+         comment '  USB Bluetooth can only be used with disabled Bluetooth subsystem'
+      fi
+   fi
+   dep_tristate '  USB MIDI support' CONFIG_USB_MIDI $CONFIG_USB $CONFIG_SOUND
    if [ "$CONFIG_SCSI" = "n" ]; then
       comment '  SCSI support is needed for USB Storage'
    fi
@@ -63,6 +68,7 @@
    fi
    dep_tristate '  Aiptek 6000U/8000U tablet support' CONFIG_USB_AIPTEK $CONFIG_USB $CONFIG_INPUT
    dep_tristate '  Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT
+   dep_tristate '  Griffin Technology PowerMate support' CONFIG_USB_POWERMATE $CONFIG_USB $CONFIG_INPUT
 
    comment 'USB Imaging devices'
    dep_tristate '  USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
@@ -94,7 +100,7 @@
       dep_tristate '  USB KLSI KL5USB101-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_KAWETH $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
       dep_tristate '  USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CATC $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
       dep_tristate '  USB Communication Class Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CDCETHER $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
-      dep_tristate '  USB-to-USB Networking cable device support (EXPERIMENTAL)' CONFIG_USB_USBNET $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+      dep_tristate '  USB-to-USB Networking cables, Linux PDAs, ... (EXPERIMENTAL)' CONFIG_USB_USBNET $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
    fi
 
    comment 'USB port drivers'
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/Makefile linux-2.4.21/drivers/usb/Makefile
--- linux-2.4.20/drivers/usb/Makefile	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/Makefile	2002-12-18 18:58:07.000000000 +0000
@@ -64,6 +64,7 @@
 obj-$(CONFIG_USB_KBD)		+= usbkbd.o
 obj-$(CONFIG_USB_AIPTEK)	+= aiptek.o
 obj-$(CONFIG_USB_WACOM)		+= wacom.o
+obj-$(CONFIG_USB_POWERMATE)	+= powermate.o
 
 obj-$(CONFIG_USB_SCANNER)	+= scanner.o
 obj-$(CONFIG_USB_ACM)		+= acm.o
@@ -77,7 +78,7 @@
 obj-$(CONFIG_USB_MDC800)	+= mdc800.o
 obj-$(CONFIG_USB_USS720)	+= uss720.o
 obj-$(CONFIG_USB_DABUSB)	+= dabusb.o
-obj-$(CONFIG_USB_VICAM)		+= vicam.o
+obj-$(CONFIG_USB_VICAM)		+= vicam.o usbvideo.o
 obj-$(CONFIG_USB_OV511)		+= ov511.o
 obj-$(CONFIG_USB_SE401)		+= se401.o
 obj-$(CONFIG_USB_STV680)	+= stv680.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/devio.c linux-2.4.21/drivers/usb/devio.c
--- linux-2.4.20/drivers/usb/devio.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/devio.c	2002-12-18 18:58:09.000000000 +0000
@@ -50,6 +50,7 @@
         struct dev_state *ps;
 	struct task_struct *task;
 	unsigned int signr;
+	unsigned int intf;
 	void *userbuffer;
         void *userurb;
         struct urb urb;
@@ -204,8 +205,7 @@
         unsigned long flags;
         
         spin_lock_irqsave(&ps->lock, flags);
-        list_del(&as->asynclist);
-        INIT_LIST_HEAD(&as->asynclist);
+        list_del_init(&as->asynclist);
         spin_unlock_irqrestore(&ps->lock, flags);
 }
 
@@ -217,8 +217,7 @@
         spin_lock_irqsave(&ps->lock, flags);
         if (!list_empty(&ps->async_completed)) {
                 as = list_entry(ps->async_completed.next, struct async, asynclist);
-                list_del(&as->asynclist);
-                INIT_LIST_HEAD(&as->asynclist);
+                list_del_init(&as->asynclist);
         }
         spin_unlock_irqrestore(&ps->lock, flags);
         return as;
@@ -228,19 +227,14 @@
 {
         unsigned long flags;
         struct async *as;
-        struct list_head *p;
 
         spin_lock_irqsave(&ps->lock, flags);
-        for (p = ps->async_pending.next; p != &ps->async_pending; ) {
-                as = list_entry(p, struct async, asynclist);
-                p = p->next;
-                if (as->userurb != userurb)
-                        continue;
-                list_del(&as->asynclist);
-                INIT_LIST_HEAD(&as->asynclist);
-                spin_unlock_irqrestore(&ps->lock, flags);
-                return as;
-        }
+	list_for_each_entry(as, &ps->async_pending, asynclist)
+		if (as->userurb == userurb) {
+			list_del_init(&as->asynclist);
+			spin_unlock_irqrestore(&ps->lock, flags);
+			return as;
+		}
         spin_unlock_irqrestore(&ps->lock, flags);
         return NULL;
 }
@@ -252,8 +246,7 @@
 	struct siginfo sinfo;
 
         spin_lock(&ps->lock);
-        list_del(&as->asynclist);
-        list_add_tail(&as->asynclist, &ps->async_completed);
+        list_move_tail(&as->asynclist, &ps->async_completed);
         spin_unlock(&ps->lock);
         wake_up(&ps->wait);
 	if (as->signr) {
@@ -265,24 +258,42 @@
 	}
 }
 
-static void destroy_all_async(struct dev_state *ps)
+static void destroy_async (struct dev_state *ps, struct list_head *list)
 {
-        struct async *as;
-        unsigned long flags;
+	struct async *as;
+	unsigned long flags;
 
-        spin_lock_irqsave(&ps->lock, flags);
-        while (!list_empty(&ps->async_pending)) {
-                as = list_entry(ps->async_pending.next, struct async, asynclist);
-                list_del(&as->asynclist);
-                INIT_LIST_HEAD(&as->asynclist);
-                spin_unlock_irqrestore(&ps->lock, flags);
-                /* usb_unlink_urb calls the completion handler with status == USB_ST_URB_KILLED */
-                usb_unlink_urb(&as->urb);
-                spin_lock_irqsave(&ps->lock, flags);
-        }
-        spin_unlock_irqrestore(&ps->lock, flags);
-        while ((as = async_getcompleted(ps)))
-                free_async(as);
+	spin_lock_irqsave(&ps->lock, flags);
+	while (!list_empty(list)) {
+		as = list_entry(list->next, struct async, asynclist);
+		list_del_init(&as->asynclist);
+		spin_unlock_irqrestore(&ps->lock, flags);
+		/* usb_unlink_urb calls the completion handler with status == USB_ST_URB_KILLED */
+		usb_unlink_urb(&as->urb);
+		spin_lock_irqsave(&ps->lock, flags);
+	}
+	spin_unlock_irqrestore(&ps->lock, flags);
+	while ((as = async_getcompleted(ps)))
+		free_async(as);
+}
+
+static void destroy_async_on_interface (struct dev_state *ps, unsigned int intf)
+{
+	struct list_head *p, *q, hitlist;
+	unsigned long flags;
+
+	INIT_LIST_HEAD(&hitlist);
+	spin_lock_irqsave(&ps->lock, flags);
+	list_for_each_safe(p, q, &ps->async_pending)
+		if (intf == list_entry(p, struct async, asynclist)->intf)
+			list_move_tail(p, &hitlist);
+	spin_unlock_irqrestore(&ps->lock, flags);
+	destroy_async(ps, &hitlist);
+}
+
+static inline void destroy_all_async(struct dev_state *ps)
+{
+	destroy_async(ps, &ps->async_pending);
 }
 
 /*
@@ -519,8 +530,7 @@
 	unsigned int i;
 
 	lock_kernel();
-	list_del(&ps->list);
-	INIT_LIST_HEAD(&ps->list);
+	list_del_init(&ps->list);
 	if (ps->dev) {
 		for (i = 0; ps->ifclaimed && i < 8*sizeof(ps->ifclaimed); i++)
 			if (test_bit(i, &ps->ifclaimed))
@@ -775,6 +785,7 @@
 	struct usb_ctrlrequest *dr = NULL;
 	unsigned int u, totlen, isofrmlen;
 	int ret;
+	int intf = -1;
 
 	if (copy_from_user(&uurb, arg, sizeof(uurb)))
 		return -EFAULT;
@@ -786,9 +797,9 @@
 	if (uurb.signr != 0 && (uurb.signr < SIGRTMIN || uurb.signr > SIGRTMAX))
 		return -EINVAL;
 	if (!(uurb.type == USBDEVFS_URB_TYPE_CONTROL && (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
-		if ((ret = findintfep(ps->dev, uurb.endpoint)) < 0)
-			return ret;
-		if ((ret = checkintf(ps, ret)))
+		if ((intf = findintfep(ps->dev, uurb.endpoint)) < 0)
+			return intf;
+		if ((ret = checkintf(ps, intf)))
 			return ret;
 	}
 	switch(uurb.type) {
@@ -909,6 +920,7 @@
 	else
 		as->userbuffer = NULL;
 	as->signr = uurb.signr;
+	as->intf = intf;
 	as->task = current;
 	if (!(uurb.endpoint & USB_DIR_IN)) {
 		if (copy_from_user(as->urb.transfer_buffer, uurb.buffer, as->urb.transfer_buffer_length)) {
@@ -1054,7 +1066,10 @@
 		return -EFAULT;
 	if ((ret = findintfif(ps->dev, intf)) < 0)
 		return ret;
-	return releaseintf(ps, intf);
+	if ((ret = releaseintf(ps, intf)) < 0)
+		return ret;
+	destroy_async_on_interface (ps, intf);
+	return 0;
 }
 
 static int proc_ioctl (struct dev_state *ps, void *arg)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hc_sl811.c linux-2.4.21/drivers/usb/hc_sl811.c
--- linux-2.4.20/drivers/usb/hc_sl811.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/hc_sl811.c	2002-12-18 18:58:07.000000000 +0000
@@ -28,7 +28,7 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hcd/ehci-dbg.c linux-2.4.21/drivers/usb/hcd/ehci-dbg.c
--- linux-2.4.20/drivers/usb/hcd/ehci-dbg.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/usb/hcd/ehci-dbg.c	2002-12-18 18:58:09.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001 by David Brownell
+ * Copyright (c) 2001-2002 by David Brownell
  * 
  * 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
@@ -26,8 +26,10 @@
 
 #ifdef	DEBUG
 
-/* check the values in the HCSPARAMS register - host controller structural parameters */
-/* see EHCI 0.95 Spec, Table 2-4 for each value */
+/* check the values in the HCSPARAMS register
+ * (host controller _Structural_ parameters)
+ * see EHCI spec, Table 2-4 for each value
+ */
 static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
 {
 	u32	params = readl (&ehci->caps->hcs_params);
@@ -55,7 +57,7 @@
 			strcat(buf, tmp);
 		}
 		dbg ("%s: %s portroute %s", 
-			ehci->hcd.bus_name, label,
+			hcd_to_bus (&ehci->hcd)->bus_name, label,
 			buf);
 	}
 }
@@ -67,25 +69,27 @@
 
 #ifdef	DEBUG
 
-/* check the values in the HCCPARAMS register - host controller capability parameters */
-/* see EHCI 0.95 Spec, Table 2-5 for each value */
+/* check the values in the HCCPARAMS register
+ * (host controller _Capability_ parameters)
+ * see EHCI Spec, Table 2-5 for each value
+ * */
 static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
 {
 	u32	params = readl (&ehci->caps->hcc_params);
 
 	if (HCC_EXT_CAPS (params)) {
 		// EHCI 0.96 ... could interpret these (legacy?)
-		dbg ("%s extended capabilities at pci %d",
+		dbg ("%s extended capabilities at pci %2x",
 			label, HCC_EXT_CAPS (params));
 	}
 	if (HCC_ISOC_CACHE (params)) {
-		dbg ("%s hcc_params 0x%04x caching frame %s%s%s",
+		dbg ("%s hcc_params %04x caching frame %s%s%s",
 		     label, params,
 		     HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
 		     HCC_CANPARK (params) ? " park" : "",
 		     HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
 	} else {
-		dbg ("%s hcc_params 0x%04x caching %d uframes %s%s%s",
+		dbg ("%s hcc_params %04x caching %d uframes %s%s%s",
 		     label,
 		     params,
 		     HCC_ISOC_THRES (params),
@@ -102,8 +106,8 @@
 
 #ifdef	DEBUG
 
-#if 0
-static void dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
+static void __attribute__((__unused__))
+dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
 	dbg ("%s %p info1 %x info2 %x hw_curr %x qtd_next %x", label,
 		qh, qh->hw_info1, qh->hw_info2,
@@ -117,63 +121,462 @@
 			qh->hw_buf [4]);
 	}
 }
-#endif
+
+static int __attribute__((__unused__))
+dbg_status_buf (char *buf, unsigned len, char *label, u32 status)
+{
+	return snprintf (buf, len,
+		"%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s",
+		label, label [0] ? " " : "", status,
+		(status & STS_ASS) ? " Async" : "",
+		(status & STS_PSS) ? " Periodic" : "",
+		(status & STS_RECL) ? " Recl" : "",
+		(status & STS_HALT) ? " Halt" : "",
+		(status & STS_IAA) ? " IAA" : "",
+		(status & STS_FATAL) ? " FATAL" : "",
+		(status & STS_FLR) ? " FLR" : "",
+		(status & STS_PCD) ? " PCD" : "",
+		(status & STS_ERR) ? " ERR" : "",
+		(status & STS_INT) ? " INT" : ""
+		);
+}
+
+static int __attribute__((__unused__))
+dbg_intr_buf (char *buf, unsigned len, char *label, u32 enable)
+{
+	return snprintf (buf, len,
+		"%s%sintrenable %02x%s%s%s%s%s%s",
+		label, label [0] ? " " : "", enable,
+		(enable & STS_IAA) ? " IAA" : "",
+		(enable & STS_FATAL) ? " FATAL" : "",
+		(enable & STS_FLR) ? " FLR" : "",
+		(enable & STS_PCD) ? " PCD" : "",
+		(enable & STS_ERR) ? " ERR" : "",
+		(enable & STS_INT) ? " INT" : ""
+		);
+}
 
 static const char *const fls_strings [] =
     { "1024", "512", "256", "??" };
 
+static int dbg_command_buf (char *buf, unsigned len, char *label, u32 command)
+{
+	return snprintf (buf, len,
+		"%s%scommand %06x %s=%d ithresh=%d%s%s%s%s period=%s%s %s",
+		label, label [0] ? " " : "", command,
+		(command & CMD_PARK) ? "park" : "(park)",
+		CMD_PARK_CNT (command),
+		(command >> 16) & 0x3f,
+		(command & CMD_LRESET) ? " LReset" : "",
+		(command & CMD_IAAD) ? " IAAD" : "",
+		(command & CMD_ASE) ? " Async" : "",
+		(command & CMD_PSE) ? " Periodic" : "",
+		fls_strings [(command >> 2) & 0x3],
+		(command & CMD_RESET) ? " Reset" : "",
+		(command & CMD_RUN) ? "RUN" : "HALT"
+		);
+}
+
+static int
+dbg_port_buf (char *buf, unsigned len, char *label, int port, u32 status)
+{
+	char	*sig;
+
+	/* signaling state */
+	switch (status & (3 << 10)) {
+	case 0 << 10: sig = "se0"; break;
+	case 1 << 10: sig = "k"; break;		/* low speed */
+	case 2 << 10: sig = "j"; break;
+	default: sig = "?"; break;
+	}
+
+	return snprintf (buf, len,
+		"%s%sport %d status %06x%s%s sig=%s %s%s%s%s%s%s%s%s%s",
+		label, label [0] ? " " : "", port, status,
+		(status & PORT_POWER) ? " POWER" : "",
+		(status & PORT_OWNER) ? " OWNER" : "",
+		sig,
+		(status & PORT_RESET) ? " RESET" : "",
+		(status & PORT_SUSPEND) ? " SUSPEND" : "",
+		(status & PORT_RESUME) ? " RESUME" : "",
+		(status & PORT_OCC) ? " OCC" : "",
+		(status & PORT_OC) ? " OC" : "",
+		(status & PORT_PEC) ? " PEC" : "",
+		(status & PORT_PE) ? " PE" : "",
+		(status & PORT_CSC) ? " CSC" : "",
+		(status & PORT_CONNECT) ? " CONNECT" : ""
+	    );
+}
+
 #else
-#if 0
-static inline void dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) {}
-#endif
+static inline void __attribute__((__unused__))
+dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
+{}
+
+static inline int __attribute__((__unused__))
+dbg_status_buf (char *buf, unsigned len, char *label, u32 status)
+{ return 0; }
+
+static inline int __attribute__((__unused__))
+dbg_command_buf (char *buf, unsigned len, char *label, u32 command)
+{ return 0; }
+
+static inline int __attribute__((__unused__))
+dbg_intr_buf (char *buf, unsigned len, char *label, u32 enable)
+{ return 0; }
+
+static inline int __attribute__((__unused__))
+dbg_port_buf (char *buf, unsigned len, char *label, int port, u32 status)
+{ return 0; }
+
 #endif	/* DEBUG */
 
 /* functions have the "wrong" filename when they're output... */
+#define dbg_status(ehci, label, status) { \
+	char _buf [80]; \
+	dbg_status_buf (_buf, sizeof _buf, label, status); \
+	dbg ("%s", _buf); \
+}
+
+#define dbg_cmd(ehci, label, command) { \
+	char _buf [80]; \
+	dbg_command_buf (_buf, sizeof _buf, label, command); \
+	dbg ("%s", _buf); \
+}
+
+#define dbg_port(hcd, label, port, status) { \
+	char _buf [80]; \
+	dbg_port_buf (_buf, sizeof _buf, label, port, status); \
+	dbg ("%s", _buf); \
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef STUB_DEBUG_FILES
+
+static inline void create_debug_files (struct ehci_hcd *bus) { }
+static inline void remove_debug_files (struct ehci_hcd *bus) { }
+
+#else
+
+/* troubleshooting help: expose state in driverfs */
+
+#define speed_char(info1) ({ char tmp; \
+		switch (info1 & (3 << 12)) { \
+		case 0 << 12: tmp = 'f'; break; \
+		case 1 << 12: tmp = 'l'; break; \
+		case 2 << 12: tmp = 'h'; break; \
+		default: tmp = '?'; break; \
+		}; tmp; })
+
+static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep)
+{
+	u32			scratch;
+	struct list_head	*entry;
+	struct ehci_qtd		*td;
+	unsigned		temp;
+	unsigned		size = *sizep;
+	char			*next = *nextp;
+
+	scratch = cpu_to_le32p (&qh->hw_info1);
+	temp = snprintf (next, size, "qh/%p dev%d %cs ep%d %08x %08x",
+			qh, scratch & 0x007f,
+			speed_char (scratch),
+			(scratch >> 8) & 0x000f,
+			scratch, cpu_to_le32p (&qh->hw_info2));
+	size -= temp;
+	next += temp;
+
+	list_for_each (entry, &qh->qtd_list) {
+		td = list_entry (entry, struct ehci_qtd,
+				qtd_list);
+		scratch = cpu_to_le32p (&td->hw_token);
+		temp = snprintf (next, size,
+				"\n\ttd/%p %s len=%d %08x urb %p",
+				td, ({ char *tmp;
+				 switch ((scratch>>8)&0x03) {
+				 case 0: tmp = "out"; break;
+				 case 1: tmp = "in"; break;
+				 case 2: tmp = "setup"; break;
+				 default: tmp = "?"; break;
+				 } tmp;}),
+				(scratch >> 16) & 0x7fff,
+				scratch,
+				td->urb);
+		size -= temp;
+		next += temp;
+	}
+
+	temp = snprintf (next, size, "\n");
+	*sizep = size - temp;
+	*nextp = next + temp;
+}
+
+static ssize_t
+show_async (struct device *dev, char *buf, size_t count, loff_t off)
+{
+	struct pci_dev		*pdev;
+	struct ehci_hcd		*ehci;
+	unsigned long		flags;
+	unsigned		temp, size;
+	char			*next;
+	struct ehci_qh		*qh;
+
+	if (off != 0)
+		return 0;
+
+	pdev = container_of (dev, struct pci_dev, dev);
+	ehci = container_of (pci_get_drvdata (pdev), struct ehci_hcd, hcd);
+	next = buf;
+	size = count;
+
+	/* dumps a snapshot of the async schedule.
+	 * usually empty except for long-term bulk reads, or head.
+	 * one QH per line, and TDs we know about
+	 */
+	spin_lock_irqsave (&ehci->lock, flags);
+	if (ehci->async) {
+		qh = ehci->async;
+		do {
+			qh_lines (qh, &next, &size);
+		} while ((qh = qh->qh_next.qh) != ehci->async);
+	}
+	if (ehci->reclaim) {
+		temp = snprintf (next, size, "\nreclaim =\n");
+		size -= temp;
+		next += temp;
+
+		qh_lines (ehci->reclaim, &next, &size);
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+
+	return count - size;
+}
+static DEVICE_ATTR (async, S_IRUGO, show_async, NULL);
+
+#define DBG_SCHED_LIMIT 64
+
+static ssize_t
+show_periodic (struct device *dev, char *buf, size_t count, loff_t off)
+{
+	struct pci_dev		*pdev;
+	struct ehci_hcd		*ehci;
+	unsigned long		flags;
+	union ehci_shadow	p, *seen;
+	unsigned		temp, size, seen_count;
+	char			*next;
+	unsigned		i, tag;
+
+	if (off != 0)
+		return 0;
+	if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, SLAB_ATOMIC)))
+		return 0;
+	seen_count = 0;
+
+	pdev = container_of (dev, struct pci_dev, dev);
+	ehci = container_of (pci_get_drvdata (pdev), struct ehci_hcd, hcd);
+	next = buf;
+	size = count;
+
+	temp = snprintf (next, size, "size = %d\n", ehci->periodic_size);
+	size -= temp;
+	next += temp;
+
+	/* dump a snapshot of the periodic schedule.
+	 * iso changes, interrupt usually doesn't.
+	 */
+	spin_lock_irqsave (&ehci->lock, flags);
+	for (i = 0; i < ehci->periodic_size; i++) {
+		p = ehci->pshadow [i];
+		if (!p.ptr)
+			continue;
+		tag = Q_NEXT_TYPE (ehci->periodic [i]);
+
+		temp = snprintf (next, size, "%4d: ", i);
+		size -= temp;
+		next += temp;
+
+		do {
+			switch (tag) {
+			case Q_TYPE_QH:
+				temp = snprintf (next, size, " qh%d/%p",
+						p.qh->period, p.qh);
+				size -= temp;
+				next += temp;
+				for (temp = 0; temp < seen_count; temp++) {
+					if (seen [temp].ptr == p.ptr)
+						break;
+				}
+				/* show more info the first time around */
+				if (temp == seen_count) {
+					u32	scratch = cpu_to_le32p (
+							&p.qh->hw_info1);
+
+					temp = snprintf (next, size,
+						" (%cs dev%d ep%d [%d/%d] %d)",
+						speed_char (scratch),
+						scratch & 0x007f,
+						(scratch >> 8) & 0x000f,
+						p.qh->usecs, p.qh->c_usecs,
+						scratch >> 16);
+
+					/* FIXME TD info too */
+
+					if (seen_count < DBG_SCHED_LIMIT)
+						seen [seen_count++].qh = p.qh;
+				} else
+					temp = 0;
+				tag = Q_NEXT_TYPE (p.qh->hw_next);
+				p = p.qh->qh_next;
+				break;
+			case Q_TYPE_FSTN:
+				temp = snprintf (next, size,
+					" fstn-%8x/%p", p.fstn->hw_prev,
+					p.fstn);
+				tag = Q_NEXT_TYPE (p.fstn->hw_next);
+				p = p.fstn->fstn_next;
+				break;
+			case Q_TYPE_ITD:
+				temp = snprintf (next, size,
+					" itd/%p", p.itd);
+				tag = Q_NEXT_TYPE (p.itd->hw_next);
+				p = p.itd->itd_next;
+				break;
+			case Q_TYPE_SITD:
+				temp = snprintf (next, size,
+					" sitd/%p", p.sitd);
+				tag = Q_NEXT_TYPE (p.sitd->hw_next);
+				p = p.sitd->sitd_next;
+				break;
+			}
+			size -= temp;
+			next += temp;
+		} while (p.ptr);
+
+		temp = snprintf (next, size, "\n");
+		size -= temp;
+		next += temp;
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	kfree (seen);
+
+	return count - size;
+}
+static DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL);
+
+#undef DBG_SCHED_LIMIT
+
+static ssize_t
+show_registers (struct device *dev, char *buf, size_t count, loff_t off)
+{
+	struct pci_dev		*pdev;
+	struct ehci_hcd		*ehci;
+	unsigned long		flags;
+	unsigned		temp, size, i;
+	char			*next, scratch [80];
+	static char		fmt [] = "%*s\n";
+	static char		label [] = "";
+
+	if (off != 0)
+		return 0;
+
+	pdev = container_of (dev, struct pci_dev, dev);
+	ehci = container_of (pci_get_drvdata (pdev), struct ehci_hcd, hcd);
+
+	next = buf;
+	size = count;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	/* Capability Registers */
+	i = readw (&ehci->caps->hci_version);
+	temp = snprintf (next, size, "EHCI %x.%02x, hcd state %d\n",
+		i >> 8, i & 0x0ff, ehci->hcd.state);
+	size -= temp;
+	next += temp;
+
+	// FIXME interpret both types of params
+	i = readl (&ehci->caps->hcs_params);
+	temp = snprintf (next, size, "structural params 0x%08x\n", i);
+	size -= temp;
+	next += temp;
+
+	i = readl (&ehci->caps->hcc_params);
+	temp = snprintf (next, size, "capability params 0x%08x\n", i);
+	size -= temp;
+	next += temp;
+
+	/* Operational Registers */
+	temp = dbg_status_buf (scratch, sizeof scratch, label,
+			readl (&ehci->regs->status));
+	temp = snprintf (next, size, fmt, temp, scratch);
+	size -= temp;
+	next += temp;
+
+	temp = dbg_command_buf (scratch, sizeof scratch, label,
+			readl (&ehci->regs->command));
+	temp = snprintf (next, size, fmt, temp, scratch);
+	size -= temp;
+	next += temp;
+
+	temp = dbg_intr_buf (scratch, sizeof scratch, label,
+			readl (&ehci->regs->intr_enable));
+	temp = snprintf (next, size, fmt, temp, scratch);
+	size -= temp;
+	next += temp;
+
+	temp = snprintf (next, size, "uframe %04x\n",
+			readl (&ehci->regs->frame_index));
+	size -= temp;
+	next += temp;
+
+	for (i = 0; i < HCS_N_PORTS (ehci->hcs_params); i++) {
+		temp = dbg_port_buf (scratch, sizeof scratch, label, i,
+				readl (&ehci->regs->port_status [i]));
+		temp = snprintf (next, size, fmt, temp, scratch);
+		size -= temp;
+		next += temp;
+	}
+
+	if (ehci->reclaim) {
+		temp = snprintf (next, size, "reclaim qh %p%s\n",
+				ehci->reclaim,
+				ehci->reclaim_ready ? " ready" : "");
+		size -= temp;
+		next += temp;
+	}
+
+#ifdef EHCI_STATS
+	temp = snprintf (next, size, "irq normal %ld err %ld reclaim %ld\n",
+		ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim);
+	size -= temp;
+	next += temp;
+
+	temp = snprintf (next, size, "complete %ld unlink %ld qpatch %ld\n",
+		ehci->stats.complete, ehci->stats.unlink, ehci->stats.qpatch);
+	size -= temp;
+	next += temp;
+#endif
+
+	spin_unlock_irqrestore (&ehci->lock, flags);
+
+	return count - size;
+}
+static DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
+
+static inline void create_debug_files (struct ehci_hcd *bus)
+{
+	device_create_file (&bus->hcd.pdev->dev, &dev_attr_async);
+	device_create_file (&bus->hcd.pdev->dev, &dev_attr_periodic);
+	device_create_file (&bus->hcd.pdev->dev, &dev_attr_registers);
+}
+
+static inline void remove_debug_files (struct ehci_hcd *bus)
+{
+	device_remove_file (&bus->hcd.pdev->dev, &dev_attr_async);
+	device_remove_file (&bus->hcd.pdev->dev, &dev_attr_periodic);
+	device_remove_file (&bus->hcd.pdev->dev, &dev_attr_registers);
+}
 
-#define dbg_status(ehci, label, status) \
-	dbg ("%s status 0x%x%s%s%s%s%s%s%s%s%s%s", \
-		label, status, \
-		(status & STS_ASS) ? " Async" : "", \
-		(status & STS_PSS) ? " Periodic" : "", \
-		(status & STS_RECL) ? " Recl" : "", \
-		(status & STS_HALT) ? " Halt" : "", \
-		(status & STS_IAA) ? " IAA" : "", \
-		(status & STS_FATAL) ? " FATAL" : "", \
-		(status & STS_FLR) ? " FLR" : "", \
-		(status & STS_PCD) ? " PCD" : "", \
-		(status & STS_ERR) ? " ERR" : "", \
-		(status & STS_INT) ? " INT" : "" \
-		)
-
-#define dbg_cmd(ehci, label, command) \
-	dbg ("%s %x cmd %s=%d ithresh=%d%s%s%s%s period=%s%s %s", \
-		label, command, \
-		(command & CMD_PARK) ? "park" : "(park)", \
-		CMD_PARK_CNT (command), \
-		(command >> 16) & 0x3f, \
-		(command & CMD_LRESET) ? " LReset" : "", \
-		(command & CMD_IAAD) ? " IAAD" : "", \
-		(command & CMD_ASE) ? " Async" : "", \
-		(command & CMD_PSE) ? " Periodic" : "", \
-		fls_strings [(command >> 2) & 0x3], \
-		(command & CMD_RESET) ? " Reset" : "", \
-		(command & CMD_RUN) ? "RUN" : "HALT" \
-		)
-
-#define dbg_port(hcd, label, port, status) \
-	dbg ("%s port %d status 0x%x%s%s speed=%d%s%s%s%s%s%s%s%s%s", \
-		label, port, status, \
-		(status & PORT_OWNER) ? " OWNER" : "", \
-		(status & PORT_POWER) ? " POWER" : "", \
-		(status >> 10) & 3, \
-		(status & PORT_RESET) ? " RESET" : "", \
-		(status & PORT_SUSPEND) ? " SUSPEND" : "", \
-		(status & PORT_RESUME) ? " RESUME" : "", \
-		(status & PORT_OCC) ? " OCC" : "", \
-		(status & PORT_OC) ? " OC" : "", \
-		(status & PORT_PEC) ? " PEC" : "", \
-		(status & PORT_PE) ? " PE" : "", \
-		(status & PORT_CSC) ? " CSC" : "", \
-		(status & PORT_CONNECT) ? " CONNECT" : "" \
-	    )
+#endif /* STUB_DEBUG_FILES */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hcd/ehci-hcd.c linux-2.4.21/drivers/usb/hcd/ehci-hcd.c
--- linux-2.4.20/drivers/usb/hcd/ehci-hcd.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/hcd/ehci-hcd.c	2002-12-18 18:58:08.000000000 +0000
@@ -38,7 +38,13 @@
 #endif
 
 #include <linux/usb.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,32)
 #include "../hcd.h"
+#else
+#include "../core/hcd.h"
+#endif
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -46,8 +52,6 @@
 #include <asm/system.h>
 #include <asm/unaligned.h>
 
-//#undef KERN_DEBUG
-//#define KERN_DEBUG ""
 
 /*-------------------------------------------------------------------------*/
 
@@ -55,21 +59,24 @@
  * EHCI hc_driver implementation ... experimental, incomplete.
  * Based on the final 1.0 register interface specification.
  *
- * There are lots of things to help out with here ... notably
- * everything "periodic", and of course testing with all sorts
- * of usb 2.0 devices and configurations.
- *
  * USB 2.0 shows up in upcoming www.pcmcia.org technology.
  * First was PCMCIA, like ISA; then CardBus, which is PCI.
  * Next comes "CardBay", using USB 2.0 signals.
  *
- * Contains additional contributions by:
- *	Brad Hards
- *	Rory Bolt
- *	...
+ * Contains additional contributions by: Brad Hards, Rory Bolt, and more.
+ * Special thanks to Intel and VIA for providing host controllers to
+ * test this driver on, and Cypress (including In-System Design) for
+ * providing early devices for those host controllers to talk to!
  *
  * HISTORY:
  *
+ * 2002-08-06	Handling for bulk and interrupt transfers is mostly shared;
+ *	only scheduling is different, no arbitrary limitations.
+ * 2002-07-25	Sanity check PCI reads, mostly for better cardbus support,
+ * 	clean up HC run state handshaking.
+ * 2002-05-24	Preliminary FS/LS interrupts, using scheduling shortcuts
+ * 2002-05-11	Clear TT errors for FS/LS ctrl/bulk.  Fill in some other
+ *	missing pieces:  enabling 64bit dma, handoff from BIOS/SMM.
  * 2002-05-07	Some error path cleanups to report better errors; wmb();
  *	use non-CVS version id; better iso bandwidth claim.
  * 2002-04-19	Control/bulk/interrupt submit no longer uses giveback() on
@@ -85,14 +92,22 @@
  * 2001-June	Works with usb-storage and NEC EHCI on 2.4
  */
 
-#define DRIVER_VERSION "2002-May-07"
+#define DRIVER_VERSION "2002-Sep-23"
 #define DRIVER_AUTHOR "David Brownell"
 #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
 
+static const char	hcd_name [] = "ehci-hcd";
+
 
 // #define EHCI_VERBOSE_DEBUG
 // #define have_split_iso
 
+#ifdef DEBUG
+#define EHCI_STATS
+#endif
+
+#define INTR_AUTOMAGIC		/* to be removed later in 2.5 */
+
 /* magic numbers that can affect system performance */
 #define	EHCI_TUNE_CERR		3	/* 0-3 qtd retries; 0 == don't stop */
 #define	EHCI_TUNE_RL_HS		0	/* nak throttle; see 4.9 */
@@ -100,11 +115,20 @@
 #define	EHCI_TUNE_MULT_HS	1	/* 1-3 transactions/uframe; 4.10.3 */
 #define	EHCI_TUNE_MULT_TT	1
 
+#define EHCI_WATCHDOG_JIFFIES	(HZ/100)	/* arbitrary; ~10 msec */
+#define EHCI_ASYNC_JIFFIES	(HZ/3)		/* async idle timeout */
+
 /* Initial IRQ latency:  lower than default */
 static int log2_irq_thresh = 0;		// 0 to 6
 MODULE_PARM (log2_irq_thresh, "i");
 MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
 
+/* allow irqs at least every N URB completions */
+static int max_completions = 16;
+MODULE_PARM (max_completions, "i");
+MODULE_PARM_DESC (max_completions,
+		"limit for urb completions called with irqs disenabled");
+
 #define	INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT)
 
 /*-------------------------------------------------------------------------*/
@@ -115,42 +139,105 @@
 /*-------------------------------------------------------------------------*/
 
 /*
+ * handshake - spin reading hc until handshake completes or fails
+ * @ptr: address of hc register to be read
+ * @mask: bits to look at in result of read
+ * @done: value of those bits when handshake succeeds
+ * @usec: timeout in microseconds
+ *
+ * Returns negative errno, or zero on success
+ *
+ * Success happens when the "mask" bits have the specified value (hardware
+ * handshake done).  There are two failure modes:  "usec" have passed (major
+ * hardware flakeout), or the register reads as all-ones (hardware removed).
+ *
+ * That last failure should_only happen in cases like physical cardbus eject
+ * before driver shutdown. But it also seems to be caused by bugs in cardbus
+ * bridge shutdown:  shutting down the bridge before the devices using it.
+ */
+static int handshake (u32 *ptr, u32 mask, u32 done, int usec)
+{
+	u32	result;
+
+	do {
+		result = readl (ptr);
+		if (result == ~(u32)0)		/* card removed */
+			return -ENODEV;
+		result &= mask;
+		if (result == done)
+			return 0;
+		udelay (1);
+		usec--;
+	} while (usec > 0);
+	return -ETIMEDOUT;
+}
+
+/*
  * hc states include: unknown, halted, ready, running
  * transitional states are messy just now
  * trying to avoid "running" unless urbs are active
  * a "ready" hc can be finishing prefetched work
  */
 
-/* halt a non-running controller */
-static void ehci_reset (struct ehci_hcd *ehci)
+/* force HC to halt state from unknown (EHCI spec section 2.3) */
+static int ehci_halt (struct ehci_hcd *ehci)
+{
+	u32	temp = readl (&ehci->regs->status);
+
+	if ((temp & STS_HALT) != 0)
+		return 0;
+
+	temp = readl (&ehci->regs->command);
+	temp &= ~CMD_RUN;
+	writel (temp, &ehci->regs->command);
+	return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125);
+}
+
+/* reset a non-running (STS_HALT == 1) controller */
+static int ehci_reset (struct ehci_hcd *ehci)
 {
 	u32	command = readl (&ehci->regs->command);
 
 	command |= CMD_RESET;
 	dbg_cmd (ehci, "reset", command);
 	writel (command, &ehci->regs->command);
-	while (readl (&ehci->regs->command) & CMD_RESET)
-		continue;
 	ehci->hcd.state = USB_STATE_HALT;
+	return handshake (&ehci->regs->command, CMD_RESET, 0, 250);
 }
 
 /* idle the controller (from running) */
 static void ehci_ready (struct ehci_hcd *ehci)
 {
-	u32	command;
+	u32	temp;
 
 #ifdef DEBUG
 	if (!HCD_IS_RUNNING (ehci->hcd.state))
 		BUG ();
 #endif
 
-	while (!(readl (&ehci->regs->status) & (STS_ASS | STS_PSS)))
-		udelay (100);
-	command = readl (&ehci->regs->command);
-	command &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
-	writel (command, &ehci->regs->command);
+	/* wait for any schedule enables/disables to take effect */
+	temp = 0;
+	if (ehci->async)
+		temp = STS_ASS;
+	if (ehci->next_uframe != -1)
+		temp |= STS_PSS;
+	if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+				temp, 16 * 125) != 0) {
+		ehci->hcd.state = USB_STATE_HALT;
+		return;
+	}
+
+	/* then disable anything that's still active */
+	temp = readl (&ehci->regs->command);
+	temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
+	writel (temp, &ehci->regs->command);
 
-	// hardware can take 16 microframes to turn off ...
+	/* hardware can take 16 microframes to turn off ... */
+	if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+				0, 16 * 125) != 0) {
+		ehci->hcd.state = USB_STATE_HALT;
+		return;
+	}
 	ehci->hcd.state = USB_STATE_READY;
 }
 
@@ -165,6 +252,52 @@
 
 static void ehci_tasklet (unsigned long param);
 
+static void ehci_irq (struct usb_hcd *hcd);
+
+static void ehci_watchdog (unsigned long param)
+{
+	struct ehci_hcd		*ehci = (struct ehci_hcd *) param;
+	unsigned long		flags;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	/* guard against lost IAA, which wedges everything */
+	ehci_irq (&ehci->hcd);
+ 	/* unlink the last qh after it's idled a while */
+ 	if (ehci->async_idle) {
+ 		start_unlink_async (ehci, ehci->async);
+ 		ehci->async_idle = 0;
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+}
+
+/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/...
+ * off the controller (maybe it can boot from highspeed USB disks).
+ */
+static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap)
+{
+	if (cap & (1 << 16)) {
+		int msec = 500;
+
+		/* request handoff to OS */
+		cap &= 1 << 24;
+		pci_write_config_dword (ehci->hcd.pdev, where, cap);
+
+		/* and wait a while for it to happen */
+		do {
+			wait_ms (10);
+			msec -= 10;
+			pci_read_config_dword (ehci->hcd.pdev, where, &cap);
+		} while ((cap & (1 << 16)) && msec);
+		if (cap & (1 << 16)) {
+			info ("BIOS handoff failed (%d, %04x)", where, cap);
+			return 1;
+		} 
+		dbg ("BIOS handoff succeeded");
+	} else
+		dbg ("BIOS handoff not needed");
+	return 0;
+}
+
 /* called by khubd or root hub init threads */
 
 static int ehci_start (struct usb_hcd *hcd)
@@ -172,14 +305,11 @@
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	u32			temp;
 	struct usb_device	*udev;
+	struct usb_bus		*bus;
 	int			retval;
 	u32			hcc_params;
 	u8                      tempbyte;
 
-	// FIXME:  given EHCI 0.96 or later, and a controller with
-	// the USBLEGSUP/USBLEGCTLSTS extended capability, make sure
-	// the BIOS doesn't still own this controller.
-
 	spin_lock_init (&ehci->lock);
 
 	ehci->caps = (struct ehci_caps *) hcd->regs;
@@ -187,9 +317,37 @@
 	dbg_hcs_params (ehci, "ehci_start");
 	dbg_hcc_params (ehci, "ehci_start");
 
+	hcc_params = readl (&ehci->caps->hcc_params);
+
+	/* EHCI 0.96 and later may have "extended capabilities" */
+	temp = HCC_EXT_CAPS (hcc_params);
+	while (temp) {
+		u32		cap;
+
+		pci_read_config_dword (ehci->hcd.pdev, temp, &cap);
+		dbg ("capability %04x at %02x", cap, temp);
+		switch (cap & 0xff) {
+		case 1:			/* BIOS/SMM/... handoff */
+			if (bios_handoff (ehci, temp, cap) != 0)
+				return -EOPNOTSUPP;
+			break;
+		case 0:			/* illegal reserved capability */
+			warn ("illegal capability!");
+			cap = 0;
+			/* FALLTHROUGH */
+		default:		/* unknown */
+			break;
+		}
+		temp = (cap >> 8) & 0xff;
+	}
+
 	/* cache this readonly data; minimize PCI reads */
 	ehci->hcs_params = readl (&ehci->caps->hcs_params);
 
+	/* force HC to halt state */
+	if ((retval = ehci_halt (ehci)) != 0)
+		return retval;
+
 	/*
 	 * hw default: 1K periodic list heads, one per frame.
 	 * periodic_size can shrink by USBCMD update if hcc_params allows.
@@ -197,7 +355,6 @@
 	ehci->periodic_size = DEFAULT_I_TDPS;
 	if ((retval = ehci_mem_init (ehci, SLAB_KERNEL)) < 0)
 		return retval;
-	hcc_params = readl (&ehci->caps->hcc_params);
 
 	/* controllers may cache some of the periodic schedule ... */
 	if (HCC_ISOC_CACHE (hcc_params)) 	// full frame cache
@@ -212,8 +369,10 @@
 	/* controller state:  unknown --> reset */
 
 	/* EHCI spec section 4.1 */
-	// FIXME require STS_HALT before reset...
-	ehci_reset (ehci);
+	if ((retval = ehci_reset (ehci)) != 0) {
+		ehci_mem_cleanup (ehci);
+		return retval;
+	}
 	writel (INTR_MASK, &ehci->regs->intr_enable);
 	writel (ehci->periodic_dma, &ehci->regs->frame_list);
 
@@ -221,23 +380,25 @@
 	 * hcc_params controls whether ehci->regs->segment must (!!!)
 	 * be used; it constrains QH/ITD/SITD and QTD locations.
 	 * pci_pool consistent memory always uses segment zero.
+	 * streaming mappings for I/O buffers, like pci_map_single(),
+	 * can return segments above 4GB, if the device allows.
+	 *
+	 * NOTE:  layered drivers can't yet tell when we enable that,
+	 * so they can't pass this info along (like NETIF_F_HIGHDMA)
+	 * (or like Scsi_Host.highmem_io) ... usb_bus.flags?
 	 */
 	if (HCC_64BIT_ADDR (hcc_params)) {
 		writel (0, &ehci->regs->segment);
-		/*
-		 * FIXME Enlarge pci_set_dma_mask() when possible.  The DMA
-		 * mapping API spec now says that'll affect only single shot
-		 * mappings, and the pci_pool data will stay safe in seg 0.
-		 * That's what we want:  no extra copies for USB transfers.
-		 */
-		info ("restricting 64bit DMA mappings to segment 0 ...");
+		if (!pci_set_dma_mask (ehci->hcd.pdev, 0xffffffffffffffffULL))
+			info ("enabled 64bit PCI DMA (DAC)");
 	}
 
 	/* clear interrupt enables, set irq latency */
 	temp = readl (&ehci->regs->command) & 0xff;
 	if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
-	    log2_irq_thresh = 0;
+		log2_irq_thresh = 0;
 	temp |= 1 << (16 + log2_irq_thresh);
+	// if hc can park (ehci >= 0.96), default is 3 packets per async QH 
 	// keeping default periodic framelist size
 	temp &= ~(CMD_IAAD | CMD_ASE | CMD_PSE),
 	// Philips, Intel, and maybe others need CMD_RUN before the
@@ -251,8 +412,13 @@
 	ehci->tasklet.func = ehci_tasklet;
 	ehci->tasklet.data = (unsigned long) ehci;
 
+	init_timer (&ehci->watchdog);
+	ehci->watchdog.function = ehci_watchdog;
+	ehci->watchdog.data = (unsigned long) ehci;
+
 	/* wire up the root hub */
-	hcd->bus->root_hub = udev = usb_alloc_dev (NULL, hcd->bus);
+	bus = hcd_to_bus (hcd);
+	bus->root_hub = udev = usb_alloc_dev (NULL, bus);
 	if (!udev) {
 done2:
 		ehci_mem_cleanup (ehci);
@@ -271,11 +437,10 @@
         /* PCI Serial Bus Release Number is at 0x60 offset */
 	pci_read_config_byte (hcd->pdev, 0x60, &tempbyte);
 	temp = readw (&ehci->caps->hci_version);
-	info ("USB %x.%x support enabled, EHCI rev %x.%2x",
-	      ((tempbyte & 0xf0)>>4),
-	      (tempbyte & 0x0f),
-	       temp >> 8,
-	       temp & 0xff);
+	info ("USB %x.%x support enabled, EHCI rev %x.%02x, %s %s",
+	      ((tempbyte & 0xf0)>>4), (tempbyte & 0x0f),
+	       temp >> 8, temp & 0xff,
+	       hcd_name, DRIVER_VERSION);
 
 	/*
 	 * From here on, khubd concurrently accesses the root
@@ -286,19 +451,18 @@
 	 */
 	usb_connect (udev);
 	udev->speed = USB_SPEED_HIGH;
-	if (usb_new_device (udev) != 0) {
+	if (hcd_register_root (hcd) != 0) {
 		if (hcd->state == USB_STATE_RUNNING)
 			ehci_ready (ehci);
-		while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
-			udelay (100);
 		ehci_reset (ehci);
-		// usb_disconnect (udev); 
-		hcd->bus->root_hub = 0;
+		bus->root_hub = 0;
 		usb_free_dev (udev); 
 		retval = -ENODEV;
 		goto done2;
 	}
 
+	create_debug_files (ehci);
+
 	return 0;
 }
 
@@ -308,20 +472,34 @@
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 
-	dbg ("%s: stop", hcd->bus_name);
+	dbg ("%s: stop", hcd_to_bus (hcd)->bus_name);
 
+	/* no more interrupts ... */
 	if (hcd->state == USB_STATE_RUNNING)
 		ehci_ready (ehci);
-	while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
-		udelay (100);
+	if (in_interrupt ())		/* should not happen!! */
+		err ("stopped %s!", RUN_CONTEXT);
+	else
+		del_timer_sync (&ehci->watchdog);
 	ehci_reset (ehci);
 
-	// root hub is shut down separately (first, when possible)
-	scan_async (ehci);
-	if (ehci->next_uframe != -1)
-		scan_periodic (ehci);
+	/* let companion controllers work when we aren't */
+	writel (0, &ehci->regs->configured_flag);
+
+	remove_debug_files (ehci);
+
+	/* root hub is shut down separately (first, when possible) */
+	tasklet_disable (&ehci->tasklet);
+	ehci_tasklet ((unsigned long) ehci);
 	ehci_mem_cleanup (ehci);
 
+#ifdef	EHCI_STATS
+	dbg ("irq normal %ld err %ld reclaim %ld",
+		ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim);
+	dbg ("complete %ld unlink %ld qpatch %ld",
+		ehci->stats.complete, ehci->stats.unlink, ehci->stats.qpatch);
+#endif
+
 	dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
 }
 
@@ -343,7 +521,7 @@
 	int			ports;
 	int			i;
 
-	dbg ("%s: suspend to %d", hcd->bus_name, state);
+	dbg ("%s: suspend to %d", hcd_to_bus (hcd)->bus_name, state);
 
 	ports = HCS_N_PORTS (ehci->hcs_params);
 
@@ -360,15 +538,13 @@
 		if ((temp & PORT_PE) == 0
 				|| (temp & PORT_OWNER) != 0)
 			continue;
-dbg ("%s: suspend port %d", hcd->bus_name, i);
+dbg ("%s: suspend port %d", hcd_to_bus (hcd)->bus_name, i);
 		temp |= PORT_SUSPEND;
 		writel (temp, &ehci->regs->port_status [i]);
 	}
 
 	if (hcd->state == USB_STATE_RUNNING)
 		ehci_ready (ehci);
-	while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
-		udelay (100);
 	writel (readl (&ehci->regs->command) & ~CMD_RUN, &ehci->regs->command);
 
 // save pci FLADJ value
@@ -384,7 +560,7 @@
 	int			ports;
 	int			i;
 
-	dbg ("%s: resume", hcd->bus_name);
+	dbg ("%s: resume", hcd_to_bus (hcd)->bus_name);
 
 	ports = HCS_N_PORTS (ehci->hcs_params);
 
@@ -404,7 +580,7 @@
 		if ((temp & PORT_PE) == 0
 				|| (temp & PORT_SUSPEND) != 0)
 			continue;
-dbg ("%s: resume port %d", hcd->bus_name, i);
+dbg ("%s: resume port %d", hcd_to_bus (hcd)->bus_name, i);
 		temp |= PORT_RESUME;
 		writel (temp, &ehci->regs->port_status [i]);
 		readl (&ehci->regs->command);	/* unblock posted writes */
@@ -429,11 +605,15 @@
 {
 	struct ehci_hcd		*ehci = (struct ehci_hcd *) param;
 
+	spin_lock_irq (&ehci->lock);
+
 	if (ehci->reclaim_ready)
 		end_unlink_async (ehci);
 	scan_async (ehci);
 	if (ehci->next_uframe != -1)
 		scan_periodic (ehci);
+
+	spin_unlock_irq (&ehci->lock);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -444,6 +624,12 @@
 	u32			status = readl (&ehci->regs->status);
 	int			bh;
 
+	/* e.g. cardbus physical eject */
+	if (status == ~(u32) 0) {
+		dbg ("%s: device removed!", hcd_to_bus (hcd)->bus_name);
+		goto dead;
+	}
+
 	status &= INTR_MASK;
 	if (!status)			/* irq sharing? */
 		return;
@@ -461,21 +647,30 @@
 	/* INT, ERR, and IAA interrupt rates can be throttled */
 
 	/* normal [4.15.1.2] or error [4.15.1.1] completion */
-	if (likely ((status & (STS_INT|STS_ERR)) != 0))
+	if (likely ((status & (STS_INT|STS_ERR)) != 0)) {
+		if (likely ((status & STS_ERR) == 0))
+			COUNT (ehci->stats.normal);
+		else
+			COUNT (ehci->stats.error);
 		bh = 1;
+	}
 
 	/* complete the unlinking of some qh [4.15.2.3] */
 	if (status & STS_IAA) {
+		COUNT (ehci->stats.reclaim);
 		ehci->reclaim_ready = 1;
 		bh = 1;
 	}
 
 	/* PCI errors [4.15.2.4] */
 	if (unlikely ((status & STS_FATAL) != 0)) {
-		err ("%s: fatal error, state %x", hcd->bus_name, hcd->state);
+		err ("%s: fatal error, state %x",
+			hcd_to_bus (hcd)->bus_name, hcd->state);
+dead:
 		ehci_reset (ehci);
-		// generic layer kills/unlinks all urbs
-		// then tasklet cleans up the rest
+		/* generic layer kills/unlinks all urbs, then
+		 * uses ehci_stop to clean up the rest
+		 */
 		bh = 1;
 	}
 
@@ -495,7 +690,8 @@
  *
  * hcd-specific init for hcpriv hasn't been done yet
  *
- * NOTE:  EHCI queues control and bulk requests transparently, like OHCI.
+ * NOTE:  control, bulk, and interrupt share the same code to append TDs
+ * to a (possibly active) QH, and the same QH scanning code.
  */
 static int ehci_urb_enqueue (
 	struct usb_hcd	*hcd,
@@ -507,10 +703,11 @@
 
 	urb->transfer_flags &= ~EHCI_STATE_UNLINK;
 	INIT_LIST_HEAD (&qtd_list);
-	switch (usb_pipetype (urb->pipe)) {
 
-	case PIPE_CONTROL:
-	case PIPE_BULK:
+	switch (usb_pipetype (urb->pipe)) {
+	// case PIPE_CONTROL:
+	// case PIPE_BULK:
+	default:
 		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
 			return -ENOMEM;
 		return submit_async (ehci, urb, &qtd_list, mem_flags);
@@ -530,9 +727,6 @@
 		dbg ("no split iso support yet");
 		return -ENOSYS;
 #endif /* have_split_iso */
-
-	default:	/* can't happen */
-		return -ENOSYS;
 	}
 }
 
@@ -546,15 +740,22 @@
 	struct ehci_qh		*qh = (struct ehci_qh *) urb->hcpriv;
 	unsigned long		flags;
 
-	dbg ("%s urb_dequeue %p qh state %d",
-		hcd->bus_name, urb, qh->qh_state);
+	dbg ("%s urb_dequeue %p qh %p state %d",
+		hcd_to_bus (hcd)->bus_name, urb, qh, qh->qh_state);
 
 	switch (usb_pipetype (urb->pipe)) {
-	case PIPE_CONTROL:
-	case PIPE_BULK:
+	// case PIPE_CONTROL:
+	// case PIPE_BULK:
+	default:
 		spin_lock_irqsave (&ehci->lock, flags);
 		if (ehci->reclaim) {
-dbg ("dq: reclaim busy, %s", RUN_CONTEXT);
+			dbg ("dq %p: reclaim = %p, %s",
+				qh, ehci->reclaim, RUN_CONTEXT);
+			if (qh == ehci->reclaim) {
+				/* unlinking qh for another queued urb? */
+				spin_unlock_irqrestore (&ehci->lock, flags);
+				return 0;
+			}
 			if (in_interrupt ()) {
 				spin_unlock_irqrestore (&ehci->lock, flags);
 				return -EAGAIN;
@@ -564,28 +765,43 @@
 					&& ehci->hcd.state != USB_STATE_HALT
 					) {
 				spin_unlock_irqrestore (&ehci->lock, flags);
-// yeech ... this could spin for up to two frames!
-dbg ("wait for dequeue: state %d, reclaim %p, hcd state %d",
-    qh->qh_state, ehci->reclaim, ehci->hcd.state
-);
-				udelay (100);
+				/* let pending unlinks complete */
+				wait_ms (1);
 				spin_lock_irqsave (&ehci->lock, flags);
 			}
 		}
 		if (qh->qh_state == QH_STATE_LINKED)
 			start_unlink_async (ehci, qh);
 		spin_unlock_irqrestore (&ehci->lock, flags);
-		return 0;
+		break;
 
 	case PIPE_INTERRUPT:
-		intr_deschedule (ehci, urb->start_frame, qh,
-			(urb->dev->speed == USB_SPEED_HIGH)
-			    ? urb->interval
-			    : (urb->interval << 3));
-		if (ehci->hcd.state == USB_STATE_HALT)
-			urb->status = -ESHUTDOWN;
-		qh_completions (ehci, qh, 1);
-		return 0;
+		spin_lock_irqsave (&ehci->lock, flags);
+		if (qh->qh_state == QH_STATE_LINKED) {
+			/* messy, can spin or block a microframe ... */
+			intr_deschedule (ehci, qh, 1);
+			/* qh_state == IDLE */
+		}
+		qh_completions (ehci, qh);
+
+		/* reschedule QH iff another request is queued */
+		if (!list_empty (&qh->qtd_list)
+				&& HCD_IS_RUNNING (ehci->hcd.state)) {
+			int status;
+
+			status = qh_schedule (ehci, qh);
+			spin_unlock_irqrestore (&ehci->lock, flags);
+
+			if (status != 0) {
+				// shouldn't happen often, but ...
+				// FIXME kill those tds' urbs
+				err ("can't reschedule qh %p, err %d",
+					qh, status);
+			}
+			return status;
+		}
+		spin_unlock_irqrestore (&ehci->lock, flags);
+		break;
 
 	case PIPE_ISOCHRONOUS:
 		// itd or sitd ...
@@ -593,9 +809,9 @@
 		// wait till next completion, do it then.
 		// completion irqs can wait up to 1024 msec,
 		urb->transfer_flags |= EHCI_STATE_UNLINK;
-		return 0;
+		break;
 	}
-	return -EINVAL;
+	return 0;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -609,42 +825,67 @@
 	int			i;
 	unsigned long		flags;
 
+	/* ASSERT:  no requests/urbs are still linked (so no TDs) */
 	/* ASSERT:  nobody can be submitting urbs for this any more */
 
-	dbg ("%s: free_config devnum %d", hcd->bus_name, udev->devnum);
+	dbg ("%s: free_config devnum %d",
+		hcd_to_bus (hcd)->bus_name, udev->devnum);
 
 	spin_lock_irqsave (&ehci->lock, flags);
 	for (i = 0; i < 32; i++) {
 		if (dev->ep [i]) {
 			struct ehci_qh		*qh;
+			char			*why;
 
 			/* dev->ep never has ITDs or SITDs */
 			qh = (struct ehci_qh *) dev->ep [i];
-			vdbg ("free_config, ep 0x%02x qh %p", i, qh);
-			if (!list_empty (&qh->qtd_list)) {
-				dbg ("ep 0x%02x qh %p not empty!", i, qh);
+
+			/* detect/report non-recoverable errors */
+			if (in_interrupt ()) 
+				why = "disconnect() didn't";
+			else if ((qh->hw_info2 & cpu_to_le32 (0xffff)) != 0
+					&& qh->qh_state != QH_STATE_IDLE)
+				why = "(active periodic)";
+			else
+				why = 0;
+			if (why) {
+				err ("dev %s-%s ep %d-%s error: %s",
+					hcd_to_bus (hcd)->bus_name,
+					udev->devpath,
+					i & 0xf, (i & 0x10) ? "IN" : "OUT",
+					why);
 				BUG ();
 			}
-			dev->ep [i] = 0;
 
-			/* wait_ms() won't spin here -- we're a thread */
+			dev->ep [i] = 0;
+			if (qh->qh_state == QH_STATE_IDLE)
+				goto idle;
+			dbg ("free_config, async ep 0x%02x qh %p", i, qh);
+
+			/* scan_async() empties the ring as it does its work,
+			 * using IAA, but doesn't (yet?) turn it off.  if it
+			 * doesn't empty this qh, likely it's the last entry.
+			 */
 			while (qh->qh_state == QH_STATE_LINKED
 					&& ehci->reclaim
 					&& ehci->hcd.state != USB_STATE_HALT
 					) {
 				spin_unlock_irqrestore (&ehci->lock, flags);
+				/* wait_ms() won't spin, we're a thread;
+				 * and we know IRQ+tasklet can progress
+				 */
 				wait_ms (1);
 				spin_lock_irqsave (&ehci->lock, flags);
 			}
-			if (qh->qh_state == QH_STATE_LINKED) {
+			if (qh->qh_state == QH_STATE_LINKED)
 				start_unlink_async (ehci, qh);
-				while (qh->qh_state != QH_STATE_IDLE) {
-					spin_unlock_irqrestore (&ehci->lock,
-						flags);
-					wait_ms (1);
-					spin_lock_irqsave (&ehci->lock, flags);
-				}
+			while (qh->qh_state != QH_STATE_IDLE
+					&& ehci->hcd.state != USB_STATE_HALT) {
+				spin_unlock_irqrestore (&ehci->lock, flags);
+				wait_ms (1);
+				spin_lock_irqsave (&ehci->lock, flags);
 			}
+idle:
 			qh_put (ehci, qh);
 		}
 	}
@@ -654,50 +895,48 @@
 
 /*-------------------------------------------------------------------------*/
 
-static const char	hcd_name [] = "ehci-hcd";
-
 static const struct hc_driver ehci_driver = {
-	description:		hcd_name,
+	.description =		hcd_name,
 
 	/*
 	 * generic hardware linkage
 	 */
-	irq:			ehci_irq,
-	flags:			HCD_MEMORY | HCD_USB2,
+	.irq =			ehci_irq,
+	.flags =		HCD_MEMORY | HCD_USB2,
 
 	/*
 	 * basic lifecycle operations
 	 */
-	start:			ehci_start,
+	.start =		ehci_start,
 #ifdef	CONFIG_PM
-	suspend:		ehci_suspend,
-	resume:			ehci_resume,
+	.suspend =		ehci_suspend,
+	.resume =		ehci_resume,
 #endif
-	stop:			ehci_stop,
+	.stop =			ehci_stop,
 
 	/*
 	 * memory lifecycle (except per-request)
 	 */
-	hcd_alloc:		ehci_hcd_alloc,
-	hcd_free:		ehci_hcd_free,
+	.hcd_alloc =		ehci_hcd_alloc,
+	.hcd_free =		ehci_hcd_free,
 
 	/*
 	 * managing i/o requests and associated device resources
 	 */
-	urb_enqueue:		ehci_urb_enqueue,
-	urb_dequeue:		ehci_urb_dequeue,
-	free_config:		ehci_free_config,
+	.urb_enqueue =		ehci_urb_enqueue,
+	.urb_dequeue =		ehci_urb_dequeue,
+	.free_config =		ehci_free_config,
 
 	/*
 	 * scheduling support
 	 */
-	get_frame_number:	ehci_get_frame,
+	.get_frame_number =	ehci_get_frame,
 
 	/*
 	 * root hub support
 	 */
-	hub_status_data:	ehci_hub_status_data,
-	hub_control:		ehci_hub_control,
+	.hub_status_data =	ehci_hub_status_data,
+	.hub_control =		ehci_hub_control,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -709,15 +948,15 @@
 
 	/* handle any USB 2.0 EHCI controller */
 
-	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x20),
-	class_mask: 	~0,
-	driver_data:	(unsigned long) &ehci_driver,
+	.class = 		((PCI_CLASS_SERIAL_USB << 8) | 0x20),
+	.class_mask = 	~0,
+	.driver_data =	(unsigned long) &ehci_driver,
 
 	/* no matter who makes it */
-	vendor:		PCI_ANY_ID,
-	device:		PCI_ANY_ID,
-	subvendor:	PCI_ANY_ID,
-	subdevice:	PCI_ANY_ID,
+	.vendor =	PCI_ANY_ID,
+	.device =	PCI_ANY_ID,
+	.subvendor =	PCI_ANY_ID,
+	.subdevice =	PCI_ANY_ID,
 
 }, { /* end: all zeroes */ }
 };
@@ -725,21 +964,20 @@
 
 /* pci driver glue; this is a "new style" PCI driver module */
 static struct pci_driver ehci_pci_driver = {
-	name:		(char *) hcd_name,
-	id_table:	pci_ids,
+	.name =		(char *) hcd_name,
+	.id_table =	pci_ids,
 
-	probe:		usb_hcd_pci_probe,
-	remove:		usb_hcd_pci_remove,
+	.probe =	usb_hcd_pci_probe,
+	.remove =	usb_hcd_pci_remove,
 
 #ifdef	CONFIG_PM
-	suspend:	usb_hcd_pci_suspend,
-	resume:		usb_hcd_pci_resume,
+	.suspend =	usb_hcd_pci_suspend,
+	.resume =	usb_hcd_pci_resume,
 #endif
 };
 
 #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
 
-EXPORT_NO_SYMBOLS;
 MODULE_DESCRIPTION (DRIVER_INFO);
 MODULE_AUTHOR (DRIVER_AUTHOR);
 MODULE_LICENSE ("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hcd/ehci-hub.c linux-2.4.21/drivers/usb/hcd/ehci-hub.c
--- linux-2.4.20/drivers/usb/hcd/ehci-hub.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/usb/hcd/ehci-hub.c	2002-12-18 18:58:02.000000000 +0000
@@ -41,14 +41,17 @@
 	/* if reset finished and it's still not enabled -- handoff */
 	if (!(port_status & PORT_PE)) {
 		dbg ("%s port %d full speed, give to companion, 0x%x",
-			ehci->hcd.bus_name, index + 1, port_status);
+			hcd_to_bus (&ehci->hcd)->bus_name,
+			index + 1, port_status);
 
 		// what happens if HCS_N_CC(params) == 0 ?
 		port_status |= PORT_OWNER;
 		writel (port_status, &ehci->regs->port_status [index]);
 
 	} else
-		dbg ("%s port %d high speed", ehci->hcd.bus_name, index + 1);
+		dbg ("%s port %d high speed",
+			hcd_to_bus (&ehci->hcd)->bus_name,
+			index + 1);
 
 	return port_status;
 }
@@ -236,7 +239,8 @@
 
 		/* whoever resets must GetPortStatus to complete it!! */
 		if ((temp & PORT_RESET)
-				&& jiffies > ehci->reset_done [wIndex]) {
+				&& time_after (jiffies,
+					ehci->reset_done [wIndex])) {
 			status |= 1 << USB_PORT_FEAT_C_RESET;
 
 			/* force reset to complete */
@@ -310,11 +314,13 @@
 			if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
 					&& PORT_USB11 (temp)) {
 				dbg ("%s port %d low speed, give to companion",
-					hcd->bus_name, wIndex + 1);
+					hcd_to_bus (&ehci->hcd)->bus_name,
+					wIndex + 1);
 				temp |= PORT_OWNER;
 			} else {
 				vdbg ("%s port %d reset",
-					hcd->bus_name, wIndex + 1);
+					hcd_to_bus (&ehci->hcd)->bus_name,
+					wIndex + 1);
 				temp |= PORT_RESET;
 				temp &= ~PORT_PE;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hcd/ehci-q.c linux-2.4.21/drivers/usb/hcd/ehci-q.c
--- linux-2.4.20/drivers/usb/hcd/ehci-q.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/hcd/ehci-q.c	2002-12-18 18:58:01.000000000 +0000
@@ -26,8 +26,7 @@
  * Control, bulk, and interrupt traffic all use "qh" lists.  They list "qtd"
  * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned
  * buffers needed for the larger number).  We use one QH per endpoint, queue
- * multiple (bulk or control) urbs per endpoint.  URBs may need several qtds.
- * A scheduled interrupt qh always (for now) has one qtd, one urb.
+ * multiple urbs (all three types) per endpoint.  URBs may need several qtds.
  *
  * ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with
  * interrupts) needs careful scheduling.  Performance improvements can be
@@ -47,9 +46,11 @@
 qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len, int token)
 {
 	int	i, count;
+	u64	addr = buf;
 
 	/* one buffer entry per 4K ... first might be short or unaligned */
-	qtd->hw_buf [0] = cpu_to_le32 (buf);
+	qtd->hw_buf [0] = cpu_to_le32 ((u32)addr);
+	qtd->hw_buf_hi [0] = cpu_to_le32 ((u32)(addr >> 32));
 	count = 0x1000 - (buf & 0x0fff);	/* rest of that page */
 	if (likely (len < count))		/* ... iff needed */
 		count = len;
@@ -59,7 +60,7 @@
 
 		/* per-qtd limit: from 16K to 20K (best alignment) */
 		for (i = 1; count < len && i < 5; i++) {
-			u64	addr = buf;
+			addr = buf;
 			qtd->hw_buf [i] = cpu_to_le32 ((u32)addr);
 			qtd->hw_buf_hi [i] = cpu_to_le32 ((u32)(addr >> 32));
 			buf += 0x1000;
@@ -144,97 +145,106 @@
 					usb_pipeendpoint (pipe),
 					usb_pipeout (pipe));
 			if (urb->dev->tt && !usb_pipeint (pipe)) {
-err ("must CLEAR_TT_BUFFER, hub port %d%s addr %d ep %d",
-    urb->dev->ttport, /* devpath */
-    urb->dev->tt->multi ? "" : " (all-ports TT)",
-    urb->dev->devnum, usb_pipeendpoint (urb->pipe));
-				// FIXME something (khubd?) should make the hub
-				// CLEAR_TT_BUFFER ASAP, it's blocking other
-				// fs/ls requests... hub_tt_clear_buffer() ?
+#ifdef DEBUG
+				struct usb_device *tt = urb->dev->tt->hub;
+				dbg ("clear tt %s-%s p%d buffer, a%d ep%d",
+					tt->bus->bus_name, tt->devpath,
+    					urb->dev->ttport, urb->dev->devnum,
+    					usb_pipeendpoint (pipe));
+#endif /* DEBUG */
+				usb_hub_tt_clear_buffer (urb->dev, pipe);
 			}
 		}
 	}
 }
 
-static void ehci_urb_complete (
-	struct ehci_hcd		*ehci,
-	dma_addr_t		addr,
-	struct urb		*urb
-) {
-	if (urb->transfer_buffer_length && usb_pipein (urb->pipe))
-		pci_dma_sync_single (ehci->hcd.pdev, addr,
-			urb->transfer_buffer_length,
-			PCI_DMA_FROMDEVICE);
+static void ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb)
+{
+#ifdef	INTR_AUTOMAGIC
+	struct urb		*resubmit = 0;
+	struct usb_device	*dev = 0;
 
-	/* cleanse status if we saw no error */
-	if (likely (urb->status == -EINPROGRESS)) {
-		if (urb->actual_length != urb->transfer_buffer_length
-				&& (urb->transfer_flags & USB_DISABLE_SPD))
-			urb->status = -EREMOTEIO;
-		else
-			urb->status = 0;
-	}
+	static int ehci_urb_enqueue (struct usb_hcd *, struct urb *, int);
+#endif
 
-	/* only report unlinks once */
-	if (likely (urb->status != -ENOENT && urb->status != -ENOTCONN))
-		urb->complete (urb);
-}
+	if (likely (urb->hcpriv != 0)) {
+		struct ehci_qh	*qh = (struct ehci_qh *) urb->hcpriv;
 
-/* urb->lock ignored from here on (hcd is done with urb) */
+		/* S-mask in a QH means it's an interrupt urb */
+		if ((qh->hw_info2 & cpu_to_le32 (0x00ff)) != 0) {
 
-static void ehci_urb_done (
-	struct ehci_hcd		*ehci,
-	dma_addr_t		addr,
-	struct urb		*urb
-) {
-	if (urb->transfer_buffer_length)
-		pci_unmap_single (ehci->hcd.pdev,
-			addr,
-			urb->transfer_buffer_length,
-			usb_pipein (urb->pipe)
-			    ? PCI_DMA_FROMDEVICE
-			    : PCI_DMA_TODEVICE);
-	if (likely (urb->hcpriv != 0)) {
-		qh_put (ehci, (struct ehci_qh *) urb->hcpriv);
+			/* ... update hc-wide periodic stats (for usbfs) */
+			hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs--;
+
+#ifdef	INTR_AUTOMAGIC
+			if (!((urb->status == -ENOENT)
+					|| (urb->status == -ECONNRESET))) {
+				resubmit = usb_get_urb (urb);
+				dev = urb->dev;
+			}
+#endif
+		}
+		qh_put (ehci, qh);
 		urb->hcpriv = 0;
 	}
 
 	if (likely (urb->status == -EINPROGRESS)) {
 		if (urb->actual_length != urb->transfer_buffer_length
-				&& (urb->transfer_flags & USB_DISABLE_SPD))
+				&& (urb->transfer_flags & URB_SHORT_NOT_OK))
 			urb->status = -EREMOTEIO;
 		else
 			urb->status = 0;
 	}
 
-	/* hand off urb ownership */
+	if (likely (urb->status == 0))
+		COUNT (ehci->stats.complete);
+	else if (urb->status == -ECONNRESET || urb->status == -ENOENT)
+		COUNT (ehci->stats.unlink);
+	else
+		COUNT (ehci->stats.error);
+
+	/* complete() can reenter this HCD */
+	spin_unlock (&ehci->lock);
 	usb_hcd_giveback_urb (&ehci->hcd, urb);
+
+#ifdef	INTR_AUTOMAGIC
+	if (resubmit && ((urb->status == -ENOENT)
+				|| (urb->status == -ECONNRESET))) {
+		usb_put_urb (resubmit);
+		resubmit = 0;
+	}
+	// device drivers will soon be doing something like this
+	if (resubmit) {
+		int	status;
+
+		resubmit->dev = dev;
+		status = SUBMIT_URB (resubmit, SLAB_KERNEL);
+		if (status != 0)
+			err ("can't resubmit interrupt urb %p: status %d",
+					resubmit, status);
+		usb_put_urb (resubmit);
+	}
+#endif
+
+	spin_lock (&ehci->lock);
 }
 
 
 /*
- * Process completed qtds for a qh, issuing completions if needed.
- * When freeing:  frees qtds, unmaps buf, returns URB to driver.
- * When not freeing (queued periodic qh):  retain qtds, mapping, and urb.
- * Races up to qh->hw_current; returns number of urb completions.
+ * Process and free completed qtds for a qh, returning URBs to drivers.
+ * Chases up to qh->hw_current.  Returns number of completions called,
+ * indicating how much "real" work we did.
  */
-static int
-qh_completions (
-	struct ehci_hcd		*ehci,
-	struct ehci_qh		*qh,
-	int			freeing
-) {
+static unsigned
+qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
 	struct ehci_qtd		*qtd, *last;
 	struct list_head	*next, *qtd_list = &qh->qtd_list;
 	int			unlink = 0, halted = 0;
-	unsigned long		flags;
-	int			retval = 0;
+	unsigned		count = 0;
 
-	spin_lock_irqsave (&ehci->lock, flags);
-	if (unlikely (list_empty (qtd_list))) {
-		spin_unlock_irqrestore (&ehci->lock, flags);
-		return retval;
-	}
+	if (unlikely (list_empty (qtd_list)))
+		return count;
 
 	/* scan QTDs till end of list, or we reach an active one */
 	for (qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list),
@@ -248,16 +258,8 @@
 		/* clean up any state from previous QTD ...*/
 		if (last) {
 			if (likely (last->urb != urb)) {
-				/* complete() can reenter this HCD */
-				spin_unlock_irqrestore (&ehci->lock, flags);
-				if (likely (freeing != 0))
-					ehci_urb_done (ehci, last->buf_dma,
-						last->urb);
-				else
-					ehci_urb_complete (ehci, last->buf_dma,
-						last->urb);
-				spin_lock_irqsave (&ehci->lock, flags);
-				retval++;
+				ehci_urb_done (ehci, last->urb);
+				count++;
 			}
 
 			/* qh overlays can have HC's old cached copies of
@@ -267,10 +269,10 @@
 					&& last->hw_next != qh->hw_qtd_next) {
 				qh->hw_alt_next = last->hw_alt_next;
 				qh->hw_qtd_next = last->hw_next;
+				COUNT (ehci->stats.qpatch);
 			}
 
-			if (likely (freeing != 0))
-				ehci_qtd_free (ehci, last);
+			ehci_qtd_free (ehci, last);
 			last = 0;
 		}
 		next = qtd->qtd_list.next;
@@ -285,9 +287,17 @@
 			|| (ehci->hcd.state == USB_STATE_HALT)
 			|| (qh->qh_state == QH_STATE_IDLE);
 
+		// FIXME Remove the automagic unlink mode.
+		// Drivers can now clean up safely; it's their job.
+		//
+		// FIXME Removing it should fix the short read scenarios
+		// with "huge" urb data (more than one 16+KByte td) with
+		// the short read someplace other than the last data TD.
+		// Except the control case: 'retrigger' status ACKs.
+
 		/* fault: unlink the rest, since this qtd saw an error? */
 		if (unlikely ((token & QTD_STS_HALT) != 0)) {
-			freeing = unlink = 1;
+			unlink = 1;
 			/* status copied below */
 
 		/* QH halts only because of fault (above) or unlink (here). */
@@ -295,13 +305,14 @@
 
 			/* unlinking everything because of HC shutdown? */
 			if (ehci->hcd.state == USB_STATE_HALT) {
-				freeing = unlink = 1;
+				unlink = 1;
 
 			/* explicit unlink, maybe starting here? */
 			} else if (qh->qh_state == QH_STATE_IDLE
 					&& (urb->status == -ECONNRESET
+						|| urb->status == -ESHUTDOWN
 						|| urb->status == -ENOENT)) {
-				freeing = unlink = 1;
+				unlink = 1;
 
 			/* QH halted to unlink urbs _after_ this?  */
 			} else if (!unlink && (token & QTD_STS_ACTIVE) != 0) {
@@ -311,7 +322,7 @@
 
 			/* unlink the rest?  once we start unlinking, after
 			 * a fault or explicit unlink, we unlink all later
-			 * urbs.  usb spec requires that.
+			 * urbs.  usb spec requires that for faults...
 			 */
 			if (unlink && urb->status == -EINPROGRESS)
 				urb->status = -ECONNRESET;
@@ -329,31 +340,7 @@
 		qtd_copy_status (urb, qtd->length, token);
 		spin_unlock (&urb->lock);
 
-		/*
-		 * NOTE:  this won't work right with interrupt urbs that
-		 * need multiple qtds ... only the first scan of qh->qtd_list
-		 * starts at the right qtd, yet multiple scans could happen
-		 * for transfers that are scheduled across multiple uframes. 
-		 * (Such schedules are not currently allowed!)
-		 */
-		if (likely (freeing != 0))
-			list_del (&qtd->qtd_list);
-		else {
-			/* restore everything the HC could change
-			 * from an interrupt QTD
-			 */
-			qtd->hw_token = (qtd->hw_token
-					& __constant_cpu_to_le32 (0x8300))
-				| cpu_to_le32 (qtd->length << 16)
-				| __constant_cpu_to_le32 (QTD_STS_ACTIVE
-					| (EHCI_TUNE_CERR << 10));
-			qtd->hw_buf [0] &= ~__constant_cpu_to_le32 (0x0fff);
-
-			/* this offset, and the length above,
-			 * are likely wrong on QTDs #2..N
-			 */
-			qtd->hw_buf [0] |= cpu_to_le32 (0x0fff & qtd->buf_dma);
-		}
+		list_del (&qtd->qtd_list);
 
 #if 0
 		if (urb->status == -EINPROGRESS)
@@ -364,31 +351,22 @@
 				urb, urb->status, qtd, token,
 				urb->actual_length);
 #endif
+	}
 
-		/* SETUP for control urb? */
-		if (unlikely (QTD_PID (token) == 2))
-			pci_unmap_single (ehci->hcd.pdev,
-				qtd->buf_dma, sizeof (struct usb_ctrlrequest),
-				PCI_DMA_TODEVICE);
+	/* last urb's completion might still need calling */
+	if (likely (last != 0)) {
+		ehci_urb_done (ehci, last->urb);
+		count++;
+		ehci_qtd_free (ehci, last);
 	}
 
-	/* patch up list head? */
+	/* reactivate queue after error and driver's cleanup */
 	if (unlikely (halted && !list_empty (qtd_list))) {
 		qh_update (qh, list_entry (qtd_list->next,
 				struct ehci_qtd, qtd_list));
 	}
-	spin_unlock_irqrestore (&ehci->lock, flags);
 
-	/* last urb's completion might still need calling */
-	if (likely (last != 0)) {
-		if (likely (freeing != 0)) {
-			ehci_urb_done (ehci, last->buf_dma, last->urb);
-			ehci_qtd_free (ehci, last);
-		} else
-			ehci_urb_complete (ehci, last->buf_dma, last->urb);
-		retval++;
-	}
-	return retval;
+	return count;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -403,35 +381,12 @@
 	struct list_head	*qtd_list
 ) {
 	struct list_head	*entry, *temp;
-	int			unmapped = 0;
 
 	list_for_each_safe (entry, temp, qtd_list) {
 		struct ehci_qtd	*qtd;
 
 		qtd = list_entry (entry, struct ehci_qtd, qtd_list);
 		list_del (&qtd->qtd_list);
-		if (unmapped != 2) {
-			int	direction;
-			size_t	size;
-
-			/* for ctrl unmap twice: SETUP and DATA;
-			 * else (bulk, intr) just once: DATA
-			 */
-			if (!unmapped++ && usb_pipecontrol (urb->pipe)) {
-				direction = PCI_DMA_TODEVICE;
-				size = sizeof (struct usb_ctrlrequest);
-			} else {
-				direction = usb_pipein (urb->pipe)
-					? PCI_DMA_FROMDEVICE
-					: PCI_DMA_TODEVICE;
-				size = qtd->urb->transfer_buffer_length;
-				unmapped++;
-			}
-			if (qtd->buf_dma)
-				pci_unmap_single (ehci->hcd.pdev,
-					qtd->buf_dma,
-					size, direction);
-		}
 		ehci_qtd_free (ehci, qtd);
 	}
 }
@@ -447,8 +402,9 @@
 	int			flags
 ) {
 	struct ehci_qtd		*qtd, *qtd_prev;
-	dma_addr_t		buf, map_buf;
+	dma_addr_t		buf;
 	int			len, maxpacket;
+	int			is_input, status_patch = 0;
 	u32			token;
 
 	/*
@@ -466,17 +422,8 @@
 	/* for split transactions, SplitXState initialized to zero */
 
 	if (usb_pipecontrol (urb->pipe)) {
-		/* control request data is passed in the "setup" pid */
-		qtd->buf_dma = pci_map_single (
-					ehci->hcd.pdev,
-					urb->setup_packet,
-					sizeof (struct usb_ctrlrequest),
-					PCI_DMA_TODEVICE);
-		if (unlikely (!qtd->buf_dma))
-			goto cleanup;
-
 		/* SETUP pid */
-		qtd_fill (qtd, qtd->buf_dma, sizeof (struct usb_ctrlrequest),
+		qtd_fill (qtd, urb->setup_dma, sizeof (struct usb_ctrlrequest),
 			token | (2 /* "setup" */ << 8));
 
 		/* ... and always at least one more pid */
@@ -488,29 +435,26 @@
 		qtd->urb = urb;
 		qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
 		list_add_tail (&qtd->qtd_list, head);
+
+		if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
+			status_patch = 1;
 	} 
 
 	/*
 	 * data transfer stage:  buffer setup
 	 */
 	len = urb->transfer_buffer_length;
-	if (likely (len > 0)) {
-		buf = map_buf = pci_map_single (ehci->hcd.pdev,
-			urb->transfer_buffer, len,
-			usb_pipein (urb->pipe)
-			    ? PCI_DMA_FROMDEVICE
-			    : PCI_DMA_TODEVICE);
-		if (unlikely (!buf))
-			goto cleanup;
-	} else
-		buf = map_buf = 0;
+	is_input = usb_pipein (urb->pipe);
+	if (likely (len > 0))
+		buf = urb->transfer_dma;
+	else
+		buf = 0;
 
-	if (!buf || usb_pipein (urb->pipe))
+	if (!buf || is_input)
 		token |= (1 /* "in" */ << 8);
 	/* else it's already initted to "out" pid (0 << 8) */
 
-	maxpacket = usb_maxpacket (urb->dev, urb->pipe,
-			usb_pipeout (urb->pipe));
+	maxpacket = usb_maxpacket (urb->dev, urb->pipe, !is_input) & 0x03ff;
 
 	/*
 	 * buffer gets wrapped in one or more qtds;
@@ -521,7 +465,6 @@
 		int this_qtd_len;
 
 		qtd->urb = urb;
-		qtd->buf_dma = map_buf;
 		this_qtd_len = qtd_fill (qtd, buf, len, token);
 		len -= this_qtd_len;
 		buf += this_qtd_len;
@@ -572,6 +515,19 @@
 		}
 	}
 
+	/* if we're permitting a short control read, we want the hardware to
+	 * just continue after short data and send the status ack.  it can do
+	 * that on the last data packet (typically the only one).  for other
+	 * packets, software fixup is needed (in qh_completions).
+	 */
+	if (status_patch) {
+		struct ehci_qtd		*prev;
+
+		prev = list_entry (qtd->qtd_list.prev,
+				struct ehci_qtd, qtd_list);
+		prev->hw_alt_next = QTD_NEXT (qtd->qtd_dma);
+	}
+
 	/* by default, enable interrupt on urb completion */
 	if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))
 		qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC);
@@ -606,6 +562,11 @@
 // That'd mean updating how usbcore talks to HCDs. (2.5?)
 
 
+// high bandwidth multiplier, as encoded in highspeed endpoint descriptors
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+// ... and packet size, for any kind of endpoint descriptor
+#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x03ff)
+
 /*
  * Each QH holds a qtd list; a QH is used for everything except iso.
  *
@@ -623,6 +584,8 @@
 ) {
 	struct ehci_qh		*qh = ehci_qh_alloc (ehci, flags);
 	u32			info1 = 0, info2 = 0;
+	int			is_input, type;
+	int			maxp = 0;
 
 	if (!qh)
 		return qh;
@@ -633,6 +596,53 @@
 	info1 |= usb_pipeendpoint (urb->pipe) << 8;
 	info1 |= usb_pipedevice (urb->pipe) << 0;
 
+	is_input = usb_pipein (urb->pipe);
+	type = usb_pipetype (urb->pipe);
+	maxp = usb_maxpacket (urb->dev, urb->pipe, !is_input);
+
+	/* Compute interrupt scheduling parameters just once, and save.
+	 * - allowing for high bandwidth, how many nsec/uframe are used?
+	 * - split transactions need a second CSPLIT uframe; same question
+	 * - splits also need a schedule gap (for full/low speed I/O)
+	 * - qh has a polling interval
+	 *
+	 * For control/bulk requests, the HC or TT handles these.
+	 */
+	if (type == PIPE_INTERRUPT) {
+		qh->usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0,
+				hb_mult (maxp) * max_packet (maxp));
+		qh->start = NO_FRAME;
+
+		if (urb->dev->speed == USB_SPEED_HIGH) {
+			qh->c_usecs = 0;
+			qh->gap_uf = 0;
+
+			/* FIXME handle HS periods of less than 1 frame. */
+			qh->period = urb->interval >> 3;
+			if (qh->period < 1) {
+				dbg ("intr period %d uframes, NYET!",
+						urb->interval);
+				qh = 0;
+				goto done;
+			}
+		} else {
+			/* gap is f(FS/LS transfer times) */
+			qh->gap_uf = 1 + usb_calc_bus_time (urb->dev->speed,
+					is_input, 0, maxp) / (125 * 1000);
+
+			/* FIXME this just approximates SPLIT/CSPLIT times */
+			if (is_input) {		// SPLIT, gap, CSPLIT+DATA
+				qh->c_usecs = qh->usecs + HS_USECS (0);
+				qh->usecs = HS_USECS (1);
+			} else {		// SPLIT+DATA, gap, CSPLIT
+				qh->usecs += HS_USECS (1);
+				qh->c_usecs = HS_USECS (0);
+			}
+
+			qh->period = urb->interval;
+		}
+	}
+
 	/* using TT? */
 	switch (urb->dev->speed) {
 	case USB_SPEED_LOW:
@@ -642,69 +652,62 @@
 	case USB_SPEED_FULL:
 		/* EPS 0 means "full" */
 		info1 |= (EHCI_TUNE_RL_TT << 28);
-		if (usb_pipecontrol (urb->pipe)) {
+		if (type == PIPE_CONTROL) {
 			info1 |= (1 << 27);	/* for TT */
 			info1 |= 1 << 14;	/* toggle from qtd */
 		}
-		info1 |= usb_maxpacket (urb->dev, urb->pipe,
-					usb_pipeout (urb->pipe)) << 16;
+		info1 |= maxp << 16;
 
 		info2 |= (EHCI_TUNE_MULT_TT << 30);
 		info2 |= urb->dev->ttport << 23;
 		info2 |= urb->dev->tt->hub->devnum << 16;
 
-		/* NOTE:  if (usb_pipeint (urb->pipe)) { scheduler sets c-mask }
-		 * ... and a 0.96 scheduler might use FSTN nodes too
-		 */
+		/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets c-mask } */
+
 		break;
 
 	case USB_SPEED_HIGH:		/* no TT involved */
 		info1 |= (2 << 12);	/* EPS "high" */
 		info1 |= (EHCI_TUNE_RL_HS << 28);
-		if (usb_pipecontrol (urb->pipe)) {
+		if (type == PIPE_CONTROL) {
 			info1 |= 64 << 16;	/* usb2 fixed maxpacket */
 			info1 |= 1 << 14;	/* toggle from qtd */
 			info2 |= (EHCI_TUNE_MULT_HS << 30);
-		} else if (usb_pipebulk (urb->pipe)) {
+		} else if (type == PIPE_BULK) {
 			info1 |= 512 << 16;	/* usb2 fixed maxpacket */
 			info2 |= (EHCI_TUNE_MULT_HS << 30);
-		} else {
-			u32	temp;
-			temp = usb_maxpacket (urb->dev, urb->pipe,
-						usb_pipeout (urb->pipe));
-			info1 |= (temp & 0x3ff) << 16;	/* maxpacket */
-			/* HS intr can be "high bandwidth" */
-			temp = 1 + ((temp >> 11) & 0x03);
-			info2 |= temp << 30;		/* mult */
+		} else {		/* PIPE_INTERRUPT */
+			info1 |= max_packet (maxp) << 16;
+			info2 |= hb_mult (maxp) << 30;
 		}
 		break;
 	default:
-#ifdef DEBUG
-		BUG ();
-#else
-		;
-#endif
+ 		dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
+ 		return 0;
 	}
 
-	/* NOTE:  if (usb_pipeint (urb->pipe)) { scheduler sets s-mask } */
+	/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets s-mask } */
 
 	qh->qh_state = QH_STATE_IDLE;
 	qh->hw_info1 = cpu_to_le32 (info1);
 	qh->hw_info2 = cpu_to_le32 (info2);
 
 	/* initialize sw and hw queues with these qtds */
-	list_splice (qtd_list, &qh->qtd_list);
-	qh_update (qh, list_entry (qtd_list->next, struct ehci_qtd, qtd_list));
+	if (!list_empty (qtd_list)) {
+		list_splice (qtd_list, &qh->qtd_list);
+		qh_update (qh, list_entry (qtd_list->next, struct ehci_qtd, qtd_list));
+	} else {
+		qh->hw_qtd_next = qh->hw_alt_next = EHCI_LIST_END;
+	}
 
 	/* initialize data toggle state */
-	if (!usb_pipecontrol (urb->pipe))
-		clear_toggle (urb->dev,
-			usb_pipeendpoint (urb->pipe),
-			usb_pipeout (urb->pipe),
-			qh);
+	clear_toggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, qh);
 
+done:
 	return qh;
 }
+#undef hb_mult
+#undef hb_packet
 
 /*-------------------------------------------------------------------------*/
 
@@ -719,8 +722,7 @@
 		u32	cmd = readl (&ehci->regs->command);
 
 		/* in case a clear of CMD_ASE didn't take yet */
-		while (readl (&ehci->regs->status) & STS_ASS)
-			udelay (100);
+		(void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
 
 		qh->hw_info1 |= __constant_cpu_to_le32 (QH_HEAD); /* [4.8] */
 		qh->qh_next.qh = qh;
@@ -743,58 +745,58 @@
 	}
 	qh->qh_state = QH_STATE_LINKED;
 	/* qtd completions reported later by interrupt */
+
+	ehci->async_idle = 0;
 }
 
 /*-------------------------------------------------------------------------*/
 
-static int
-submit_async (
+/*
+ * For control/bulk/interrupt, return QH with these TDs appended.
+ * Allocates and initializes the QH if necessary.
+ * Returns null if it can't allocate a QH it needs to.
+ * If the QH has TDs (urbs) already, that's great.
+ */
+static struct ehci_qh *qh_append_tds (
 	struct ehci_hcd		*ehci,
 	struct urb		*urb,
 	struct list_head	*qtd_list,
-	int			mem_flags
-) {
-	struct ehci_qtd		*qtd;
-	struct hcd_dev		*dev;
-	int			epnum;
-	unsigned long		flags;
+	int			epnum,
+	void			**ptr
+)
+{
 	struct ehci_qh		*qh = 0;
 
-	qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
-	dev = (struct hcd_dev *)urb->dev->hcpriv;
-	epnum = usb_pipeendpoint (urb->pipe);
-	if (usb_pipein (urb->pipe))
-		epnum |= 0x10;
-
-	vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]",
-		ehci->hcd.bus_name, urb, urb->transfer_buffer_length,
-		epnum & 0x0f, (epnum & 0x10) ? "in" : "out",
-		qtd, dev ? dev->ep [epnum] : (void *)~0);
-
-	spin_lock_irqsave (&ehci->lock, flags);
-
-	qh = (struct ehci_qh *) dev->ep [epnum];
+	qh = (struct ehci_qh *) *ptr;
 	if (likely (qh != 0)) {
-		u32	hw_next = QTD_NEXT (qtd->qtd_dma);
+		struct ehci_qtd	*qtd;
+
+		if (unlikely (list_empty (qtd_list)))
+			qtd = 0;
+		else
+			qtd = list_entry (qtd_list->next, struct ehci_qtd,
+					qtd_list);
 
 		/* maybe patch the qh used for set_address */
 		if (unlikely (epnum == 0
 				&& le32_to_cpu (qh->hw_info1 & 0x7f) == 0))
 			qh->hw_info1 |= cpu_to_le32 (usb_pipedevice(urb->pipe));
 
-		/* is an URB is queued to this qh already? */
-		if (unlikely (!list_empty (&qh->qtd_list))) {
+		/* append to tds already queued to this qh? */
+		if (unlikely (!list_empty (&qh->qtd_list) && qtd)) {
 			struct ehci_qtd		*last_qtd;
 			int			short_rx = 0;
+			u32			hw_next;
 
 			/* update the last qtd's "next" pointer */
 			// dbg_qh ("non-empty qh", ehci, qh);
 			last_qtd = list_entry (qh->qtd_list.prev,
 					struct ehci_qtd, qtd_list);
+			hw_next = QTD_NEXT (qtd->qtd_dma);
 			last_qtd->hw_next = hw_next;
 
 			/* previous urb allows short rx? maybe optimize. */
-			if (!(last_qtd->urb->transfer_flags & USB_DISABLE_SPD)
+			if (!(last_qtd->urb->transfer_flags & URB_SHORT_NOT_OK)
 					&& (epnum & 0x10)) {
 				// only the last QTD for now
 				last_qtd->hw_alt_next = hw_next;
@@ -805,6 +807,7 @@
 			 * Interrupt code must cope with case of HC having it
 			 * cached, and clobbering these updates.
 			 * ... complicates getting rid of extra interrupts!
+			 * (Or:  use dummy td, so cache always stays valid.)
 			 */
 			if (qh->hw_current == cpu_to_le32 (last_qtd->qtd_dma)) {
 				wmb ();
@@ -824,31 +827,62 @@
 			 */
 
 			/* usb_clear_halt() means qh data toggle gets reset */
-			if (usb_pipebulk (urb->pipe)
-					&& unlikely (!usb_gettoggle (urb->dev,
+			if (unlikely (!usb_gettoggle (urb->dev,
 						(epnum & 0x0f),
 						!(epnum & 0x10)))) {
 				clear_toggle (urb->dev,
 					epnum & 0x0f, !(epnum & 0x10), qh);
 			}
-			qh_update (qh, qtd);
+			if (qtd)
+				qh_update (qh, qtd);
 		}
 		list_splice (qtd_list, qh->qtd_list.prev);
 
 	} else {
 		/* can't sleep here, we have ehci->lock... */
 		qh = ehci_qh_make (ehci, urb, qtd_list, SLAB_ATOMIC);
-		if (likely (qh != 0)) {
-			// dbg_qh ("new qh", ehci, qh);
-			dev->ep [epnum] = qh;
-		}
+		// if (qh) dbg_qh ("new qh", ehci, qh);
+		*ptr = qh;
 	}
+	if (qh)
+		urb->hcpriv = qh_get (qh);
+	return qh;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+submit_async (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	int			mem_flags
+) {
+	struct ehci_qtd		*qtd;
+	struct hcd_dev		*dev;
+	int			epnum;
+	unsigned long		flags;
+	struct ehci_qh		*qh = 0;
+
+	qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
+	dev = (struct hcd_dev *)urb->dev->hcpriv;
+	epnum = usb_pipeendpoint (urb->pipe);
+	if (usb_pipein (urb->pipe) && !usb_pipecontrol (urb->pipe))
+		epnum |= 0x10;
+
+	vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]",
+		hcd_to_bus (&ehci->hcd)->bus_name,
+		urb, urb->transfer_buffer_length,
+		epnum & 0x0f, (epnum & 0x10) ? "in" : "out",
+		qtd, dev ? dev->ep [epnum] : (void *)~0);
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	qh = qh_append_tds (ehci, urb, qtd_list, epnum, &dev->ep [epnum]);
 
 	/* Control/bulk operations through TTs don't need scheduling,
 	 * the HC and TT handle it when the TT has a buffer ready.
 	 */
 	if (likely (qh != 0)) {
-		urb->hcpriv = qh_get (qh);
 		if (likely (qh->qh_state == QH_STATE_IDLE))
 			qh_link_async (ehci, qh_get (qh));
 	}
@@ -869,16 +903,16 @@
 {
 	struct ehci_qh		*qh = ehci->reclaim;
 
+	del_timer (&ehci->watchdog);
+
 	qh->qh_state = QH_STATE_IDLE;
 	qh->qh_next.qh = 0;
 	qh_put (ehci, qh);			// refcount from reclaim 
 	ehci->reclaim = 0;
 	ehci->reclaim_ready = 0;
 
-	qh_completions (ehci, qh, 1);
+	qh_completions (ehci, qh);
 
-	// unlink any urb should now unlink all following urbs, so that
-	// relinking only happens for urbs before the unlinked ones.
 	if (!list_empty (&qh->qtd_list)
 			&& HCD_IS_RUNNING (ehci->hcd.state))
 		qh_link_async (ehci, qh);
@@ -886,7 +920,6 @@
 		qh_put (ehci, qh);		// refcount from async list
 }
 
-
 /* makes sure the async qh will become idle */
 /* caller must own ehci->lock */
 
@@ -916,13 +949,14 @@
 	if (unlikely (qh == ehci->async && qh->qh_next.qh == qh)) {
 		/* can't get here without STS_ASS set */
 		if (ehci->hcd.state != USB_STATE_HALT) {
-			if (cmd & CMD_PSE)
-				writel (cmd & ~CMD_ASE, &ehci->regs->command);
-			else {
-				ehci_ready (ehci);
-				while (readl (&ehci->regs->status) & STS_ASS)
-					udelay (100);
-			}
+			writel (cmd & ~CMD_ASE, &ehci->regs->command);
+			(void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
+#if 0
+			// one VT8235 system wants to die with STS_FATAL
+			// unless this qh is leaked here. others seem ok...
+			qh = qh_get (qh);
+			dbg_qh ("async/off", ehci, qh);
+#endif
 		}
 		qh->qh_next.qh = ehci->async = 0;
 
@@ -940,10 +974,6 @@
 	prev = ehci->async;
 	while (prev->qh_next.qh != qh && prev->qh_next.qh != ehci->async)
 		prev = prev->qh_next.qh;
-#ifdef DEBUG
-	if (prev->qh_next.qh != qh)
-		BUG ();
-#endif
 
 	if (qh->hw_info1 & __constant_cpu_to_le32 (QH_HEAD)) {
 		ehci->async = prev;
@@ -957,48 +987,63 @@
 	cmd |= CMD_IAAD;
 	writel (cmd, &ehci->regs->command);
 	/* posted write need not be known to HC yet ... */
+
+	mod_timer (&ehci->watchdog, jiffies + EHCI_WATCHDOG_JIFFIES);
 }
 
 /*-------------------------------------------------------------------------*/
 
-static void scan_async (struct ehci_hcd *ehci)
+static void
+scan_async (struct ehci_hcd *ehci)
 {
 	struct ehci_qh		*qh;
-	unsigned long		flags;
+	unsigned		count;
 
-	spin_lock_irqsave (&ehci->lock, flags);
 rescan:
 	qh = ehci->async;
+	count = 0;
 	if (likely (qh != 0)) {
 		do {
 			/* clean any finished work for this qh */
 			if (!list_empty (&qh->qtd_list)) {
 				// dbg_qh ("scan_async", ehci, qh);
 				qh = qh_get (qh);
-				spin_unlock_irqrestore (&ehci->lock, flags);
 
 				/* concurrent unlink could happen here */
-				qh_completions (ehci, qh, 1);
-
-				spin_lock_irqsave (&ehci->lock, flags);
+				count += qh_completions (ehci, qh);
 				qh_put (ehci, qh);
 			}
 
-			/* unlink idle entries (reduces PCI usage) */
+			/* unlink idle entries, reducing HC PCI usage as
+			 * well as HCD schedule-scanning costs.  removing
+			 * the last qh is deferred, since it's costly.
+			 *
+			 * FIXME don't unlink idle entries so quickly; it
+			 * can penalize (common) half duplex protocols.
+			 */
 			if (list_empty (&qh->qtd_list) && !ehci->reclaim) {
 				if (qh->qh_next.qh != qh) {
 					// dbg ("irq/empty");
 					start_unlink_async (ehci, qh);
-				} else {
-					// FIXME:  arrange to stop
-					// after it's been idle a while.
+				} else if (!timer_pending (&ehci->watchdog)) {
+					/* can't use IAA for last entry */
+					ehci->async_idle = 1;
+					mod_timer (&ehci->watchdog,
+						jiffies + EHCI_ASYNC_JIFFIES);
 				}
 			}
+
+			/* keep latencies down: let any irqs in */
+			if (count > max_completions) {
+				spin_unlock_irq (&ehci->lock);
+				cpu_relax ();
+				spin_lock_irq (&ehci->lock);
+				goto rescan;
+			}
+
 			qh = qh->qh_next.qh;
 			if (!qh)		/* unlinked? */
 				goto rescan;
 		} while (qh != ehci->async);
 	}
-
-	spin_unlock_irqrestore (&ehci->lock, flags);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hcd/ehci-sched.c linux-2.4.21/drivers/usb/hcd/ehci-sched.c
--- linux-2.4.20/drivers/usb/hcd/ehci-sched.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/hcd/ehci-sched.c	2002-12-18 18:58:06.000000000 +0000
@@ -33,19 +33,6 @@
  * or with "USB On The Go" additions to USB 2.0 ...)
  */
 
-/*
- * Ceiling microseconds (typical) for that many bytes at high speed
- * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
- * to preallocate bandwidth)
- */
-#define EHCI_HOST_DELAY	5	/* nsec, guess */
-#define HS_USECS(bytes) NS_TO_US ( ((55 * 8 * 2083)/1000) \
-	+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
-	+ EHCI_HOST_DELAY)
-#define HS_USECS_ISO(bytes) NS_TO_US ( ((long)(38 * 8 * 2.083)) \
-	+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
-	+ EHCI_HOST_DELAY)
-	
 static int ehci_get_frame (struct usb_hcd *hcd);
 
 /*-------------------------------------------------------------------------*/
@@ -124,6 +111,9 @@
 			/* is it in the S-mask? */
 			if (q->qh->hw_info2 & cpu_to_le32 (1 << uframe))
 				usecs += q->qh->usecs;
+			/* ... or C-mask? */
+			if (q->qh->hw_info2 & cpu_to_le32 (1 << (8 + uframe)))
+				usecs += q->qh->c_usecs;
 			q = &q->qh->qh_next;
 			break;
 		case Q_TYPE_FSTN:
@@ -181,15 +171,19 @@
 
 /*-------------------------------------------------------------------------*/
 
-static void enable_periodic (struct ehci_hcd *ehci)
+static int enable_periodic (struct ehci_hcd *ehci)
 {
 	u32	cmd;
+	int	status;
 
 	/* did clearing PSE did take effect yet?
 	 * takes effect only at frame boundaries...
 	 */
-	while (readl (&ehci->regs->status) & STS_PSS)
-		udelay (20);
+	status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125);
+	if (status != 0) {
+		ehci->hcd.state = USB_STATE_HALT;
+		return status;
+	}
 
 	cmd = readl (&ehci->regs->command) | CMD_PSE;
 	writel (cmd, &ehci->regs->command);
@@ -199,80 +193,104 @@
 	/* make sure tasklet scans these */
 	ehci->next_uframe = readl (&ehci->regs->frame_index)
 				% (ehci->periodic_size << 3);
+	return 0;
 }
 
-static void disable_periodic (struct ehci_hcd *ehci)
+static int disable_periodic (struct ehci_hcd *ehci)
 {
 	u32	cmd;
+	int	status;
 
 	/* did setting PSE not take effect yet?
 	 * takes effect only at frame boundaries...
 	 */
-	while (!(readl (&ehci->regs->status) & STS_PSS))
-		udelay (20);
+	status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
+	if (status != 0) {
+		ehci->hcd.state = USB_STATE_HALT;
+		return status;
+	}
 
 	cmd = readl (&ehci->regs->command) & ~CMD_PSE;
 	writel (cmd, &ehci->regs->command);
 	/* posted write ... */
 
 	ehci->next_uframe = -1;
+	return 0;
 }
 
 /*-------------------------------------------------------------------------*/
 
+// FIXME microframe periods not yet handled
+
 static void intr_deschedule (
 	struct ehci_hcd	*ehci,
-	unsigned	frame,
 	struct ehci_qh	*qh,
-	unsigned	period
+	int		wait
 ) {
-	unsigned long	flags;
-
-	period >>= 3;		// FIXME microframe periods not handled yet
-
-	spin_lock_irqsave (&ehci->lock, flags);
+	int		status;
+	unsigned	frame = qh->start;
 
 	do {
 		periodic_unlink (ehci, frame, qh);
 		qh_put (ehci, qh);
-		frame += period;
+		frame += qh->period;
 	} while (frame < ehci->periodic_size);
 
 	qh->qh_state = QH_STATE_UNLINK;
 	qh->qh_next.ptr = 0;
-	ehci->periodic_urbs--;
+	ehci->periodic_sched--;
 
 	/* maybe turn off periodic schedule */
-	if (!ehci->periodic_urbs)
-		disable_periodic (ehci);
-	else
+	if (!ehci->periodic_sched)
+		status = disable_periodic (ehci);
+	else {
+		status = 0;
 		vdbg ("periodic schedule still enabled");
-
-	spin_unlock_irqrestore (&ehci->lock, flags);
+	}
 
 	/*
 	 * If the hc may be looking at this qh, then delay a uframe
 	 * (yeech!) to be sure it's done.
 	 * No other threads may be mucking with this qh.
 	 */
-	if (((ehci_get_frame (&ehci->hcd) - frame) % period) == 0)
-		udelay (125);
+	if (((ehci_get_frame (&ehci->hcd) - frame) % qh->period) == 0) {
+		if (wait) {
+			udelay (125);
+			qh->hw_next = EHCI_LIST_END;
+		} else {
+			/* we may not be IDLE yet, but if the qh is empty
+			 * the race is very short.  then if qh also isn't
+			 * rescheduled soon, it won't matter.  otherwise...
+			 */
+			vdbg ("intr_deschedule...");
+		}
+	} else
+		qh->hw_next = EHCI_LIST_END;
 
 	qh->qh_state = QH_STATE_IDLE;
-	qh->hw_next = EHCI_LIST_END;
 
-	vdbg ("descheduled qh %p, per = %d frame = %d count = %d, urbs = %d",
-		qh, period, frame,
-		atomic_read (&qh->refcount), ehci->periodic_urbs);
+	/* update per-qh bandwidth utilization (for usbfs) */
+	hcd_to_bus (&ehci->hcd)->bandwidth_allocated -= 
+		(qh->usecs + qh->c_usecs) / qh->period;
+
+	dbg ("descheduled qh %p, period = %d frame = %d count = %d, urbs = %d",
+		qh, qh->period, frame,
+		atomic_read (&qh->refcount), ehci->periodic_sched);
 }
 
 static int check_period (
 	struct ehci_hcd *ehci, 
 	unsigned	frame,
-	int		uframe,
+	unsigned	uframe,
 	unsigned	period,
 	unsigned	usecs
 ) {
+	/* complete split running into next frame?
+	 * given FSTN support, we could sometimes check...
+	 */
+	if (uframe >= 8)
+		return 0;
+
 	/*
 	 * 80% periodic == 100 usec/uframe available
 	 * convert "usecs we need" to "max already claimed" 
@@ -284,6 +302,8 @@
 
 // FIXME delete when intr_submit handles non-empty queues
 // this gives us a one intr/frame limit (vs N/uframe)
+// ... and also lets us avoid tracking split transactions
+// that might collide at a given TT/hub.
 		if (ehci->pshadow [frame].ptr)
 			return 0;
 
@@ -298,226 +318,203 @@
 	return 1;
 }
 
-static int intr_submit (
-	struct ehci_hcd		*ehci,
-	struct urb		*urb,
-	struct list_head	*qtd_list,
-	int			mem_flags
-) {
-	unsigned		epnum, period;
-	unsigned short		usecs;
-	unsigned long		flags;
-	struct ehci_qh		*qh;
-	struct hcd_dev		*dev;
-	int			status = 0;
+static int check_intr_schedule (
+	struct ehci_hcd		*ehci, 
+	unsigned		frame,
+	unsigned		uframe,
+	const struct ehci_qh	*qh,
+	u32			*c_maskp
+)
+{
+    	int		retval = -ENOSPC;
 
-	/* get endpoint and transfer data */
-	epnum = usb_pipeendpoint (urb->pipe);
-	if (usb_pipein (urb->pipe))
-		epnum |= 0x10;
-	if (urb->dev->speed != USB_SPEED_HIGH) {
-		dbg ("no intr/tt scheduling yet"); 
-		status = -ENOSYS;
+	if (!check_period (ehci, frame, uframe, qh->period, qh->usecs))
+		goto done;
+	if (!qh->c_usecs) {
+		retval = 0;
+		*c_maskp = cpu_to_le32 (0);
 		goto done;
 	}
 
-	/*
-	 * NOTE: current completion/restart logic doesn't handle more than
-	 * one qtd in a periodic qh ... 16-20 KB/urb is pretty big for this.
-	 * such big requests need many periods to transfer.
+	/* This is a split transaction; check the bandwidth available for
+	 * the completion too.  Check both worst and best case gaps: worst
+	 * case is SPLIT near uframe end, and CSPLIT near start ... best is
+	 * vice versa.  Difference can be almost two uframe times, but we
+	 * reserve unnecessary bandwidth (waste it) this way.  (Actually
+	 * even better cases exist, like immediate device NAK.)
 	 *
-	 * FIXME want to change hcd core submit model to expect queuing
-	 * for all transfer types ... not just ISO and (with flag) BULK.
-	 * that means: getting rid of this check; handling the "interrupt
-	 * urb already queued" case below like bulk queuing is handled (no
-	 * errors possible!); and completly getting rid of that annoying
-	 * qh restart logic.  simpler/smaller overall, and more flexible.
+	 * FIXME don't even bother unless we know this TT is idle in that
+	 * range of uframes ... for now, check_period() allows only one
+	 * interrupt transfer per frame, so needn't check "TT busy" status
+	 * when scheduling a split (QH, SITD, or FSTN).
+	 *
+	 * FIXME ehci 0.96 and above can use FSTNs
 	 */
-	if (unlikely (qtd_list->next != qtd_list->prev)) {
-		dbg ("only one intr qtd per urb allowed"); 
-		status = -EINVAL;
+	if (!check_period (ehci, frame, uframe + qh->gap_uf + 1,
+				qh->period, qh->c_usecs))
 		goto done;
-	}
-
-	usecs = HS_USECS (urb->transfer_buffer_length);
-
-	/* FIXME handle HS periods of less than 1 frame. */
-	period = urb->interval >> 3;
-	if (period < 1) {
-		dbg ("intr period %d uframes, NYET!", urb->interval);
-		status = -EINVAL;
+	if (!check_period (ehci, frame, uframe + qh->gap_uf,
+				qh->period, qh->c_usecs))
 		goto done;
-	}
 
-	spin_lock_irqsave (&ehci->lock, flags);
-
-	/* get the qh (must be empty and idle) */
-	dev = (struct hcd_dev *)urb->dev->hcpriv;
-	qh = (struct ehci_qh *) dev->ep [epnum];
-	if (qh) {
-		/* only allow one queued interrupt urb per EP */
-		if (unlikely (qh->qh_state != QH_STATE_IDLE
-				|| !list_empty (&qh->qtd_list))) {
-			dbg ("interrupt urb already queued");
-			status = -EBUSY;
-		} else {
-			/* maybe reset hardware's data toggle in the qh */
-			if (unlikely (!usb_gettoggle (urb->dev, epnum & 0x0f,
-					!(epnum & 0x10)))) {
-				qh->hw_token |=
-					__constant_cpu_to_le32 (QTD_TOGGLE);
-				usb_settoggle (urb->dev, epnum & 0x0f,
-					!(epnum & 0x10), 1);
-			}
-			/* trust the QH was set up as interrupt ... */
-			list_splice (qtd_list, &qh->qtd_list);
-			qh_update (qh, list_entry (qtd_list->next,
-						struct ehci_qtd, qtd_list));
-			qtd_list = &qh->qtd_list;
-		}
-	} else {
-		/* can't sleep here, we have ehci->lock... */
-		qh = ehci_qh_make (ehci, urb, qtd_list, SLAB_ATOMIC);
-		if (likely (qh != 0)) {
-			// dbg ("new INTR qh %p", qh);
-			dev->ep [epnum] = qh;
-			qtd_list = &qh->qtd_list;
-		} else
-			status = -ENOMEM;
-	}
+	*c_maskp = cpu_to_le32 (0x03 << (8 + uframe + qh->gap_uf));
+	retval = 0;
+done:
+	return retval;
+}
 
-	/* Schedule this periodic QH. */
-	if (likely (status == 0)) {
-		unsigned	frame = period;
+static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	int 		status;
+	unsigned	uframe;
+	u32		c_mask;
+	unsigned	frame;		/* 0..(qh->period - 1), or NO_FRAME */
 
-		qh->hw_next = EHCI_LIST_END;
-		qh->usecs = usecs;
+	qh->hw_next = EHCI_LIST_END;
+	frame = qh->start;
 
-		urb->hcpriv = qh_get (qh);
+	/* reuse the previous schedule slots, if we can */
+	if (frame < qh->period) {
+		uframe = ffs (le32_to_cpup (&qh->hw_info2) & 0x00ff);
+		status = check_intr_schedule (ehci, frame, --uframe,
+				qh, &c_mask);
+	} else {
+		uframe = 0;
+		c_mask = 0;
 		status = -ENOSPC;
+	}
 
-		/* pick a set of schedule slots, link the QH into them */
+	/* else scan the schedule to find a group of slots such that all
+	 * uframes have enough periodic bandwidth available.
+	 */
+	if (status) {
+		frame = qh->period - 1;
 		do {
-			int	uframe;
-
-			/* pick a set of slots such that all uframes have
-			 * enough periodic bandwidth available.
-			 *
-			 * FIXME for TT splits, need uframes for start and end.
-			 * FSTNs can put end into next frame (uframes 0 or 1).
-			 */
-			frame--;
 			for (uframe = 0; uframe < 8; uframe++) {
-				if (check_period (ehci, frame, uframe,
-						period, usecs) != 0)
+				status = check_intr_schedule (ehci,
+						frame, uframe, qh,
+						&c_mask);
+				if (status == 0)
 					break;
 			}
-			if (uframe == 8)
-				continue;
+		} while (status && --frame);
+		if (status)
+			goto done;
+		qh->start = frame;
+
+		/* reset S-frame and (maybe) C-frame masks */
+		qh->hw_info2 &= ~0xffff;
+		qh->hw_info2 |= cpu_to_le32 (1 << uframe) | c_mask;
+	} else
+		dbg ("reused previous qh %p schedule", qh);
+
+	/* stuff into the periodic schedule */
+	qh->qh_state = QH_STATE_LINKED;
+	dbg ("scheduled qh %p usecs %d/%d period %d.0 starting %d.%d (gap %d)",
+		qh, qh->usecs, qh->c_usecs,
+		qh->period, frame, uframe, qh->gap_uf);
+	do {
+		if (unlikely (ehci->pshadow [frame].ptr != 0)) {
 
-			/* QH will run once each period, starting there  */
-			urb->start_frame = frame;
-			status = 0;
-
-			/* set S-frame mask */
-			qh->hw_info2 |= cpu_to_le32 (1 << uframe);
-			// dbg_qh ("Schedule INTR qh", ehci, qh);
-
-			/* stuff into the periodic schedule */
-			qh->qh_state = QH_STATE_LINKED;
-			vdbg ("qh %p usecs %d period %d starting %d.%d",
-				qh, qh->usecs, period, frame, uframe);
-			do {
-				if (unlikely (ehci->pshadow [frame].ptr != 0)) {
 // FIXME -- just link toward the end, before any qh with a shorter period,
-// AND handle it already being (implicitly) linked into this frame
-// AS WELL AS updating the check_period() logic
-					BUG ();
-				} else {
-					ehci->pshadow [frame].qh = qh_get (qh);
-					ehci->periodic [frame] =
-						QH_NEXT (qh->qh_dma);
-				}
-				wmb ();
-				frame += period;
-			} while (frame < ehci->periodic_size);
-
-			/* update bandwidth utilization records (for usbfs) */
-			usb_claim_bandwidth (urb->dev, urb, usecs/period, 0);
-
-			/* maybe enable periodic schedule processing */
-			if (!ehci->periodic_urbs++)
-				enable_periodic (ehci);
-			break;
+// AND accomodate it already having been linked here (after some other qh)
+// AS WELL AS updating the schedule checking logic
+
+			BUG ();
+		} else {
+			ehci->pshadow [frame].qh = qh_get (qh);
+			ehci->periodic [frame] =
+				QH_NEXT (qh->qh_dma);
+		}
+		wmb ();
+		frame += qh->period;
+	} while (frame < ehci->periodic_size);
+
+	/* update per-qh bandwidth for usbfs */
+	hcd_to_bus (&ehci->hcd)->bandwidth_allocated += 
+		(qh->usecs + qh->c_usecs) / qh->period;
+
+	/* maybe enable periodic schedule processing */
+	if (!ehci->periodic_sched++)
+		status = enable_periodic (ehci);
+done:
+	return status;
+}
 
-		} while (frame);
+static int intr_submit (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	int			mem_flags
+) {
+	unsigned		epnum;
+	unsigned long		flags;
+	struct ehci_qh		*qh;
+	struct hcd_dev		*dev;
+	int			is_input;
+	int			status = 0;
+	struct list_head	empty;
+
+	/* get endpoint and transfer/schedule data */
+	epnum = usb_pipeendpoint (urb->pipe);
+	is_input = usb_pipein (urb->pipe);
+	if (is_input)
+		epnum |= 0x10;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	dev = (struct hcd_dev *)urb->dev->hcpriv;
+
+	/* get qh and force any scheduling errors */
+	INIT_LIST_HEAD (&empty);
+	qh = qh_append_tds (ehci, urb, &empty, epnum, &dev->ep [epnum]);
+	if (qh == 0) {
+		status = -ENOMEM;
+		goto done;
 	}
-	spin_unlock_irqrestore (&ehci->lock, flags);
+	if (qh->qh_state == QH_STATE_IDLE) {
+		if ((status = qh_schedule (ehci, qh)) != 0)
+			goto done;
+	}
+
+	/* then queue the urb's tds to the qh */
+	qh = qh_append_tds (ehci, urb, qtd_list, epnum, &dev->ep [epnum]);
+	BUG_ON (qh == 0);
+
+	/* ... update usbfs periodic stats */
+	hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs++;
+
 done:
+	spin_unlock_irqrestore (&ehci->lock, flags);
 	if (status)
 		qtd_list_free (ehci, urb, qtd_list);
 
 	return status;
 }
 
-static unsigned long
+static unsigned
 intr_complete (
 	struct ehci_hcd	*ehci,
 	unsigned	frame,
-	struct ehci_qh	*qh,
-	unsigned long	flags		/* caller owns ehci->lock ... */
+	struct ehci_qh	*qh
 ) {
-	struct ehci_qtd	*qtd;
-	struct urb	*urb;
-	int		unlinking;
+	unsigned	count;
 
 	/* nothing to report? */
 	if (likely ((qh->hw_token & __constant_cpu_to_le32 (QTD_STS_ACTIVE))
 			!= 0))
-		return flags;
+		return 0;
 	if (unlikely (list_empty (&qh->qtd_list))) {
 		dbg ("intr qh %p no TDs?", qh);
-		return flags;
+		return 0;
 	}
 	
-	qtd = list_entry (qh->qtd_list.next, struct ehci_qtd, qtd_list);
-	urb = qtd->urb;
-	unlinking = (urb->status == -ENOENT) || (urb->status == -ECONNRESET);
-
-	/* call any completions, after patching for reactivation */
-	spin_unlock_irqrestore (&ehci->lock, flags);
-	/* NOTE:  currently restricted to one qtd per qh! */
-	if (qh_completions (ehci, qh, 0) == 0)
-		urb = 0;
-	spin_lock_irqsave (&ehci->lock, flags);
+	/* handle any completions */
+	count = qh_completions (ehci, qh);
 
-	/* never reactivate requests that were unlinked ... */
-	if (likely (urb != 0)) {
-		if (unlinking
-				|| urb->status == -ECONNRESET
-				|| urb->status == -ENOENT
-				// || (urb->dev == null)
-				|| ehci->hcd.state == USB_STATE_HALT)
-			urb = 0;
-		// FIXME look at all those unlink cases ... we always
-		// need exactly one completion that reports unlink.
-		// the one above might not have been it!
-	}
-
-	/* normally reactivate */
-	if (likely (urb != 0)) {
-		if (usb_pipeout (urb->pipe))
-			pci_dma_sync_single (ehci->hcd.pdev,
-				qtd->buf_dma,
-				urb->transfer_buffer_length,
-				PCI_DMA_TODEVICE);
-		urb->status = -EINPROGRESS;
-		urb->actual_length = 0;
+	if (unlikely (list_empty (&qh->qtd_list)))
+		intr_deschedule (ehci, qh, 0);
 
-		/* patch qh and restart */
-		qh_update (qh, qtd);
-	}
-	return flags;
+	return count;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -527,11 +524,6 @@
 {
 	struct ehci_itd *first_itd = urb->hcpriv;
 
-	pci_unmap_single (ehci->hcd.pdev,
-		first_itd->buf_dma, urb->transfer_buffer_length,
-		usb_pipein (urb->pipe)
-		    ? PCI_DMA_FROMDEVICE
-		    : PCI_DMA_TODEVICE);
 	while (!list_empty (&first_itd->itd_list)) {
 		struct ehci_itd	*itd;
 
@@ -557,6 +549,7 @@
 	u32		buf1;
 	unsigned	i, epnum, maxp, multi;
 	unsigned	length;
+	int		is_input;
 
 	itd->hw_next = EHCI_LIST_END;
 	itd->urb = urb;
@@ -578,7 +571,8 @@
 	 * as encoded in the ep descriptor's maxpacket field
 	 */
 	epnum = usb_pipeendpoint (urb->pipe);
-	if (usb_pipein (urb->pipe)) {
+	is_input = usb_pipein (urb->pipe);
+	if (is_input) {
 		maxp = urb->dev->epmaxpacketin [epnum];
 		buf1 = (1 << 11);
 	} else {
@@ -598,7 +592,7 @@
 			urb->iso_frame_desc [index].length);
 		return -ENOSPC;
 	}
-	itd->usecs = HS_USECS_ISO (length);
+	itd->usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 1, length);
 
 	/* "plus" info in low order bits of buffer pointers */
 	itd->hw_bufp [0] |= cpu_to_le32 ((epnum << 8) | urb->dev->devnum);
@@ -625,16 +619,7 @@
 	int			frame_index;
 	struct ehci_itd		*first_itd, *itd;
 	int			status;
-	dma_addr_t		buf_dma, itd_dma;
-
-	/* set up one dma mapping for this urb */
-	buf_dma = pci_map_single (ehci->hcd.pdev,
-		urb->transfer_buffer, urb->transfer_buffer_length,
-		usb_pipein (urb->pipe)
-		    ? PCI_DMA_FROMDEVICE
-		    : PCI_DMA_TODEVICE);
-	if (buf_dma == 0)
-		return -ENOMEM;
+	dma_addr_t		itd_dma;
 
 	/* allocate/init ITDs */
 	for (frame_index = 0, first_itd = 0;
@@ -648,7 +633,8 @@
 		memset (itd, 0, sizeof *itd);
 		itd->itd_dma = itd_dma;
 
-		status = itd_fill (ehci, itd, urb, frame_index, buf_dma);
+		status = itd_fill (ehci, itd, urb, frame_index,
+				urb->transfer_dma);
 		if (status != 0)
 			goto fail;
 
@@ -737,7 +723,7 @@
 
 	/* calculate the legal range [start,max) */
 	now = readl (&ehci->regs->frame_index) + 1;	/* next uframe */
-	if (!ehci->periodic_urbs)
+	if (!ehci->periodic_sched)
 		now += 8;				/* startup delay */
 	now %= mod;
 	end = now + mod;
@@ -857,8 +843,12 @@
 		usb_claim_bandwidth (urb->dev, urb, usecs, 1);
 
 		/* maybe enable periodic schedule processing */
-		if (!ehci->periodic_urbs++)
-			enable_periodic (ehci);
+		if (!ehci->periodic_sched++) {
+			if ((status =  enable_periodic (ehci)) != 0) {
+				// FIXME deschedule right away
+				err ("itd_schedule, enable = %d", status);
+			}
+		}
 
 		return 0;
 
@@ -873,15 +863,14 @@
 
 #define	ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
 
-static unsigned long
+static unsigned
 itd_complete (
 	struct ehci_hcd	*ehci,
 	struct ehci_itd	*itd,
-	unsigned	uframe,
-	unsigned long	flags
+	unsigned	uframe
 ) {
 	struct urb				*urb = itd->urb;
-	struct iso_packet_descriptor		*desc;
+	struct usb_iso_packet_descriptor	*desc;
 	u32					t;
 
 	/* update status for this uframe's transfers */
@@ -916,7 +905,7 @@
 
 	/* handle completion now? */
 	if ((itd->index + 1) != urb->number_of_packets)
-		return flags;
+		return 0;
 
 	/*
 	 * Always give the urb back to the driver ... expect it to submit
@@ -931,16 +920,17 @@
 	if (urb->status == -EINPROGRESS)
 		urb->status = 0;
 
-	spin_unlock_irqrestore (&ehci->lock, flags);
+	/* complete() can reenter this HCD */
+	spin_unlock (&ehci->lock);
 	usb_hcd_giveback_urb (&ehci->hcd, urb);
-	spin_lock_irqsave (&ehci->lock, flags);
+	spin_lock (&ehci->lock);
 
 	/* defer stopping schedule; completion can submit */
-	ehci->periodic_urbs--;
-	if (!ehci->periodic_urbs)
-		disable_periodic (ehci);
+	ehci->periodic_sched--;
+	if (!ehci->periodic_sched)
+		(void) disable_periodic (ehci);
 
-	return flags;
+	return 1;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -952,10 +942,6 @@
 
 	dbg ("itd_submit urb %p", urb);
 
-	/* NOTE DMA mapping assumes this ... */
-	if (urb->iso_frame_desc [0].offset != 0)
-		return -EINVAL;
-	
 	/* allocate ITDs w/o locking anything */
 	status = itd_urb_transaction (ehci, urb, mem_flags);
 	if (status < 0)
@@ -978,130 +964,21 @@
 /*
  * "Split ISO TDs" ... used for USB 1.1 devices going through
  * the TTs in USB 2.0 hubs.
+ *
+ * FIXME not yet implemented
  */
 
-static void
-sitd_free (struct ehci_hcd *ehci, struct ehci_sitd *sitd)
-{
-	pci_pool_free (ehci->sitd_pool, sitd, sitd->sitd_dma);
-}
-
-static struct ehci_sitd *
-sitd_make (
-	struct ehci_hcd	*ehci,
-	struct urb	*urb,
-	unsigned	index,		// urb->iso_frame_desc [index]
-	unsigned	uframe,		// scheduled start
-	dma_addr_t	dma,		// mapped transfer buffer
-	int		mem_flags
-) {
-	struct ehci_sitd	*sitd;
-	unsigned		length;
-
-	sitd = pci_pool_alloc (ehci->sitd_pool, mem_flags, &dma);
-	if (!sitd)
-		return sitd;
-	sitd->urb = urb;
-	length = urb->iso_frame_desc [index].length;
-	dma += urb->iso_frame_desc [index].offset;
-
-#if 0
-	// FIXME:  do the rest!
-#else
-	sitd_free (ehci, sitd);
-	return 0;
-#endif
-
-}
-
-static void
-sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd)
-{
-	u32		ptr;
-
-	ptr = cpu_to_le32 (sitd->sitd_dma | 2);	// type 2 == sitd
-	if (ehci->pshadow [frame].ptr) {
-		if (!sitd->sitd_next.ptr) {
-			sitd->sitd_next = ehci->pshadow [frame];
-			sitd->hw_next = ehci->periodic [frame];
-		} else if (sitd->sitd_next.ptr != ehci->pshadow [frame].ptr) {
-			dbg ("frame %d sitd link goof", frame);
-			BUG ();
-		}
-	}
-	ehci->pshadow [frame].sitd = sitd;
-	ehci->periodic [frame] = ptr;
-}
-
-static unsigned long
-sitd_complete (
-	struct ehci_hcd *ehci,
-	struct ehci_sitd	*sitd,
-	unsigned long		flags
-) {
-	// FIXME -- implement!
-
-	dbg ("NYI -- sitd_complete");
-	return flags;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
-{
-	// struct ehci_sitd	*first_sitd = 0;
-	unsigned		frame_index;
-	dma_addr_t		dma;
-
-	dbg ("NYI -- sitd_submit");
-
-	// FIXME -- implement!
-
-	// FIXME:  setup one big dma mapping
-	dma = 0;
-
-	for (frame_index = 0;
-			frame_index < urb->number_of_packets;
-			frame_index++) {
-		struct ehci_sitd	*sitd;
-		unsigned		uframe;
-
-		// FIXME:  use real arguments, schedule this!
-		uframe = -1;
-
-		sitd = sitd_make (ehci, urb, frame_index,
-				uframe, dma, mem_flags);
-
-		if (sitd) {
-    /*
-			if (first_sitd)
-				list_add_tail (&sitd->sitd_list,
-						&first_sitd->sitd_list);
-			else
-				first_sitd = sitd;
-    */
-		} else {
-			// FIXME:  clean everything up
-		}
-	}
-
-	// if we have a first sitd, then
-		// store them all into the periodic schedule!
-		// urb->hcpriv = first sitd in sitd_list
-
-	return -ENOSYS;
-}
 #endif /* have_split_iso */
 
 /*-------------------------------------------------------------------------*/
 
-static void scan_periodic (struct ehci_hcd *ehci)
+static void
+scan_periodic (struct ehci_hcd *ehci)
 {
 	unsigned	frame, clock, now_uframe, mod;
-	unsigned long	flags;
+	unsigned	count = 0;
 
 	mod = ehci->periodic_size << 3;
-	spin_lock_irqsave (&ehci->lock, flags);
 
 	/*
 	 * When running, scan from last scan point up to "now"
@@ -1122,6 +999,14 @@
 		u32			type, *hw_p;
 		unsigned		uframes;
 
+		/* keep latencies down: let any irqs in */
+		if (count > max_completions) {
+			spin_unlock_irq (&ehci->lock);
+			cpu_relax ();
+			count = 0;
+			spin_lock_irq (&ehci->lock);
+		}
+
 restart:
 		/* scan schedule to _before_ current frame index */
 		if (frame == clock)
@@ -1145,8 +1030,8 @@
 				last = (q.qh->hw_next == EHCI_LIST_END);
 				temp = q.qh->qh_next;
 				type = Q_NEXT_TYPE (q.qh->hw_next);
-				flags = intr_complete (ehci, frame,
-						qh_get (q.qh), flags);
+				count += intr_complete (ehci, frame,
+						qh_get (q.qh));
 				qh_put (ehci, q.qh);
 				q = temp;
 				break;
@@ -1178,8 +1063,8 @@
 						type = Q_NEXT_TYPE (*hw_p);
 
 						/* might free q.itd ... */
-						flags = itd_complete (ehci,
-							temp.itd, uf, flags);
+						count += itd_complete (ehci,
+							temp.itd, uf);
 						break;
 					}
 				}
@@ -1195,7 +1080,7 @@
 #ifdef have_split_iso
 			case Q_TYPE_SITD:
 				last = (q.sitd->hw_next == EHCI_LIST_END);
-				flags = sitd_complete (ehci, q.sitd, flags);
+				sitd_complete (ehci, q.sitd);
 				type = Q_NEXT_TYPE (q.sitd->hw_next);
 
 				// FIXME unlink SITD after split completes
@@ -1241,5 +1126,4 @@
 		} else
 			frame = (frame + 1) % ehci->periodic_size;
 	} 
-	spin_unlock_irqrestore (&ehci->lock, flags);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hcd/ehci.h linux-2.4.21/drivers/usb/hcd/ehci.h
--- linux-2.4.20/drivers/usb/hcd/ehci.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/usb/hcd/ehci.h	2002-12-18 18:58:06.000000000 +0000
@@ -21,6 +21,23 @@
 
 /* definitions used for the EHCI driver */
 
+/* statistics can be kept for for tuning/monitoring */
+struct ehci_stats {
+	/* irq usage */
+	unsigned long		normal;
+	unsigned long		error;
+	unsigned long		reclaim;
+
+	/* termination of urbs from core */
+	unsigned long		complete;
+	unsigned long		unlink;
+
+	/* qhs patched to recover from td queueing race
+	 * (can avoid by using 'dummy td', allowing fewer irqs)
+	 */
+	unsigned long		qpatch;
+};
+
 /* ehci_hcd->lock guards shared data against other CPUs:
  *   ehci_hcd:	async, reclaim, periodic (and shadow), ...
  *   hcd_dev:	ep[]
@@ -39,7 +56,8 @@
 	/* async schedule support */
 	struct ehci_qh		*async;
 	struct ehci_qh		*reclaim;
-	int			reclaim_ready;
+	int			reclaim_ready : 1,
+				async_idle : 1;
 
 	/* periodic schedule support */
 #define	DEFAULT_I_TDPS		1024		/* some HCs can do less */
@@ -50,7 +68,7 @@
 
 	union ehci_shadow	*pshadow;	/* mirror hw periodic table */
 	int			next_uframe;	/* scan periodic, start here */
-	unsigned		periodic_urbs;	/* how many urbs scheduled? */
+	unsigned		periodic_sched;	/* periodic activity count */
 
 	/* deferred work from IRQ, etc */
 	struct tasklet_struct	tasklet;
@@ -69,10 +87,19 @@
 	struct pci_pool		*qtd_pool;	/* one or more per qh */
 	struct pci_pool		*itd_pool;	/* itd per iso urb */
 	struct pci_pool		*sitd_pool;	/* sitd per split iso urb */
+
+	struct timer_list	watchdog;
+
+#ifdef EHCI_STATS
+	struct ehci_stats	stats;
+#	define COUNT(x) do { (x)++; } while (0)
+#else
+#	define COUNT(x) do {} while (0)
+#endif
 };
 
 /* unwrap an HCD pointer to get an EHCI_HCD pointer */ 
-#define hcd_to_ehci(hcd_ptr) list_entry(hcd_ptr, struct ehci_hcd, hcd)
+#define hcd_to_ehci(hcd_ptr) container_of(hcd_ptr, struct ehci_hcd, hcd)
 
 /* NOTE:  urb->transfer_flags expected to not use this bit !!! */
 #define EHCI_STATE_UNLINK	0x8000		/* urb being unlinked */
@@ -219,7 +246,6 @@
 
 	/* dma same in urb's qtds, except 1st control qtd (setup buffer) */
 	struct urb		*urb;			/* qtd's urb */
-	dma_addr_t		buf_dma;		/* buffer address */
 	size_t			length;			/* length of buffer */
 } __attribute__ ((aligned (32)));
 
@@ -287,15 +313,20 @@
 	struct list_head	qtd_list;	/* sw qtd list */
 
 	atomic_t		refcount;
-	unsigned short		usecs;		/* intr bandwidth */
-	short			qh_state;
+
+	u8			qh_state;
 #define	QH_STATE_LINKED		1		/* HC sees this */
 #define	QH_STATE_UNLINK		2		/* HC may still see this */
 #define	QH_STATE_IDLE		3		/* HC doesn't see this */
 
-#ifdef EHCI_SOFT_RETRIES
-	int			retries;
-#endif
+	/* periodic schedule info */
+	u8			usecs;		/* intr bandwidth */
+	u8			gap_uf;		/* uframes split/csplit gap */
+	u8			c_usecs;	/* ... split completion bw */
+	unsigned short		period;		/* polling interval */
+	unsigned short		start;		/* where polling starts */
+#define NO_FRAME ((unsigned short)~0)			/* pick new start */
+
 } __attribute__ ((aligned (32)));
 
 /*-------------------------------------------------------------------------*/
@@ -360,6 +391,9 @@
 	union ehci_shadow	sitd_next;	/* ptr to periodic q entry */
 	struct urb		*urb;
 	dma_addr_t		buf_dma;	/* buffer address */
+
+	unsigned short		usecs;		/* start bandwidth */
+	unsigned short		c_usecs;	/* completion bandwidth */
 } __attribute__ ((aligned (32)));
 
 /*-------------------------------------------------------------------------*/
@@ -382,4 +416,39 @@
 	union ehci_shadow	fstn_next;	/* ptr to periodic q entry */
 } __attribute__ ((aligned (32)));
 
+/*-------------------------------------------------------------------------*/
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,32)
+
+#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb)
+#define STUB_DEBUG_FILES
+
+static inline int hcd_register_root (struct usb_hcd *hcd)
+{
+	return usb_new_device (hcd_to_bus (hcd)->root_hub);
+}
+
+#else	/* LINUX_VERSION_CODE */
+
+// hcd_to_bus() eventually moves to hcd.h on 2.5 too
+static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
+	{ return &hcd->self; }
+// ... as does hcd_register_root()
+static inline int hcd_register_root (struct usb_hcd *hcd)
+{
+	return usb_register_root_hub (
+		hcd_to_bus (hcd)->root_hub, &hcd->pdev->dev);
+}
+
+#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags)
+
+#ifndef DEBUG
+#define STUB_DEBUG_FILES
+#endif	/* DEBUG */
+
+#endif	/* LINUX_VERSION_CODE */
+
+/*-------------------------------------------------------------------------*/
+
 #endif /* __LINUX_EHCI_HCD_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hcd.c linux-2.4.21/drivers/usb/hcd.c
--- linux-2.4.20/drivers/usb/hcd.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/hcd.c	2002-12-18 18:58:08.000000000 +0000
@@ -296,7 +296,7 @@
 
 	// serial number
 	} else if (id == 1) {
-		strcpy (buf, hcd->bus_name);
+		strcpy (buf, hcd->bus->bus_name);
 
 	// product description
 	} else if (id == 2) {
@@ -392,7 +392,7 @@
 	case DeviceOutRequest | USB_REQ_SET_ADDRESS:
 		// wValue == urb->dev->devaddr
 		dbg ("%s root hub device address %d",
-			hcd->bus_name, wValue);
+			hcd->bus->bus_name, wValue);
 		break;
 
 	/* INTERFACE REQUESTS (no defined feature/status flags) */
@@ -506,7 +506,7 @@
 					&& rh_status_urb (hcd, urb) != 0) {
 				/* another driver snuck in? */
 				dbg ("%s, can't resubmit roothub status urb?",
-					hcd->bus_name);
+					hcd->bus->bus_name);
 				spin_unlock_irqrestore (&hcd_data_lock, flags);
 				BUG ();
 			}
@@ -687,6 +687,7 @@
 		base);
 
 // FIXME simpler: make "bus" be that data, not pointer to it.
+// (fixed in 2.5)
 	bus = usb_alloc_bus (&hcd_operations);
 	if (bus == NULL) {
 		dbg ("usb_alloc_bus fail");
@@ -695,7 +696,6 @@
 		goto clean_3;
 	}
 	hcd->bus = bus;
-	hcd->bus_name = dev->slot_name;		/* prefer bus->bus_name */
 	bus->bus_name = dev->slot_name;
 	hcd->product_desc = dev->name;
 	bus->hcpriv = (void *) hcd;
@@ -739,14 +739,14 @@
 	hcd = pci_get_drvdata(dev);
 	if (!hcd)
 		return;
-	info ("remove: %s, state %x", hcd->bus_name, hcd->state);
+	info ("remove: %s, state %x", hcd->bus->bus_name, hcd->state);
 
 	if (in_interrupt ()) BUG ();
 
 	hub = hcd->bus->root_hub;
 	hcd->state = USB_STATE_QUIESCING;
 
-	dbg ("%s: roothub graceful disconnect", hcd->bus_name);
+	dbg ("%s: roothub graceful disconnect", hcd->bus->bus_name);
 	usb_disconnect (&hub);
 	// usb_disconnect (&hcd->bus->root_hub);
 
@@ -817,7 +817,7 @@
 	int			retval;
 
 	hcd = pci_get_drvdata(dev);
-	info ("suspend %s to state %d", hcd->bus_name, state);
+	info ("suspend %s to state %d", hcd->bus->bus_name, state);
 
 	pci_save_state (dev, hcd->pci_state);
 
@@ -846,12 +846,12 @@
 	int			retval;
 
 	hcd = pci_get_drvdata(dev);
-	info ("resume %s", hcd->bus_name);
+	info ("resume %s", hcd->bus->bus_name);
 
 	/* guard against multiple resumes (APM bug?) */
 	atomic_inc (&hcd->resume_count);
 	if (atomic_read (&hcd->resume_count) != 1) {
-		err ("concurrent PCI resumes for %s", hcd->bus_name);
+		err ("concurrent PCI resumes for %s", hcd->bus->bus_name);
 		retval = 0;
 		goto done;
 	}
@@ -868,7 +868,8 @@
 
 	retval = hcd->driver->resume (hcd);
 	if (!HCD_IS_RUNNING (hcd->state)) {
-		dbg ("resume %s failure, retval %d", hcd->bus_name, retval);
+		dbg ("resume %s failure, retval %d",
+			hcd->bus->bus_name, retval);
 		hc_died (hcd);
 // FIXME:  recover, reset etc.
 	} else {
@@ -943,7 +944,8 @@
 		list_for_each (urblist, &dev->urb_list) {
 			urb = list_entry (urblist, struct urb, urb_list);
 			dbg ("shutdown %s urb %p pipe %x, current status %d",
-				hcd->bus_name, urb, urb->pipe, urb->status);
+				hcd->bus->bus_name,
+				urb, urb->pipe, urb->status);
 			if (urb->status == -EINPROGRESS)
 				urb->status = -ESHUTDOWN;
 		}
@@ -1067,8 +1069,6 @@
 	if (urb->transfer_buffer_length < 0)
 		return -EINVAL;
 
-	// FIXME set urb->transfer_dma and/or setup_dma 
-
 	if (urb->next) {
 		warn ("use explicit queuing not urb->next");
 		return -EINVAL;
@@ -1186,16 +1186,26 @@
 	if (status)
 		return status;
 
+	// NOTE:  2.5 does this if !URB_NO_DMA_MAP transfer flag
+	if (usb_pipecontrol (urb->pipe))
+		urb->setup_dma = pci_map_single (
+				hcd->pdev,
+				urb->setup_packet,
+				sizeof (struct usb_ctrlrequest),
+				PCI_DMA_TODEVICE);
+	if (urb->transfer_buffer_length != 0)
+		urb->transfer_dma = pci_map_single (
+				hcd->pdev,
+				urb->transfer_buffer,
+				urb->transfer_buffer_length,
+				usb_pipein (urb->pipe)
+				    ? PCI_DMA_FROMDEVICE
+				    : PCI_DMA_TODEVICE);
+
 	if (urb->dev == hcd->bus->root_hub)
 		status = rh_urb_enqueue (hcd, urb);
 	else
 		status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
-	/* urb->dev got nulled if hcd called giveback for us
-	 * NOTE: ref to urb->dev is a race without (2.5) refcounting,
-	 * unless driver only returns status when it didn't giveback 
-	 */
-	if (status && urb->dev)
-		urb_unlink (urb);
 	return status;
 }
 
@@ -1282,25 +1292,25 @@
 		goto done;
 	}
 
-	/* For non-periodic transfers, any status except -EINPROGRESS means
-	 * the HCD has already started to unlink this URB from the hardware.
-	 * In that case, there's no more work to do.
+	/* Any status except -EINPROGRESS means the HCD has already started
+	 * to return this URB to the driver.  In that case, there's no
+	 * more work for us to do.
 	 *
-	 * For periodic transfers, this is the only way to trigger unlinking
-	 * from the hardware.  Since we (currently) overload urb->status to
-	 * tell the driver to unlink, error status might get clobbered ...
-	 * unless that transfer hasn't yet restarted.  One such case is when
-	 * the URB gets unlinked from its completion handler.
+	 * There's much magic because of "automagic resubmit" of interrupt
+	 * transfers, stopped only by explicit unlinking.  We won't issue
+	 * an "it's unlinked" callback more than once, but device drivers
+	 * can need to retry (SMP, -EAGAIN) an unlink request as well as
+	 * fake out the "not yet completed" state (set -EINPROGRESS) if
+	 * unlinking from complete().  Automagic eventually vanishes.
 	 *
 	 * FIXME use an URB_UNLINKED flag to match URB_TIMEOUT_KILLED
 	 */
-	switch (usb_pipetype (urb->pipe)) {
-	case PIPE_CONTROL:
-	case PIPE_BULK:
-		if (urb->status != -EINPROGRESS) {
+	if (urb->status != -EINPROGRESS) {
+		if (usb_pipetype (urb->pipe) == PIPE_INTERRUPT)
+			retval = -EAGAIN;
+		else
 			retval = -EINVAL;
-			goto done;
-		}
+		goto done;
 	}
 
 	/* maybe set up to block on completion notification */
@@ -1340,7 +1350,7 @@
 			&& HCD_IS_RUNNING (hcd->state)
 			&& !retval) {
 		dbg ("%s: wait for giveback urb %p",
-			hcd->bus_name, urb);
+			hcd->bus->bus_name, urb);
 		wait_for_completion (&splice.done);
 	} else if ((urb->transfer_flags & USB_ASYNC_UNLINK) && retval == 0) {
 		return -EINPROGRESS;
@@ -1352,7 +1362,7 @@
 bye:
 	if (retval)
 		dbg ("%s: hcd_unlink_urb fail %d",
-		    hcd ? hcd->bus_name : "(no bus?)",
+		    hcd ? hcd->bus->bus_name : "(no bus?)",
 		    retval);
 	return retval;
 }
@@ -1385,7 +1395,7 @@
 	/* device driver problem with refcounts? */
 	if (!list_empty (&dev->urb_list)) {
 		dbg ("free busy dev, %s devnum %d (bug!)",
-			hcd->bus_name, udev->devnum);
+			hcd->bus->bus_name, udev->devnum);
 		return -EINVAL;
 	}
 
@@ -1460,7 +1470,17 @@
 		dbg ("giveback urb %p status %d len %d",
 			urb, urb->status, urb->actual_length);
 
-	// FIXME unmap urb->transfer_dma and/or setup_dma 
+	// NOTE:  2.5 does this if !URB_NO_DMA_MAP transfer flag
+	if (usb_pipecontrol (urb->pipe))
+		pci_unmap_single (hcd->pdev, urb->setup_dma,
+				sizeof (struct usb_ctrlrequest),
+				PCI_DMA_TODEVICE);
+	if (urb->transfer_buffer_length != 0)
+		pci_unmap_single (hcd->pdev, urb->transfer_dma,
+				urb->transfer_buffer_length,
+				usb_pipein (urb->pipe)
+				    ? PCI_DMA_FROMDEVICE
+				    : PCI_DMA_TODEVICE);
 
 	/* pass ownership to the completion handler */
 	urb->complete (urb);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hcd.h linux-2.4.21/drivers/usb/hcd.h
--- linux-2.4.20/drivers/usb/hcd.h	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/hcd.h	2002-12-18 18:58:02.000000000 +0000
@@ -36,7 +36,6 @@
 	struct usb_bus		*bus;		/* hcd is-a bus */
 	struct list_head	hcd_list;
 
-	const char		*bus_name;
 	const char		*product_desc;
 	const char		*description;	/* "ehci-hcd" etc */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hid-core.c linux-2.4.21/drivers/usb/hid-core.c
--- linux-2.4.20/drivers/usb/hid-core.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/hid-core.c	2002-12-18 18:58:09.000000000 +0000
@@ -1086,6 +1086,10 @@
 #define USB_DEVICE_ID_ATEN_2PORTKVM	0x2204
 #define USB_DEVICE_ID_ATEN_4PORTKVM	0x2205
 
+#define USB_VENDOR_ID_GRIFFIN		0x077d
+#define USB_DEVICE_ID_POWERMATE		0x0410 /* Griffin PowerMate */
+#define USB_DEVICE_ID_SOUNDKNOB		0x04AA /* Griffin SoundKnob */
+
 struct hid_blacklist {
 	__u16 idVendor;
 	__u16 idProduct;
@@ -1115,6 +1119,8 @@
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
 	{ 0, 0 }
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hpusbscsi.c linux-2.4.21/drivers/usb/hpusbscsi.c
--- linux-2.4.20/drivers/usb/hpusbscsi.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/hpusbscsi.c	2002-12-18 18:58:12.000000000 +0000
@@ -71,7 +71,7 @@
 
 #ifdef HPUSBSCSI_DEBUG
 #  define PDEBUG(level, fmt, args...) \
-          if (debug >= (level)) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , \
+          if (debug >= (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , \
                  ## args)
 #else
 #  define PDEBUG(level, fmt, args...) do {} while(0)
@@ -125,6 +125,7 @@
 	new->dev = dev;
 	init_waitqueue_head (&new->pending);
 	init_waitqueue_head (&new->deathrow);
+	init_MUTEX(&new->lock);
 	INIT_LIST_HEAD (&new->lh);
 
 
@@ -202,12 +203,12 @@
 {
 	struct hpusbscsi *hp = (struct hpusbscsi *)ptr;
 
+	down(&hp->lock);
 	usb_unlink_urb(&hp->controlurb);
 	usb_unlink_urb(&hp->dataurb);
 
-	spin_lock_irq(&io_request_lock);
 	hp->dev = NULL;
-	spin_unlock_irq(&io_request_lock);
+	up(&hp->lock);
 }
 
 static struct usb_device_id hpusbscsi_usb_ids[] = {
@@ -347,6 +348,15 @@
 	if ( srb->device->lun || srb->device->id || srb->device->channel ) {
 		srb->result = DID_BAD_TARGET;
 		callback(srb);
+		goto out_nolock;
+	}
+
+	/* to prevent a race with removal */
+	down(&hpusbscsi->lock);
+
+	if (hpusbscsi->dev == NULL) {
+		srb->result = DID_ERROR;
+		callback(srb);
 		goto out;
 	}
 
@@ -400,12 +410,7 @@
 	);
 	hpusbscsi->scallback = callback;
 	hpusbscsi->srb = srb;
-	
-	if (hpusbscsi->dev == NULL) {
-		srb->result = DID_ERROR;
-		callback(srb);
-		goto out;
-	}
+
 
 	res = usb_submit_urb(&hpusbscsi->dataurb);
 	if (res) {
@@ -417,6 +422,8 @@
 	}
 
 out:
+	up(&hpusbscsi->lock);
+out_nolock:
 	spin_lock_irq(&io_request_lock);
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hpusbscsi.h linux-2.4.21/drivers/usb/hpusbscsi.h
--- linux-2.4.20/drivers/usb/hpusbscsi.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21/drivers/usb/hpusbscsi.h	2002-12-18 18:58:03.000000000 +0000
@@ -29,6 +29,7 @@
 	u8 sense_command[SENSE_COMMAND_SIZE];
 
         int use_count;
+	struct semaphore lock;
         wait_queue_head_t pending;
         wait_queue_head_t deathrow;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/pegasus.c linux-2.4.21/drivers/usb/pegasus.c
--- linux-2.4.20/drivers/usb/pegasus.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/pegasus.c	2002-12-18 18:58:08.000000000 +0000
@@ -42,10 +42,12 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.4.26 (2002/03/21)"
+#define DRIVER_VERSION "v0.4.28 (2002/12/13)"
 #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
 #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
 
+static const char driver_name[] = "pegasus";
+
 #define	PEGASUS_USE_INTR
 #define	PEGASUS_WRITE_EEPROM
 #define	BMSR_MEDIA	(BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \
@@ -110,20 +112,18 @@
 	wake_up(&pegasus->ctrl_wait);
 }
 
-static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
+static int get_registers(pegasus_t * pegasus, u16 indx, u16 size,
 			 void *data)
 {
 	int ret;
-	unsigned char *buffer;
+	char *buffer;
 	DECLARE_WAITQUEUE(wait, current);
 
-	buffer = kmalloc(size, GFP_KERNEL);
+	buffer = kmalloc(size, GFP_DMA);
 	if (!buffer) {
-		err("unable to allocate memory for configuration descriptors");
-		return 0;
+		warn("%s: looks like we're out of memory", __FUNCTION__);
+		return -ENOMEM;
 	}
-	memcpy(buffer, data, size);
-
 	add_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	while (pegasus->flags & ETH_REGS_CHANGED)
@@ -160,17 +160,17 @@
 	return ret;
 }
 
-static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
+static int set_registers(pegasus_t * pegasus, u16 indx, u16 size,
 			 void *data)
 {
 	int ret;
-	unsigned char *buffer;
+	char *buffer;
 	DECLARE_WAITQUEUE(wait, current);
 
-	buffer = kmalloc(size, GFP_KERNEL);
+	buffer = kmalloc(size, GFP_DMA);
 	if (!buffer) {
-		err("unable to allocate memory for configuration descriptors");
-		return 0;
+		warn("%s: looks like we're out of memory", __FUNCTION__);
+		return -ENOMEM;
 	}
 	memcpy(buffer, data, size);
 
@@ -209,20 +209,18 @@
 	return ret;
 }
 
-static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
+static int set_register(pegasus_t * pegasus, u16 indx, u8 data)
 {
 	int ret;
-	unsigned char *buffer;
-	__u16 dat = data;
+	char *tmp;
 	DECLARE_WAITQUEUE(wait, current);
 
-	buffer = kmalloc(1, GFP_KERNEL);
-	if (!buffer) {
-		err("unable to allocate memory for configuration descriptors");
-		return 0;
+	tmp = kmalloc(1, GFP_DMA);
+	if (!tmp) {
+		warn("%s: looks like we're out of memory", __FUNCTION__);
+		return -ENOMEM;
 	}
-	memcpy(buffer, &data, 1);
-
+	memcpy(tmp, &data, 1);
 	add_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	while (pegasus->flags & ETH_REGS_CHANGED)
@@ -232,7 +230,7 @@
 
 	pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
 	pegasus->dr.bRequest = PEGASUS_REQ_SET_REG;
-	pegasus->dr.wValue = cpu_to_le16p(&dat);
+	pegasus->dr.wValue = cpu_to_le16p(&data);
 	pegasus->dr.wIndex = cpu_to_le16p(&indx);
 	pegasus->dr.wLength = cpu_to_le16(1);
 	pegasus->ctrl_urb->transfer_buffer_length = 1;
@@ -240,7 +238,7 @@
 	FILL_CONTROL_URB(pegasus->ctrl_urb, pegasus->usb,
 			 usb_sndctrlpipe(pegasus->usb, 0),
 			 (char *) &pegasus->dr,
-			 buffer, 1, ctrl_callback, pegasus);
+			 tmp, 1, ctrl_callback, pegasus);
 
 	add_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_UNINTERRUPTIBLE);
@@ -253,7 +251,7 @@
 	schedule();
 out:
 	remove_wait_queue(&pegasus->ctrl_wait, &wait);
-	kfree(buffer);
+	kfree(tmp);
 
 	return ret;
 }
@@ -281,11 +279,11 @@
 	return ret;
 }
 
-static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd)
+static int read_mii_word(pegasus_t * pegasus, u8 phy, u8 indx, u16 * regd)
 {
 	int i;
-	__u8 data[4] = { phy, 0, 0, indx };
-	__u16 regdi;
+	u8 data[4] = { phy, 0, 0, indx };
+	u16 regdi;
 
 	set_register(pegasus, PhyCtrl, 0);
 	set_registers(pegasus, PhyAddr, sizeof(data), data);
@@ -305,10 +303,19 @@
 	return 1;
 }
 
-static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd)
+static int mdio_read(struct net_device *dev, int phy_id, int loc)
+{
+	pegasus_t *pegasus = (pegasus_t *) dev->priv;
+	int res;
+
+	read_mii_word(pegasus, phy_id, loc, (u16 *) & res);
+	return res & 0xffff;
+}
+
+static int write_mii_word(pegasus_t * pegasus, u8 phy, u8 indx, u16 regd)
 {
 	int i;
-	__u8 data[4] = { phy, 0, 0, indx };
+	u8 data[4] = { phy, 0, 0, indx };
 
 	*(data + 1) = cpu_to_le16p(&regd);
 	set_register(pegasus, PhyCtrl, 0);
@@ -326,11 +333,18 @@
 	return 1;
 }
 
-static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata)
+static void mdio_write(struct net_device *dev, int phy_id, int loc, int val)
+{
+	pegasus_t *pegasus = (pegasus_t *) dev->priv;
+
+	write_mii_word(pegasus, phy_id, loc, val);
+}
+
+static int read_eprom_word(pegasus_t * pegasus, u8 index, u16 * retdata)
 {
 	int i;
-	__u8 tmp;
-	__u16 retdatai;
+	u8 tmp;
+	u16 retdatai;
 
 	set_register(pegasus, EpromCtrl, 0);
 	set_register(pegasus, EpromOffset, index);
@@ -354,7 +368,7 @@
 #ifdef	PEGASUS_WRITE_EEPROM
 static inline void enable_eprom_write(pegasus_t * pegasus)
 {
-	__u8 tmp;
+	u8 tmp;
 
 	get_registers(pegasus, EthCtrl2, 1, &tmp);
 	set_register(pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE);
@@ -362,17 +376,17 @@
 
 static inline void disable_eprom_write(pegasus_t * pegasus)
 {
-	__u8 tmp;
+	u8 tmp;
 
 	get_registers(pegasus, EthCtrl2, 1, &tmp);
 	set_register(pegasus, EpromCtrl, 0);
 	set_register(pegasus, EthCtrl2, tmp & ~EPROM_WR_ENABLE);
 }
 
-static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data)
+static int write_eprom_word(pegasus_t * pegasus, u8 index, u16 data)
 {
 	int i, tmp;
-	__u8 d[4] = { 0x3f, 0, 0, EPROM_WRITE };
+	u8 d[4] = { 0x3f, 0, 0, EPROM_WRITE };
 
 	set_registers(pegasus, EpromOffset, 4, d);
 	enable_eprom_write(pegasus);
@@ -393,20 +407,20 @@
 }
 #endif				/* PEGASUS_WRITE_EEPROM */
 
-static inline void get_node_id(pegasus_t * pegasus, __u8 * id)
+static inline void get_node_id(pegasus_t * pegasus, u8 * id)
 {
 	int i;
-	__u16 w16;
+	u16 w16;
 
 	for (i = 0; i < 3; i++) {
 		read_eprom_word(pegasus, i, &w16);
-		((__u16 *) id)[i] = cpu_to_le16p(&w16);
+		((u16 *) id)[i] = cpu_to_le16p(&w16);
 	}
 }
 
 static void set_ethernet_addr(pegasus_t * pegasus)
 {
-	__u8 node_id[6];
+	u8 node_id[6];
 
 	get_node_id(pegasus, node_id);
 	set_registers(pegasus, EthID, sizeof(node_id), node_id);
@@ -415,7 +429,7 @@
 
 static inline int reset_mac(pegasus_t * pegasus)
 {
-	__u8 data = 0x8;
+	u8 data = 0x8;
 	int i;
 
 	set_register(pegasus, EthCtrl1, data);
@@ -438,13 +452,13 @@
 
 	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
 	    usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
-		__u16 auxmode;
+		u16 auxmode;
 
 		read_mii_word(pegasus, 1, 0x1b, &auxmode);
 		write_mii_word(pegasus, 1, 0x1b, auxmode | 4);
 	}
 	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) {
-		__u16 auxmode;
+		u16 auxmode;
 		read_mii_word(pegasus, 3, 0x1b, &auxmode);
 		write_mii_word(pegasus, 3, 0x1b, auxmode | 4);
 	}
@@ -453,8 +467,8 @@
 
 static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)
 {
-	__u16 linkpart, bmsr;
-	__u8 data[4];
+	u16 linkpart, bmsr;
+	u8 data[4];
 	pegasus_t *pegasus = dev->priv;
 
 	/* read twice 'cos this is a latch bit */
@@ -487,7 +501,7 @@
 	int count = urb->actual_length, res;
 	int rx_status;
 	struct sk_buff *skb;
-	__u16 pkt_len;
+	u16 pkt_len;
 
 	if (!pegasus || !(pegasus->flags & PEGASUS_RUNNING))
 		return;
@@ -531,7 +545,12 @@
 		goto goon;
 	}
 
-	pkt_len = (rx_status & 0xfff) - 8;
+	if (pegasus->chip == 0x8513) {
+		pkt_len = le32_to_cpu(*(int *)pegasus->rx_buff);
+		pkt_len &= 0x0fff;
+	} else {
+		pkt_len = (rx_status & 0x0fff) - 8;
+	}
 
 	if (!(skb = dev_alloc_skb(pkt_len + 2)))
 		goto goon;
@@ -541,6 +560,10 @@
 	eth_copy_and_sum(skb, pegasus->rx_buff, pkt_len, 0);
 	skb_put(skb, pkt_len);
 
+	if (pegasus->chip == 0x8513) {
+		skb->data += 2;
+	}
+
 	skb->protocol = eth_type_trans(skb, net);
 	netif_rx(skb);
 	pegasus->stats.rx_packets++;
@@ -578,7 +601,7 @@
 {
 	pegasus_t *pegasus = urb->context;
 	struct net_device *net;
-	__u8 *d;
+	u8 *d;
 
 	if (!pegasus)
 		return;
@@ -626,11 +649,11 @@
 	pegasus_t *pegasus = net->priv;
 	int count = ((skb->len + 2) & 0x3f) ? skb->len + 2 : skb->len + 3;
 	int res;
-	__u16 l16 = skb->len;
+	u16 l16 = skb->len;
 
 	netif_stop_queue(net);
 
-	((__u16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16);
+	((u16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16);
 	memcpy(pegasus->tx_buff + 2, skb->data, skb->len);
 	FILL_BULK_URB(pegasus->tx_urb, pegasus->usb,
 		      usb_sndbulkpipe(pegasus->usb, 2),
@@ -666,15 +689,15 @@
 
 static inline void get_interrupt_interval(pegasus_t * pegasus)
 {
-	__u8 data[2];
+	u8 data[2];
 
-	read_eprom_word(pegasus, 4, (__u16 *) data);
+	read_eprom_word(pegasus, 4, (u16 *) data);
 	if (data[1] < 0x80) {
 		info("intr interval will be changed from %ums to %ums",
 		     data[1], 0x80);
 		data[1] = 0x80;
 #ifdef	PEGASUS_WRITE_EEPROM
-		write_eprom_word(pegasus, 4, *(__u16 *) data);
+		write_eprom_word(pegasus, 4, *(u16 *) data);
 #endif
 	}
 	pegasus->intr_interval = data[1];
@@ -750,7 +773,82 @@
 
 	return 0;
 }
+#if CONFIG_MII
+static int pegasus_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+
+	u32 ethcmd;
+	pegasus_t *pegasus = dev->priv;
 
+	if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
+		return -EFAULT;
+
+	switch (ethcmd) {
+	/* get driver-specific version/etc. info */
+	case ETHTOOL_GDRVINFO:{
+			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+			strncpy(info.driver, driver_name,
+				sizeof (info.driver) - 1);
+			strncpy(info.version, DRIVER_VERSION,
+				sizeof (info.version) - 1);
+			if (copy_to_user(useraddr, &info, sizeof (info)))
+				return -EFAULT;
+			return 0;
+		}
+
+	/* get settings */
+	case ETHTOOL_GSET:{
+			struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+			mii_ethtool_gset(&pegasus->mii, &ecmd);
+			if (copy_to_user(useraddr, &ecmd, sizeof (ecmd)))
+				return -EFAULT;
+			return 0;
+		}
+	/* set settings */
+	case ETHTOOL_SSET:{
+			int r;
+			struct ethtool_cmd ecmd;
+			if (copy_from_user(&ecmd, useraddr, sizeof (ecmd)))
+				return -EFAULT;
+			r = mii_ethtool_sset(&pegasus->mii, &ecmd);
+			return r;
+		}
+	/* restart autonegotiation */
+	case ETHTOOL_NWAY_RST:{
+			return mii_nway_restart(&pegasus->mii);
+		}
+
+	/* get link status */
+	case ETHTOOL_GLINK:{
+			struct ethtool_value edata = { ETHTOOL_GLINK };
+			edata.data = mii_link_ok(&pegasus->mii);
+			if (copy_to_user(useraddr, &edata, sizeof (edata)))
+				return -EFAULT;
+			return 0;
+		}
+	/* get message-level */
+	case ETHTOOL_GMSGLVL:{
+			struct ethtool_value edata = { ETHTOOL_GMSGLVL };
+			/* edata.data = pegasus->msg_enable; FIXME */
+			if (copy_to_user(useraddr, &edata, sizeof (edata)))
+				return -EFAULT;
+			return 0;
+		}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL:{
+			struct ethtool_value edata;
+			if (copy_from_user(&edata, useraddr, sizeof (edata)))
+				return -EFAULT;
+			/* sp->msg_enable = edata.data; FIXME */
+			return 0;
+		}
+
+	}
+
+	return -EOPNOTSUPP;
+
+}
+#else
 static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr)
 {
 	pegasus_t *pegasus;
@@ -826,10 +924,10 @@
 		return -EOPNOTSUPP;
 	}
 }
-
+#endif
 static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
 {
-	__u16 *data = (__u16 *) & rq->ifr_data;
+	u16 *data = (u16 *) & rq->ifr_data;
 	pegasus_t *pegasus = net->priv;
 	int res;
 
@@ -885,10 +983,10 @@
 	netif_wake_queue(net);
 }
 
-static __u8 mii_phy_probe(pegasus_t * pegasus)
+static u8 mii_phy_probe(pegasus_t * pegasus)
 {
 	int i;
-	__u16 tmp;
+	u16 tmp;
 
 	for (i = 0; i < 32; i++) {
 		read_mii_word(pegasus, i, MII_BMSR, &tmp);
@@ -903,9 +1001,27 @@
 
 static inline void setup_pegasus_II(pegasus_t * pegasus)
 {
+	u16 data = 0xa5;
+	
 	set_register(pegasus, Reg1d, 0);
+	set_register(pegasus, Reg7b, 1);
+	mdelay(100);
 	set_register(pegasus, Reg7b, 2);
-	if (pegasus->features & HAS_HOME_PNA && mii_mode)
+	
+	set_register(pegasus, 0x83, data);
+	get_registers(pegasus, 0x83, 1, &data);
+	
+	if (data & 0xa5) {
+		pegasus->chip = 0x8513;
+	} else {
+		pegasus->chip = 0;
+	}
+	
+	set_register( pegasus, 0x80, 0xc0 );
+	set_register( pegasus, 0x83, 0xff );
+	set_register( pegasus, 0x84, 0x01 );
+	
+	if ((pegasus->features & HAS_HOME_PNA) && mii_mode)
 		set_register(pegasus, Reg81, 6);
 	else
 		set_register(pegasus, Reg81, 2);
@@ -984,6 +1100,11 @@
 	net->set_multicast_list = pegasus_set_multicast;
 	net->get_stats = pegasus_netdev_stats;
 	net->mtu = PEGASUS_MTU;
+	pegasus->mii.dev = net;
+	pegasus->mii.mdio_read = mdio_read;
+	pegasus->mii.mdio_write = mdio_write;
+	pegasus->mii.phy_id_mask = 0x1f;
+	pegasus->mii.reg_num_mask = 0x1f;
 
 	pegasus->features = usb_dev_id[dev_index].private;
 #ifdef	PEGASUS_USE_INTR
@@ -1015,9 +1136,9 @@
 		warn("can't locate MII phy, using default");
 		pegasus->phy = 1;
 	}
-
 exit:
 	up(&pegasus->sem);
+	
 	return pegasus;
 }
 
@@ -1047,7 +1168,7 @@
 }
 
 static struct usb_driver pegasus_driver = {
-	name:		"pegasus",
+	name:		driver_name,
 	probe:		pegasus_probe,
 	disconnect:	pegasus_disconnect,
 	id_table:	pegasus_ids,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/pegasus.h linux-2.4.21/drivers/usb/pegasus.h
--- linux-2.4.20/drivers/usb/pegasus.h	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/pegasus.h	2002-12-18 18:58:12.000000000 +0000
@@ -85,6 +85,7 @@
 	struct usb_device	*usb;
 	struct net_device	*net;
 	struct net_device_stats	stats;
+	struct mii_if_info	mii;
 	unsigned		flags;
 	unsigned		features;
 	int			dev_index;
@@ -93,6 +94,7 @@
 	struct usb_ctrlrequest	dr;
 	wait_queue_head_t	ctrl_wait;
 	struct semaphore	sem;
+	int			chip;
 	unsigned char		rx_buff[PEGASUS_MAX_MTU];
 	unsigned char		tx_buff[PEGASUS_MAX_MTU];
 	unsigned char		intr_buff[8];
@@ -128,6 +130,7 @@
 #define	VENDOR_LANEED		0x056e
 #define	VENDOR_LINKSYS		0x066b
 #define	VENDOR_MELCO		0x0411
+#define VENDOR_NETGEAR		0x0846
 #define	VENDOR_SMARTBRIDGES	0x08d1
 #define	VENDOR_SMC		0x0707
 #define	VENDOR_SOHOWARE		0x15e8
@@ -164,7 +167,10 @@
 PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
 		VENDOR_ADMTEK, 0x8511,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (eval. board)",
+PEGASUS_DEV( "ADMtek ADM8513 \"Pegasus II\" USB Ethernet",
+		VENDOR_ADMTEK, 0x8513,
+		DEFAULT_GPIO_RESET | PEGASUS_II )	
+PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (evaluation board)",
 		VENDOR_ADMTEK, 0x0986,
 		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
 PEGASUS_DEV( "ADMtek AN986A USB MAC", VENDOR_ADMTEK, 0x1986,
@@ -187,7 +193,7 @@
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004,
 		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Corega FEter", VENDOR_COREGA, 0x000d,
+PEGASUS_DEV( "Corega FEter USB-TXS", VENDOR_COREGA, 0x000d,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
 		LINKSYS_GPIO_RESET )
@@ -241,6 +247,8 @@
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "NETGEAR FA101", VENDOR_MELCO, 0x1020,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/powermate.c linux-2.4.21/drivers/usb/powermate.c
--- linux-2.4.20/drivers/usb/powermate.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/usb/powermate.c	2002-12-18 18:58:08.000000000 +0000
@@ -0,0 +1,363 @@
+/*
+ * A driver for the Griffin Technology, Inc. "PowerMate" USB controller dial.
+ *
+ * v1.0, (c)2002 William R Sowerbutts <will@sowerbutts.com>
+ *
+ * This device is a stainless steel knob which connects over USB. It can measure
+ * clockwise and anticlockwise rotation. The dial also acts as a pushbutton with
+ * a spring for automatic release. The base contains a pair of LEDs which illuminate
+ * the translucent base. It rotates without limit and reports its relative rotation
+ * back to the host when polled by the USB controller.
+ *
+ * Testing with the knob I have has shown that it measures approximately 96 "clicks"
+ * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was 
+ * a variable speed cordless electric drill) has shown that the device can measure
+ * speeds of up to 7 clicks either clockwise or anticlockwise between pollings from
+ * the host. If it counts more than 7 clicks before it is polled, it will wrap back
+ * to zero and start counting again. This was at quite high speed, however, almost
+ * certainly faster than the human hand could turn it. Griffin say that it loses a
+ * pulse or two on a direction change; the granularity is so fine that I never
+ * noticed this in practice.
+ *
+ * The device's microcontroller can be programmed to set the LED to either a constant
+ * intensity, or to a rhythmic pulsing. Several patterns and speeds are available.
+ *
+ * Griffin were very happy to provide documentation and free hardware for development.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+
+#define POWERMATE_VENDOR       0x077d    /* Griffin Technology, Inc. */
+#define POWERMATE_PRODUCT_NEW  0x0410    /* Griffin PowerMate */
+#define POWERMATE_PRODUCT_OLD  0x04AA    /* Griffin soundKnob */
+
+/* these are the command codes we send to the device */
+#define SET_STATIC_BRIGHTNESS  0x01
+#define SET_PULSE_ASLEEP       0x02
+#define SET_PULSE_AWAKE        0x03
+#define SET_PULSE_MODE         0x04
+
+/* these refer to bits in the powermate_device's requires_update field. */
+#define UPDATE_STATIC_BRIGHTNESS (1<<0)
+#define UPDATE_PULSE_ASLEEP      (1<<1)
+#define UPDATE_PULSE_AWAKE       (1<<2)
+#define UPDATE_PULSE_MODE        (1<<3)
+
+#define POWERMATE_PAYLOAD_SIZE 3
+struct powermate_device {
+	signed char data[POWERMATE_PAYLOAD_SIZE];
+	struct urb irq, config;
+	struct usb_ctrlrequest configdr;
+	struct usb_device *udev;
+	struct input_dev input;
+	struct semaphore lock;
+	int static_brightness;
+	int pulse_speed;
+	int pulse_table;
+	int pulse_asleep;
+	int pulse_awake;
+	int requires_update; // physical settings which are out of sync
+	char phys[64];
+};
+
+static char pm_name_powermate[] = "Griffin PowerMate";
+static char pm_name_soundknob[] = "Griffin SoundKnob";
+
+static void powermate_config_complete(struct urb *urb); /* forward declararation of callback */
+
+/* Callback for data arriving from the PowerMate over the USB interrupt pipe */
+static void powermate_irq(struct urb *urb)
+{
+	struct powermate_device *pm = urb->context;
+
+	if(urb->status)
+		return;
+
+	/* handle updates to device state */
+	input_report_key(&pm->input, BTN_0, pm->data[0] & 0x01);
+	input_report_rel(&pm->input, REL_DIAL, pm->data[1]);
+}
+
+/* Decide if we need to issue a control message and do so. Must be called with pm->lock down */
+static void powermate_sync_state(struct powermate_device *pm)
+{
+	if(pm->requires_update == 0) 
+		return; /* no updates are required */
+	if(pm->config.status == -EINPROGRESS) 
+		return; /* an update is already in progress; it'll issue this update when it completes */
+
+	if(pm->requires_update & UPDATE_PULSE_ASLEEP){
+		pm->configdr.wValue = cpu_to_le16( SET_PULSE_ASLEEP );
+		pm->configdr.wIndex = cpu_to_le16( pm->pulse_asleep ? 1 : 0 );
+		pm->requires_update &= ~UPDATE_PULSE_ASLEEP;
+	}else if(pm->requires_update & UPDATE_PULSE_AWAKE){
+		pm->configdr.wValue = cpu_to_le16( SET_PULSE_AWAKE );
+		pm->configdr.wIndex = cpu_to_le16( pm->pulse_awake ? 1 : 0 );
+		pm->requires_update &= ~UPDATE_PULSE_AWAKE;
+	}else if(pm->requires_update & UPDATE_PULSE_MODE){
+		int op, arg;
+		/* the powermate takes an operation and an argument for its pulse algorithm.
+		   the operation can be:
+		   0: divide the speed
+		   1: pulse at normal speed
+		   2: multiply the speed
+		   the argument only has an effect for operations 0 and 2, and ranges between
+		   1 (least effect) to 255 (maximum effect).
+       
+		   thus, several states are equivalent and are coalesced into one state.
+
+		   we map this onto a range from 0 to 510, with:
+		   0 -- 254    -- use divide (0 = slowest)
+		   255         -- use normal speed
+		   256 -- 510  -- use multiple (510 = fastest).
+
+		   Only values of 'arg' quite close to 255 are particularly useful/spectacular.
+		*/    
+		if(pm->pulse_speed < 255){
+			op = 0;                   // divide
+			arg = 255 - pm->pulse_speed;
+		}else if(pm->pulse_speed > 255){
+			op = 2;                   // multiply
+			arg = pm->pulse_speed - 255;
+		}else{
+			op = 1;                   // normal speed
+			arg = 0;                  // can be any value
+		}
+		pm->configdr.wValue = cpu_to_le16( (pm->pulse_table << 8) | SET_PULSE_MODE );
+		pm->configdr.wIndex = cpu_to_le16( (arg << 8) | op );
+		pm->requires_update &= ~UPDATE_PULSE_MODE;
+	}else if(pm->requires_update & UPDATE_STATIC_BRIGHTNESS){
+		pm->configdr.wValue = cpu_to_le16( SET_STATIC_BRIGHTNESS );
+		pm->configdr.wIndex = cpu_to_le16( pm->static_brightness );
+		pm->requires_update &= ~UPDATE_STATIC_BRIGHTNESS;
+	}else{
+		printk(KERN_ERR "powermate: unknown update required");
+		pm->requires_update = 0; /* fudge the bug */
+		return;
+	}
+
+	pm->config.dev = pm->udev; /* is this necessary? */
+	pm->configdr.bRequestType = 0x41; /* vendor request */
+	pm->configdr.bRequest = 0x01;
+	pm->configdr.wLength = 0;
+
+        FILL_CONTROL_URB(&pm->config, pm->udev, usb_sndctrlpipe(pm->udev, 0), 
+			 (void*)&pm->configdr, 0, 0, powermate_config_complete, pm);	
+
+	if(usb_submit_urb(&pm->config))
+		printk(KERN_ERR "powermate: usb_submit_urb(config) failed");
+}
+
+/* Called when our asynchronous control message completes. We may need to issue another immediately */
+static void powermate_config_complete(struct urb *urb)
+{
+	struct powermate_device *pm = urb->context;
+
+	if(urb->status)
+		printk(KERN_ERR "powermate: config urb returned %d\n", urb->status);
+	
+	down(&pm->lock);
+	powermate_sync_state(pm);
+	up(&pm->lock);
+}
+
+/* Set the LED up as described and begin the sync with the hardware if required */
+static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed, 
+				int pulse_table, int pulse_asleep, int pulse_awake)
+{
+	if(pulse_speed < 0)
+		pulse_speed = 0;
+	if(pulse_table < 0)
+		pulse_table = 0;
+	if(pulse_speed > 510)
+		pulse_speed = 510;
+	if(pulse_table > 2)
+		pulse_table = 2;
+
+	pulse_asleep = !!pulse_asleep;
+	pulse_awake = !!pulse_awake;
+
+	down(&pm->lock);
+
+	/* mark state updates which are required */
+	/* we update the static brightness if we've changed pulse mode,
+	   because the hardware seems to stick at an arbitrary value rather
+	   than jumping back to the static brightness we requested */
+	if(static_brightness != pm->static_brightness){
+		pm->static_brightness = static_brightness;
+		pm->requires_update |= UPDATE_STATIC_BRIGHTNESS;		
+	}
+	if(pulse_asleep != pm->pulse_asleep){
+		pm->pulse_asleep = pulse_asleep;
+		pm->requires_update |= (UPDATE_PULSE_ASLEEP | UPDATE_STATIC_BRIGHTNESS);
+	}
+	if(pulse_awake != pm->pulse_awake){
+		pm->pulse_awake = pulse_awake;
+		pm->requires_update |= (UPDATE_PULSE_AWAKE | UPDATE_STATIC_BRIGHTNESS);
+	}
+	if(pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table){
+		pm->pulse_speed = pulse_speed;
+		pm->pulse_table = pulse_table;
+		pm->requires_update |= UPDATE_PULSE_MODE;
+	}
+
+	powermate_sync_state(pm);
+   
+	up(&pm->lock);
+}
+
+/* Callback from the Input layer when an event arrives from userspace to configure the LED */
+static int powermate_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int _value)
+{
+	unsigned int command = (unsigned int)_value;
+	struct powermate_device *pm = dev->private;
+
+	if(type == EV_MSC && code == MSC_PULSELED){
+		/*  
+		    bits  0- 7: 8 bits: LED brightness
+		    bits  8-16: 9 bits: pulsing speed modifier (0 ... 510); 0-254 = slower, 255 = standard, 256-510 = faster.
+		    bits 17-18: 2 bits: pulse table (0, 1, 2 valid)
+		    bit     19: 1 bit : pulse whilst asleep?
+		    bit     20: 1 bit : pulse constantly?
+		*/  
+		int static_brightness = command & 0xFF;   // bits 0-7
+		int pulse_speed = (command >> 8) & 0x1FF; // bits 8-16
+		int pulse_table = (command >> 17) & 0x3;  // bits 17-18
+		int pulse_asleep = (command >> 19) & 0x1; // bit 19
+		int pulse_awake  = (command >> 20) & 0x1; // bit 20
+  
+		powermate_pulse_led(pm, static_brightness, pulse_speed, pulse_table, pulse_asleep, pulse_awake);
+	}
+
+	return 0;
+}
+
+/* Called whenever a USB device matching one in our supported devices table is connected */
+static void *powermate_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
+{
+	struct usb_interface_descriptor *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct powermate_device *pm;
+	int pipe, maxp;
+
+	interface = udev->config[0].interface[ifnum].altsetting + 0;
+	endpoint = interface->endpoint + 0;
+	if (!(endpoint->bEndpointAddress & 0x80)) return NULL;
+	if ((endpoint->bmAttributes & 3) != 3) return NULL;
+
+	usb_set_protocol(udev, interface->bInterfaceNumber, 0);
+	usb_set_idle(udev, interface->bInterfaceNumber, 0, 0);
+
+	if (!(pm = kmalloc(sizeof(struct powermate_device), GFP_KERNEL)))
+		return NULL;
+
+	memset(pm, 0, sizeof(struct powermate_device));
+	pm->udev = udev;
+
+	init_MUTEX(&pm->lock);
+
+	/* get a handle to the interrupt data pipe */
+	pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
+	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+
+	if(maxp != POWERMATE_PAYLOAD_SIZE)
+		printk("powermate: Expected payload of %d bytes, found %d bytes!\n", POWERMATE_PAYLOAD_SIZE, maxp);
+
+	FILL_INT_URB(&pm->irq, udev, pipe, pm->data, POWERMATE_PAYLOAD_SIZE, powermate_irq, pm, endpoint->bInterval);
+
+	/* register our interrupt URB with the USB system */
+	if(usb_submit_urb(&pm->irq)) {
+		kfree(pm);
+		return NULL; /* failure */
+	}
+
+	switch (udev->descriptor.idProduct) {
+	case POWERMATE_PRODUCT_NEW: pm->input.name = pm_name_powermate; break;
+	case POWERMATE_PRODUCT_OLD: pm->input.name = pm_name_soundknob; break;
+	default: 
+	  pm->input.name = pm_name_soundknob;
+	  printk(KERN_WARNING "powermate: unknown product id %04x\n", udev->descriptor.idProduct);
+	}
+
+	pm->input.private = pm;
+	pm->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_MSC);
+	pm->input.keybit[LONG(BTN_0)] = BIT(BTN_0);
+	pm->input.relbit[LONG(REL_DIAL)] = BIT(REL_DIAL);
+	pm->input.mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED);
+	pm->input.idbus = BUS_USB;
+	pm->input.idvendor = udev->descriptor.idVendor;
+	pm->input.idproduct = udev->descriptor.idProduct;
+	pm->input.idversion = udev->descriptor.bcdDevice;
+	pm->input.event = powermate_input_event;
+
+	input_register_device(&pm->input);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) /* Vojtech -- is this the correct version? */
+	{
+		char path[64];
+		usb_make_path(udev, path, 64);
+		snprintf(pm->phys, 64, "%s/input0", path);
+		printk(KERN_INFO "input: %s on %s\n", pm->input.name, pm->input.path);
+	}
+#else
+	printk(KERN_INFO "input: %s on input%d\n", pm->input.name, pm->input.number);
+#endif
+	
+	/* force an update of everything */
+	pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS;
+	powermate_pulse_led(pm, 0x80, 255, 0, 1, 0); // set default pulse parameters
+  
+	return pm;
+}
+
+/* Called when a USB device we've accepted ownership of is removed */
+static void powermate_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct powermate_device *pm = ptr;
+	down(&pm->lock);
+	pm->requires_update = 0;
+	usb_unlink_urb(&pm->irq);  
+	input_unregister_device(&pm->input);
+  
+	kfree(pm);
+}
+
+static struct usb_device_id powermate_devices [] = {
+	{ USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_NEW) },
+	{ USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_OLD) },
+	{ } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, powermate_devices);
+
+static struct usb_driver powermate_driver = {
+        name:           "powermate",
+        probe:          powermate_probe,
+        disconnect:     powermate_disconnect,
+        id_table:       powermate_devices,
+};
+
+int powermate_init(void)
+{
+	if (usb_register(&powermate_driver) < 0)
+		return -1;
+	return 0;
+}
+
+void powermate_cleanup(void)
+{
+	usb_deregister(&powermate_driver);
+}
+
+module_init(powermate_init);
+module_exit(powermate_cleanup);
+
+MODULE_AUTHOR( "William R Sowerbutts" );
+MODULE_DESCRIPTION( "Griffin Technology, Inc PowerMate driver" );
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/pwc-ctrl.c linux-2.4.21/drivers/usb/pwc-ctrl.c
--- linux-2.4.20/drivers/usb/pwc-ctrl.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/drivers/usb/pwc-ctrl.c	2002-12-18 18:58:11.000000000 +0000
@@ -256,8 +256,10 @@
 
 	memcpy(buf, pEntry->mode, 3);	
 	ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3);
-	if (ret < 0)
+	if (ret < 0) {
+		Debug("Failed to send video command... %d\n", ret);
 		return ret;
+	}
 	if (pEntry->compressed && pdev->decompressor != NULL)
 		pdev->decompressor->init(pdev->release, buf, pdev->decompress_data);
 		
@@ -444,8 +446,8 @@
 			Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames);
 		else {
 			Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
-			return ret;
 		}
+		return ret;
 	}
 	pdev->view.x = width;
 	pdev->view.y = height;
@@ -997,7 +999,7 @@
 		&buf, 1, HZ / 2);
 
 	if (ret < 0)
-	    return ret;
+		return ret;
 	
 	return (buf << 8);
 }
@@ -1103,12 +1105,7 @@
 	buf[0] = on_value;
 	buf[1] = off_value;
 
-	return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
-		SET_STATUS_CTL,
-		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		LED_FORMATTER,
-		pdev->vcinterface,
-		&buf, 2, HZ / 2);
+	return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2);
 }
 
 int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
@@ -1122,13 +1119,7 @@
 		return 0;
 	}
 
-	ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
-   	        GET_STATUS_CTL,
-		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		LED_FORMATTER,
-		pdev->vcinterface,
-		&buf, 2, HZ / 2);
-
+	ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2);
 	if (ret < 0)
 		return ret;
 	*on_value = buf[0] * 100;
@@ -1252,7 +1243,7 @@
 	int ret;
 	unsigned char buf;
 	
-	ret = RecvControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
+	ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
 	if (ret < 0)
 		return ret;
 	return buf;
@@ -1276,10 +1267,9 @@
 	int ret;
 	unsigned char buf;
 	
-	ret = RecvControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
+	ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
 	if (ret < 0)
 		return ret;
-Debug("pwc_get_dynamic_noise = %d\n", buf);
 	return buf;
 }
 
@@ -1595,6 +1585,16 @@
 		break;
 	}
 	
+	case VIDIOCPWCGREALSIZE:
+	{
+		struct pwc_imagesize size;
+		
+		size.width = pdev->image.x;
+		size.height = pdev->image.y;
+		if (copy_to_user(arg, &size, sizeof(size)))
+			ret = -EFAULT;
+		break;
+	}	
 
 	default:
 		ret = -ENOIOCTLCMD;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/pwc-if.c linux-2.4.21/drivers/usb/pwc-if.c
--- linux-2.4.20/drivers/usb/pwc-if.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/pwc-if.c	2002-12-18 18:58:11.000000000 +0000
@@ -42,11 +42,15 @@
    - Alistar Moire: QuickCam 3000 Pro device/product ID
    - Tony Hoyle: Creative Labs Webcam 5 device/product ID
    - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged
-   - Jk Fang: SOTEC device/product ID
+   - Jk Fang: Sotec Afina Eye ID
+   - Xavier Roche: QuickCam Pro 4000 ID
+   - Jens Knudsen: QuickCam Zoom ID
+   - J. Debert: QuickCam for Notebooks ID
 */
 
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/poll.h>
 #include <linux/slab.h>
@@ -58,10 +62,6 @@
 #include "pwc-ioctl.h"
 #include "pwc-uncompress.h"
 
-#if !defined(MAP_NR)
-#define MAP_NR(a) virt_to_page(a)
-#endif
-
 /* Function prototypes and driver templates */
 
 /* hotplug device table support */
@@ -76,10 +76,13 @@
 	{ USB_DEVICE(0x0471, 0x0311) },
 	{ USB_DEVICE(0x0471, 0x0312) },
 	{ USB_DEVICE(0x069A, 0x0001) }, /* Askey */
-	{ USB_DEVICE(0x046D, 0x08b0) }, /* Logitech */
+	{ USB_DEVICE(0x046D, 0x08b0) }, /* Logitech QuickCam Pro 3000 */
+	{ USB_DEVICE(0x046D, 0x08b1) }, /* Logitech QuickCam Notebook Pro */
+	{ USB_DEVICE(0x046d, 0x08b2) }, /* Logitech QuickCam Pro 4000 */
+	{ USB_DEVICE(0x046d, 0x08b3) }, /* Logitech QuickCam Zoom */
 	{ USB_DEVICE(0x055D, 0x9000) }, /* Samsung */
 	{ USB_DEVICE(0x055D, 0x9001) },
-	{ USB_DEVICE(0x041E, 0x400C) }, /* Creative */
+	{ USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
 	{ USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
 	{ USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */
 	{ USB_DEVICE(0x0d81, 0x1900) },
@@ -127,7 +130,7 @@
 static long pwc_video_write(struct video_device *vdev, const char *buf, unsigned long count, int noblock);
 static unsigned int pwc_video_poll(struct video_device *vdev, struct file *file, poll_table *wait);
 static int  pwc_video_ioctl(struct video_device *vdev, unsigned int cmd, void *arg);
-static int  pwc_video_mmap(struct video_device *dev, const char *adr, unsigned long size);
+static int  pwc_video_mmap(struct video_device *vdev, const char *adr, unsigned long size);
 
 static struct video_device pwc_template = {
 	owner:		THIS_MODULE,
@@ -238,7 +241,7 @@
 	int i;
 	void *kbuf;
 
-	Trace(TRACE_MEMORY, "Entering allocate_buffers(%p).\n", pdev);
+	Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
 
 	if (pdev == NULL)
 		return -ENXIO;
@@ -315,7 +318,7 @@
 
 	kbuf = NULL;
 	  
-	Trace(TRACE_MEMORY, "Leaving pwc_allocate_buffers().\n");
+	Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n");
 	return 0;
 }
 
@@ -612,7 +615,7 @@
 	}
 #endif
 	if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
-		Trace(TRACE_OPEN, "pwc_isoc_handler(): URB unlinked.\n");
+		Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
 		return;
 	}
 	if (urb->status != -EINPROGRESS && urb->status != 0) {
@@ -685,9 +688,22 @@
 #if PWC_DEBUG
 							Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence);
 #endif
-							pdev->drop_frames = 2;
+							pdev->drop_frames += 2;
 							pdev->vframes_error++;
 						}
+						if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+							if (ptr[0] & 0x01)
+								Info("Snapshot button pressed.\n");
+							else
+								Info("Snapshot button released.\n");
+						}
+						if ((ptr[0] ^ pdev->vmirror) & 0x02) {
+							if (ptr[0] & 0x02)
+								Info("Image is mirrored.\n");
+							else
+								Info("Image is normal.\n");
+						}
+						pdev->vmirror = ptr[0] & 0x03;
 						/* Sometimes the trailer of the 730 is still sent as a 4 byte packet 
 						   after a short frame; this condition is filtered out specifically. A 4 byte
 						   frame doesn't make sense anyway.
@@ -704,7 +720,7 @@
 					/* In case we were instructed to drop the frame, do so silently.
 					   The buffer pointers are not updated either (but the counters are reset below).
 					 */
-					if (pdev->drop_frames)
+					if (pdev->drop_frames > 0)
 						pdev->drop_frames--;
 					else {
 						/* Check for underflow first */
@@ -740,10 +756,14 @@
 			} /* .. flen < last_packet_size */
 			pdev->vlast_packet_size = flen;
 		} /* ..status == 0 */
-#ifdef PWC_DEBUG
+#if PWC_DEBUG
 		/* This is normally not interesting to the user, unless you are really debugging something */
-		else 
-			Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
+		else {
+			static int iso_error = 0;
+			iso_error++;
+			if (iso_error < 20)
+				Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
+		}
 #endif			
 	}
 	if (awake)
@@ -758,7 +778,6 @@
 	int i, j, ret;
 
 	struct usb_interface_descriptor *idesc;
-	int cur_alt;
 
 	if (pdev == NULL)
 		return -EFAULT;
@@ -766,12 +785,11 @@
 		return 0;
 	pdev->vsync = 0;
 	udev = pdev->udev;
-	
+
 	/* Get the current alternate interface, adjust packet size */
 	if (!udev->actconfig)
 		return -EFAULT;
-	cur_alt = udev->actconfig->interface[0].act_altsetting;
-	idesc = &udev->actconfig->interface[0].altsetting[cur_alt];
+	idesc = &udev->actconfig->interface[0].altsetting[pdev->valternate];
 	if (!idesc)
 		return -EFAULT;
 
@@ -783,12 +801,18 @@
 			break;
 		}
 	
-	if (pdev->vmax_packet_size < 0) {
+	if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
 		Err("Failed to find packet size for video endpoint in current alternate setting.\n");
 		return -ENFILE; /* Odd error, that should be noticable */
 	}
 
+	/* Set alternate interface */
 	ret = 0;
+	Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate);
+	ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
+	if (ret < 0)
+		return ret;
+
 	for (i = 0; i < MAX_ISO_BUFS; i++) {
 		urb = usb_alloc_urb(ISO_FRAMES_PER_DESC);
 		if (urb == NULL) {
@@ -797,6 +821,7 @@
 			break;
 		}
 		pdev->sbuf[i].urb = urb;
+		Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb);
 	}
 	if (ret) {
 		/* De-allocate in reverse order */
@@ -808,8 +833,7 @@
 		}
 		return ret;
 	}
-	
-	
+
 	/* init URB structure */	
 	for (i = 0; i < MAX_ISO_BUFS; i++) {
 		urb = pdev->sbuf[i].urb;
@@ -826,7 +850,7 @@
 		urb->number_of_packets = ISO_FRAMES_PER_DESC;
 		for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
 			urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
-			urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE;
+			urb->iso_frame_desc[j].length = pdev->vmax_packet_size;
 		}
 	}
 
@@ -836,11 +860,12 @@
 		if (ret)
 			Err("isoc_init() submit_urb %d failed with error %d\n", i, ret);
 		else
-			Trace(TRACE_OPEN, "pwc_isoc_init(): URB submitted.\n");
+			Trace(TRACE_OPEN, "URB 0x%p submitted.\n", pdev->sbuf[i].urb);
 	}
 
-	/* data should stream in now */
+	/* All is done... */
 	pdev->iso_init = 1;
+	Trace(TRACE_OPEN, "<< pwc_isoc_init()\n");
 	return 0;
 }
 
@@ -848,21 +873,34 @@
 {
 	int i;
 	
+	Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n");
 	if (pdev == NULL)
 		return;
-	if (!pdev->iso_init)
-		return;
+
+	/* Unlinking ISOC buffers one by one */
+	for (i = 0; i < MAX_ISO_BUFS; i++) {
+		struct urb *urb;
+
+		urb = pdev->sbuf[i].urb;
+		if (urb != 0) {
+			if (pdev->iso_init) {
+				Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb);
+				usb_unlink_urb(urb);
+			}
+			Trace(TRACE_MEMORY, "Freeing URB\n");
+			usb_free_urb(urb);
+			pdev->sbuf[i].urb = NULL;
+		}
+	}
+
 	/* Stop camera, but only if we are sure the camera is still there */
-	if (!pdev->unplugged)
+	if (!pdev->unplugged) {
+		Trace(TRACE_OPEN, "Setting alternate interface 0.\n");
 		usb_set_interface(pdev->udev, 0, 0);
-	/* Unlinking ISOC buffers one by one */
-	for (i = MAX_ISO_BUFS - 1; i >= 0; i--) {
-		pdev->sbuf[i].urb->next = NULL;
-		usb_unlink_urb(pdev->sbuf[i].urb);
-		usb_free_urb(pdev->sbuf[i].urb);
-		pdev->sbuf[i].urb = NULL;
 	}
+
 	pdev->iso_init = 0;
+	Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n");
 }
 
 int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
@@ -876,11 +914,10 @@
 	ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);
 	if (ret) /* That failed... restore old mode (we know that worked) */
 		ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
-	else /* Set (new) alternate interface */
-		ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
 	if (!ret)
-		ret = pwc_isoc_init(pdev);
-	pdev->drop_frames = 1; /* try to avoid garbage during switch */
+		if (pwc_isoc_init(pdev) < 0)
+			Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
+	pdev->drop_frames++; /* try to avoid garbage during switch */
 	return ret;
 }
 
@@ -915,20 +952,19 @@
 	int i;
 	struct pwc_device *pdev;
 
-	Trace(TRACE_OPEN, "video_open called(0x%p, 0%o).\n", vdev, mode);
+	Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev);
 	
 	if (vdev == NULL)
 		BUG();
 	pdev = (struct pwc_device *)vdev->priv;
 	if (pdev == NULL)
 		BUG();
+	if (pdev->vopen)
+		return -EBUSY;
 	
 	down(&pdev->modlock);
 	if (!pdev->usb_init) {
 		Trace(TRACE_OPEN, "Doing first time initialization.\n");
-		/* Reset camera */
-		if (usb_set_interface(pdev->udev, 0, 0))
-			Info("Failed to set alternate interface to 0.\n");
 		pdev->usb_init = 1;
 		
 		if (pwc_trace & TRACE_OPEN) {
@@ -948,10 +984,10 @@
 			case 0x40:  sensor_type = "UPA 1021 sensor"; break;
 			case 0x100: sensor_type = "VGA sensor"; break;
 			case 0x101: sensor_type = "PAL MR sensor"; break;
-			default:   sensor_type = "unknown type of sensor"; break;
+			default:    sensor_type = "unknown type of sensor"; break;
 			}
 			if (sensor_type != NULL)
-				Info("Thes %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);
+				Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);
 		}
 	}
 
@@ -1017,16 +1053,9 @@
 		return i;
 	}
 	
-	i = usb_set_interface(pdev->udev, 0, pdev->valternate);
-	if (i) {
-		Trace(TRACE_OPEN, "Failed to set alternate interface = %d.\n", i);
-		up(&pdev->modlock);
-		return -EINVAL;
-	}
 	i = pwc_isoc_init(pdev);
 	if (i) {
 		Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i);
-		MOD_DEC_USE_COUNT;
 		up(&pdev->modlock);
 		return i;
 	}
@@ -1039,7 +1068,7 @@
 	if (pdev->decompressor != NULL)
 		pdev->decompressor->lock();
 	up(&pdev->modlock);
-	Trace(TRACE_OPEN, "video_open() returning 0.\n");
+	Trace(TRACE_OPEN, "<< video_open() returns 0.\n");
 	return 0;
 }
 
@@ -1049,15 +1078,12 @@
 	struct pwc_device *pdev;
 	int i;
 
-	Trace(TRACE_OPEN, "video_close called(0x%p).\n", vdev);
+	Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev);
 
 	pdev = (struct pwc_device *)vdev->priv;
 	if (pdev->vopen == 0)
 		Info("video_close() called on closed device?\n");
 
-	/* Free isoc URBs */
-	pwc_isoc_cleanup(pdev);
-
 	/* Dump statistics, but only if a reasonable amount of frames were
 	   processed (to prevent endless log-entries in case of snap-shot
 	   programs) 
@@ -1065,21 +1091,14 @@
 	if (pdev->vframe_count > 20)
 		Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
 
-	if (pdev->unplugged) {
-		/* The device was unplugged or some other error occured */
-		/* We unregister the video_device */
-		Trace(TRACE_OPEN, "Delayed video device unregistered.\n");
-		video_unregister_device(pdev->vdev);
-	}
-	else {
-		/* Normal close: stop isochronuous and interrupt endpoint */
-		Trace(TRACE_OPEN, "Normal close(): setting interface to 0.\n");
-		usb_set_interface(pdev->udev, 0, 0);
+	/* Free isoc URBs, stop camera */
+	pwc_isoc_cleanup(pdev);
 
+	if (!pdev->unplugged) {
 		/* Turn LEDs off */
 		if (pwc_set_leds(pdev, 0, 0) < 0)
-			Info("Failed to set LED on/off time..\n");
-		/* Power down camere to save energy */
+			Info("Failed to set LED on/off time.\n");
+		/* Power down camera to save energy */
 		if (power_save) {
 			i = pwc_camera_power(pdev, 0);
 			if (i < 0) 
@@ -1097,6 +1116,7 @@
 	/* wake up _disconnect() routine */
 	if (pdev->unplugged)
 		wake_up(&pdev->remove_ok);
+	Trace(TRACE_OPEN, "<< video_close()\n");
 }
 
 /*
@@ -1131,6 +1151,7 @@
 	if (pdev->image_read_pos == 0) {
 		/* Do wait queueing according to the (doc)book */
 		add_wait_queue(&pdev->frameq, &wait);
+	        set_current_state(TASK_INTERRUPTIBLE);
 		while (pdev->full_frames == NULL) {
 	                if (noblock) {
 	                	remove_wait_queue(&pdev->frameq, &wait);
@@ -1483,6 +1504,7 @@
 			            frameq is safe now.
 			 */
 			add_wait_queue(&pdev->frameq, &wait);
+		        set_current_state(TASK_INTERRUPTIBLE);
 			while (pdev->full_frames == NULL) {
 				if (pdev->unplugged) {
 					remove_wait_queue(&pdev->frameq, &wait);
@@ -1495,8 +1517,8 @@
 		                	set_current_state(TASK_RUNNING);
 		                	return -ERESTARTSYS;
 	        	        }
-	                	schedule();
 		                set_current_state(TASK_INTERRUPTIBLE);
+	                	schedule();
 			}
 			remove_wait_queue(&pdev->frameq, &wait);
 			set_current_state(TASK_RUNNING);
@@ -1574,8 +1596,6 @@
 	Trace(TRACE_MEMORY, "mmap(0x%p, 0x%p, %lu) called.\n", vdev, adr, size);
 	pdev = vdev->priv;
 
-	/* FIXME - audit mmap during a read */		
-	/* Nemo: 9 months and 20 kernel revisions later I still don't know what you mean by this :-) */
 	pos = (unsigned long)pdev->image_data;
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
@@ -1691,10 +1711,25 @@
 	else if (vendor_id == 0x046d) {
 		switch(product_id) {
 		case 0x08b0:
-			Info("Logitech QuickCam 3000 Pro USB webcam detected.\n");
-			name = "Logitech QuickCam 3000 Pro";
+			Info("Logitech QuickCam Pro 3000 USB webcam detected.\n");
+			name = "Logitech QuickCam Pro 3000";
 			type_id = 730;
-        		break;
+			break;
+		case 0x08b1:
+			Info("Logitech QuickCam for Notebook Pro USB webcam detected.\n");
+			name = "Logitech QuickCam Notebook Pro";
+			type_id = 740; /* ?? unknown sensor */
+			break;
+		case 0x08b2:
+			Info("Logitech QuickCam 4000 Pro USB webcam detected.\n");
+			name = "Logitech QuickCam Pro 4000";
+			type_id = 740; /* CCD sensor */
+			break;
+		case 0x08b3:
+			Info("Logitech QuickCam Zoom USB webcam detected.\n");
+			name = "Logitech QuickCam Zoom";
+			type_id = 740; /* CCD sensor */
+			break;
         	default:
         		return NULL;
         		break;
@@ -1868,6 +1903,10 @@
 	
 	pdev->unplugged = 1;
 	if (pdev->vdev != NULL) {
+		add_wait_queue(&pdev->remove_ok, &wait);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		Trace(TRACE_PROBE, "Unregistering video device.\n");
+		video_unregister_device(pdev->vdev); 
 		if (pdev->vopen) {
 			Info("Disconnected while device/video is open!\n");
 			
@@ -1883,23 +1922,19 @@
 			 */
 			   
 			Trace(TRACE_PROBE, "Sleeping on remove_ok.\n");
-			add_wait_queue(&pdev->remove_ok, &wait);
-			set_current_state(TASK_UNINTERRUPTIBLE);
 			/* ... wait ... */
 			schedule();
-			remove_wait_queue(&pdev->remove_ok, &wait);
-			set_current_state(TASK_RUNNING);
 			Trace(TRACE_PROBE, "Done sleeping.\n");
 			set_mem_leak(pdev->vdev);
 			pdev->vdev = NULL;
 		}
 		else {
 			/* Normal disconnect; remove from available devices */
-			Trace(TRACE_PROBE, "Unregistering video device normally.\n");
-			video_unregister_device(pdev->vdev); 
 			kfree(pdev->vdev);
 			pdev->vdev = NULL;
 		}
+		remove_wait_queue(&pdev->remove_ok, &wait);
+		set_current_state(TASK_RUNNING);
 	}
 
 	/* search device_hint[] table if we occupy a slot, by any chance */
@@ -1914,7 +1949,7 @@
 
 
 /* *grunt* We have to do atoi ourselves :-( */
-static int pwc_atoi(char *s)
+static int pwc_atoi(const char *s)
 {
 	int k = 0;
 	
@@ -1959,7 +1994,7 @@
 MODULE_PARM(dev_hint, "0-10s");
 MODULE_PARM_DESC(dev_hint, "Device node hints");
 
-MODULE_DESCRIPTION("Philips USB webcam driver");
+MODULE_DESCRIPTION("Philips USB & OEM webcam driver");
 MODULE_AUTHOR("Nemosoft Unv. <nemosoft@smcc.demon.nl>");
 MODULE_LICENSE("GPL");
 
@@ -1969,7 +2004,7 @@
 	char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
 
 	Info("Philips PCA645/646 + PCVC675/680/690 + PCVC730/740/750 webcam module version " PWC_VERSION " loaded.\n");
-	Info("Also supports the Askey VC010, Logitech Quickcam 3000 Pro, Samsung MPC-C10 and MPC-C30,\n");
+	Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
 	Info("the Creative WebCam 5, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
 
 	if (fps) {
@@ -2087,7 +2122,7 @@
 					device_hint[i].serial_number[k] = '\0';
 				}
 			}
-#ifdef PWC_DEBUG		
+#if PWC_DEBUG		
 			Debug("device_hint[%d]:\n", i);
 			Debug("  type    : %d\n", device_hint[i].type);
 			Debug("  serial# : %s\n", device_hint[i].serial_number);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/pwc-ioctl.h linux-2.4.21/drivers/usb/pwc-ioctl.h
--- linux-2.4.20/drivers/usb/pwc-ioctl.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/drivers/usb/pwc-ioctl.h	2002-12-18 18:58:08.000000000 +0000
@@ -18,12 +18,13 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
-/*         This is pwc-ioctl.h belonging to PWC 8.6                        */
+/*         This is pwc-ioctl.h belonging to PWC 8.10                        */
 
 /* 
    Changes
    2001/08/03  Alvarado   Added ioctl constants to access methods for 
                           changing white balance and red/blue gains
+   2002/12/15  G. H. Fernandez-Toribio   VIDIOCGREALSIZE
  */
 
 /* These are private ioctl() commands, specific for the Philips webcams.
@@ -104,7 +105,12 @@
 	int led_off;			/* Led off-time; range = 0..25000  */
 };
 
-
+/* Image size (used with GREALSIZE) */
+struct pwc_imagesize
+{
+	int width;
+	int height;
+};
 
  /* Restore user settings */
 #define VIDIOCPWCRUSER		_IO('v', 192)
@@ -173,4 +179,7 @@
 #define VIDIOCPWCSDYNNOISE	_IOW('v', 209, int)
 #define VIDIOCPWCGDYNNOISE	_IOR('v', 209, int)
 
+ /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */
+#define VIDIOCPWCGREALSIZE	_IOR('v', 210, struct pwc_imagesize)
+ 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/pwc-uncompress.c linux-2.4.21/drivers/usb/pwc-uncompress.c
--- linux-2.4.20/drivers/usb/pwc-uncompress.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/drivers/usb/pwc-uncompress.c	2002-12-18 18:58:09.000000000 +0000
@@ -77,7 +77,7 @@
 {
 	struct pwc_frame_buf *fbuf;
 	int n, line, col, stride;
-	void *yuv, *image, *dst;
+	void *yuv, *image;
 	u16 *src;
 	u16 *dsty, *dstu, *dstv;
 
@@ -114,19 +114,6 @@
 		   to get the desired output format/size.
 		 */
 		switch (pdev->vpalette) {
-		case VIDEO_PALETTE_YUV420:
-			/* Calculate byte offsets per line in image & view */
-			n   = (pdev->image.x * 3) / 2;
-			col = (pdev->view.x  * 3) / 2;
-			/* Offset into image */
-			dst = image + (pdev->view.x * pdev->offset.y + pdev->offset.x) * 3 / 2;
-			for (line = 0; line < pdev->image.y; line++) {
-				memcpy(dst, yuv, n);
-				yuv += n;
-				dst += col;
-			}
-			break;
-
 		case VIDEO_PALETTE_YUV420P:
 			/* 
 			 * We do some byte shuffling here to go from the 
@@ -163,17 +150,20 @@
 					dstu += (stride >> 1);
 			}
 			break;
+		default:
+			Err("Unsupported palette!");
+			break;
 		}
 	}
 	else { 
 		/* Compressed; the decompressor routines will write the data 
-		   in interlaced or planar format immediately.
+		   in planar format immediately.
 		 */
 		if (pdev->decompressor)
 			pdev->decompressor->decompress(
 				&pdev->image, &pdev->view, &pdev->offset,
-				yuv, image, 
-				pdev->vpalette == VIDEO_PALETTE_YUV420P ? 1 : 0,
+				yuv, image,
+				1,
 				pdev->decompress_data, pdev->vbandlength);
 		else
 			return -ENXIO; /* No such device or address: missing decompressor */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/pwc.h linux-2.4.21/drivers/usb/pwc.h
--- linux-2.4.20/drivers/usb/pwc.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/drivers/usb/pwc.h	2002-12-18 18:58:10.000000000 +0000
@@ -60,8 +60,8 @@
 
 /* Version block */
 #define PWC_MAJOR	8
-#define PWC_MINOR	6
-#define PWC_VERSION 	"8.6"
+#define PWC_MINOR	10
+#define PWC_VERSION 	"8.10"
 #define PWC_NAME 	"pwc"
 
 /* Turn certain features on/off */
@@ -130,7 +130,7 @@
    int vcinterface;		/* video control interface */
    int valternate;		/* alternate interface needed */
    int vframes, vsize;		/* frames-per-second & size (see PSZ_*) */
-   int vpalette;		/* YUV, RGB24, RGB32, etc */
+   int vpalette;		/* YUV */
    int vframe_count;		/* received frames */
    int vframes_dumped; 		/* counter for dumped frames */
    int vframes_error;		/* frames received in error */
@@ -140,7 +140,8 @@
    int vbandlength;		/* compressed band length; 0 is uncompressed */
    char vsnapshot;		/* snapshot mode */
    char vsync;			/* used by isoc handler */
-   
+   char vmirror;		/* for ToUCaM series */
+
    /* The image acquisition requires 3 to 4 steps:
       1. data is gathered in short packets from the USB controller
       2. data is synchronized and packed into a frame buffer
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/rtl8150.c linux-2.4.21/drivers/usb/rtl8150.c
--- linux-2.4.20/drivers/usb/rtl8150.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/rtl8150.c	2002-12-18 18:58:07.000000000 +0000
@@ -7,6 +7,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/slab.h>
@@ -17,15 +18,14 @@
 #include <linux/ethtool.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/usb.h>
-#include <linux/init.h>
 #include <asm/uaccess.h>
 
 /* Version Information */
-#define DRIVER_VERSION "v0.4.1 (2002/07/22)"
+#define DRIVER_VERSION "v0.4.2 (2002/09/19)"
 #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
 #define DRIVER_DESC "rtl8150 based usb-ethernet driver"
 
-#define	IRD			0x0120
+#define	IDR			0x0120
 #define	MAR			0x0126
 #define	CR			0x012e
 #define	TCR			0x012f
@@ -45,6 +45,8 @@
 #define	ANLP			0x0146
 #define	AER			0x0148
 
+#define	IDR_EEPROM		0x1202
+
 #define	PHY_READ		0
 #define	PHY_WRITE		0x20
 #define	PHY_GO			0x40
@@ -71,6 +73,8 @@
 #define PRODUCT_ID_RTL8150		0x8150
 #define	PRODUCT_ID_LUAKTX		0x0012
 
+#undef EEPROM_WRITE
+
 /* table of devices that work with this driver */
 static struct usb_device_id rtl8150_table[] = {
 	{USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150)},
@@ -225,10 +229,51 @@
 {
 	u8 node_id[6];
 
-	get_registers(dev, IRD, sizeof(node_id), node_id);
+	get_registers(dev, IDR, sizeof(node_id), node_id);
 	memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));
 }
 
+static int rtl8150_set_mac_address(struct net_device *netdev, void *p)
+{
+	struct sockaddr *addr = p;
+	rtl8150_t *dev;
+	int i;
+
+	if (netif_running(netdev))
+		return -EBUSY;
+	dev = netdev->priv;
+	if (dev == NULL) {
+		return -ENODEV;
+	}
+	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+	dbg("%s: Setting MAC address to ", netdev->name);
+	for (i = 0; i < 5; i++)
+		printk("%02X:", netdev->dev_addr[i]);
+	dbg("%02X\n", netdev->dev_addr[i]);
+	/* Set the IDR registers. */
+	set_registers(dev, IDR, sizeof(netdev->dev_addr), netdev->dev_addr);
+#ifdef EEPROM_WRITE
+	{
+	u8 cr;
+	/* Get the CR contents. */
+	get_registers(dev, CR, 1, &cr);
+	/* Set the WEPROM bit (eeprom write enable). */
+	cr |= 0x20;
+	set_registers(dev, CR, 1, &cr);
+	/* Write the MAC address into eeprom. Eeprom writes must be word-sized,
+	   so we need to split them up. */
+	for (i = 0; i * 2 < netdev->addr_len; i++) {
+		set_registers(dev, IDR_EEPROM + (i * 2), 2, 
+		              netdev->dev_addr + (i * 2));
+	}
+	/* Clear the WEPROM bit (preventing accidental eeprom writes). */
+	cr &= 0xdf;
+	set_registers(dev, CR, 1, &cr);
+	}
+#endif	
+	return 0;
+}
+
 static int rtl8150_reset(rtl8150_t * dev)
 {
 	u8 data = 0x10;
@@ -666,6 +711,7 @@
 	netdev->tx_timeout = rtl8150_tx_timeout;
 	netdev->hard_start_xmit = rtl8150_start_xmit;
 	netdev->set_multicast_list = rtl8150_set_multicast;
+	netdev->set_mac_address = rtl8150_set_mac_address;
 	netdev->get_stats = rtl8150_netdev_stats;
 	netdev->mtu = RTL8150_MTU;
 	dev->intr_interval = 100;	/* 100ms */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/scanner.h linux-2.4.21/drivers/usb/scanner.h
--- linux-2.4.20/drivers/usb/scanner.h	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/scanner.h	2002-12-18 18:58:07.000000000 +0000
@@ -121,6 +121,8 @@
 	{ USB_DEVICE(0x03f0, 0x605) },	/* 2200C */
 	/* iVina */
 	{ USB_DEVICE(0x0638, 0x0268) }, /* 1200U */
+	/* Lexmark */
+	{ USB_DEVICE(0x043d, 0x002d) }, /* X70/X73 */
 	/* Lifetec */
 	{ USB_DEVICE(0x05d8, 0x4002) }, /* Lifetec LT9385 */
 	/* Memorex */
@@ -136,17 +138,25 @@
 	/* Minolta */
 	//	{ USB_DEVICE(0x0638,0x026a) }, /* Minolta Dimage Scan Dual II */
 	/* Mustek */
-	{ USB_DEVICE(0x055f, 0x0001) },	/* 1200 CU */
+	{ USB_DEVICE(0x055f, 0x0001) },	/* ScanExpress 1200 CU */
 	{ USB_DEVICE(0x0400, 0x1000) },	/* BearPaw 1200 */
-	{ USB_DEVICE(0x055f, 0x0002) },	/* 600 CU */
-	{ USB_DEVICE(0x055f, 0x0873) }, /* 600 USB */
-	{ USB_DEVICE(0x055f, 0x0003) },	/* 1200 USB */
-	{ USB_DEVICE(0x055f, 0x0006) },	/* 1200 UB */
+	{ USB_DEVICE(0x055f, 0x0002) },	/* ScanExpress 600 CU */
+	{ USB_DEVICE(0x055f, 0x0873) }, /* ScanExpress 600 USB */
+	{ USB_DEVICE(0x055f, 0x0003) },	/* ScanExpress 1200 USB */
+	{ USB_DEVICE(0x055f, 0x0006) },	/* ScanExpress 1200 UB */
+	{ USB_DEVICE(0x055f, 0x0007) },	/* ScanExpress 1200 USB Plus */
+	{ USB_DEVICE(0x055f, 0x0210) },	/* ScanExpress A3 USB */
 	{ USB_DEVICE(0x0400, 0x1001) }, /* BearPaw 2400 */
-	{ USB_DEVICE(0x055f, 0x0008) }, /* 1200 CU Plus */
-	{ USB_DEVICE(0x0ff5, 0x0010) }, /* BearPaw 1200F */
+	{ USB_DEVICE(0x055f, 0x0008) }, /* ScanExpress 1200 CU Plus */
+	{ USB_DEVICE(0x055f, 0x0010) }, /* BearPaw 1200F */
 	{ USB_DEVICE(0x055f, 0x0218) }, /* BearPaw 2400 TA */
-	{ USB_DEVICE(0x05d8, 0x4002) }, /* 1200 CU and 1200 UB Plus */
+	{ USB_DEVICE(0x05d8, 0x4002) }, /* BearPaw 1200 CU and ScanExpress 1200 UB Plus */
+	{ USB_DEVICE(0x055f, 0x0219) }, /* BearPaw 2400 TA Plus */
+	{ USB_DEVICE(0x055f, 0x021c) }, /* BearPaw 1200 CU Plus */
+	{ USB_DEVICE(0x055f, 0x021d) }, /* Bearpaw 2400 CU Plus */
+	{ USB_DEVICE(0x055f, 0x021e) }, /* BearPaw 1200 TA/CS */
+	{ USB_DEVICE(0x055f, 0x0400) }, /* BearPaw 2400 TA PRO */
+	{ USB_DEVICE(0x055f, 0x1000) }, /* BearPaw 4800 TA PRO */
 	/* Plustek */
 	{ USB_DEVICE(0x07b3, 0x0017) }, /* OpticPro UT12 */
 	{ USB_DEVICE(0x07b3, 0x0011) }, /* OpticPro UT24 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/Config.in linux-2.4.21/drivers/usb/serial/Config.in
--- linux-2.4.20/drivers/usb/serial/Config.in	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/serial/Config.in	2002-12-18 18:58:01.000000000 +0000
@@ -34,6 +34,7 @@
    fi
    dep_tristate '  USB MCT Single Port Serial Driver' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL
    dep_tristate '  USB KL5KUSB105 (Palmconnect) Driver' CONFIG_USB_SERIAL_KLSI $CONFIG_USB_SERIAL
+   dep_tristate '  USB KOBIL chipcard reader (EXPERIMENTAL)' CONFIG_USB_SERIAL_KOBIL_SCT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
    dep_tristate '  USB Prolific 2303 Single Port Serial Driver' CONFIG_USB_SERIAL_PL2303 $CONFIG_USB_SERIAL
    dep_tristate '  USB REINER SCT cyberJack pinpad/e-com chipcard reader (EXPERIMENTAL)' CONFIG_USB_SERIAL_CYBERJACK $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
    dep_tristate '  USB Xircom / Entregra Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_XIRCOM $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/Makefile linux-2.4.21/drivers/usb/serial/Makefile
--- linux-2.4.20/drivers/usb/serial/Makefile	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/serial/Makefile	2002-12-18 18:58:03.000000000 +0000
@@ -25,6 +25,7 @@
 obj-$(CONFIG_USB_SERIAL_CYBERJACK)		+= cyberjack.o
 obj-$(CONFIG_USB_SERIAL_IR)			+= ir-usb.o
 obj-$(CONFIG_USB_SERIAL_KLSI)			+= kl5kusb105.o
+obj-$(CONFIG_USB_SERIAL_KOBIL_SCT)		+= kobil_sct.o
 
 # Objects that export symbols.
 export-objs	:= usbserial.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/ftdi_sio.c linux-2.4.21/drivers/usb/serial/ftdi_sio.c
--- linux-2.4.20/drivers/usb/serial/ftdi_sio.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/serial/ftdi_sio.c	2002-12-18 18:58:05.000000000 +0000
@@ -17,6 +17,14 @@
  * See http://ftdi-usb-sio.sourceforge.net for upto date testing info
  *	and extra documentation
  *
+ * (07/Jun/2002) Kuba Ober
+ *	Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor
+ *	function. It was getting too complex.
+ *	Fix the divisor calculation logic which was setting divisor of 0.125
+ *	instead of 0.5 for fractional parts of divisor equal to 5/8, 6/8, 7/8.
+ *	Also make it bump up the divisor to next integer in case of 7/8 - it's
+ *	a better approximation.
+ *
  * (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch
  *      Not tested by me but it doesn't break anything I use.
  * 
@@ -203,6 +211,10 @@
 static void ftdi_set_termios		(struct usb_serial_port *port, struct termios * old);
 static int  ftdi_ioctl			(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
 static void ftdi_break_ctl		(struct usb_serial_port *port, int break_state );
+static unsigned short int ftdi_baud_base_to_divisor
+					(int baud, int base);
+static unsigned short int ftdi_baud_to_divisor
+					(int baud);
 
 static struct usb_serial_device_type ftdi_SIO_device = {
 	.owner =		THIS_MODULE,
@@ -257,6 +269,23 @@
  * ***************************************************************************
  */
 
+static unsigned short int ftdi_baud_base_to_divisor(int baud, int base)
+{
+	unsigned short int divisor;
+	int divisor3 = base / 2 / baud; // divisor shifted 3 bits to the left
+	if ((divisor3 & 0x7) == 7) divisor3 ++; // round x.7/8 up to x+1
+	divisor = divisor3 >> 3;
+	divisor3 &= 0x7;
+	if (divisor3 == 1) divisor |= 0xc000; else // 0.125
+	if (divisor3 >= 4) divisor |= 0x4000; else // 0.5
+	if (divisor3 != 0) divisor |= 0x8000;      // 0.25
+	return divisor;
+}
+
+static unsigned short int ftdi_baud_to_divisor(int baud)
+{
+	 return(ftdi_baud_base_to_divisor(baud, 48000000));
+}
 
 static int set_rts(struct usb_device *dev,
 		   unsigned int pipe,
@@ -373,7 +402,7 @@
 		break;
 	case FT8U232AM: /* 8U232AM chip */
 		if (baud <= 3000000) {
-			urb_value = FTDI_SIO_BAUD_TO_DIVISOR(baud);
+			urb_value = ftdi_baud_to_divisor(baud);
 		} else {
 	                dbg("%s - Baud rate too high!", __FUNCTION__);
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/ftdi_sio.h linux-2.4.21/drivers/usb/serial/ftdi_sio.h
--- linux-2.4.20/drivers/usb/serial/ftdi_sio.h	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/serial/ftdi_sio.h	2002-12-18 18:58:06.000000000 +0000
@@ -125,17 +125,9 @@
  ftdi_sio_b115200 = 9
 } FTDI_SIO_baudrate_t ;
 
-#define FTDI_SIO_BASE_BAUD_TO_DIVISOR(base, baud) ( \
-((base/2/baud) >> 3) | \
-(((base/2/baud) & 2) ? 0x8000 : 0) | \
-(((base/2/baud) & 4) ? 0x4000 : 0) | \
-((((base/2/baud) & 0x7) == 1) ? 0xc000 : 0) )
-
-#define FTDI_SIO_BAUD_TO_DIVISOR(baud) FTDI_SIO_BASE_BAUD_TO_DIVISOR(48000000, baud)
-
 /*
- * The ftdi_8U232AM_xxMHz_byyy constans have been removed. Their values can
- * be calculated as follows: FTDI_SIO_BAUD_TO_DIVISOR(xx000000, yyy)
+ * The ftdi_8U232AM_xxMHz_byyy constants have been removed. The encoded divisor values
+ * are calculated internally.
  */
 
 #define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/io_16654.h linux-2.4.21/drivers/usb/serial/io_16654.h
--- linux-2.4.20/drivers/usb/serial/io_16654.h	2001-03-20 01:21:54.000000000 +0000
+++ linux-2.4.21/drivers/usb/serial/io_16654.h	2002-12-18 18:58:06.000000000 +0000
@@ -142,14 +142,14 @@
 #define LSR_FIFO_ERR		0x80	// Rx Fifo contains at least 1 erred char
 
 
-#define MSR_DELTA_CTS		0x01	// CTS changed from last read
-#define MSR_DELTA_DSR		0x02	// DSR changed from last read
-#define MSR_DELTA_RI		0x04	// RI  changed from 0 -> 1
-#define MSR_DELTA_CD		0x08	// CD  changed from last read
-#define MSR_CTS			0x10	// Current state of CTS
-#define MSR_DSR			0x20	// Current state of DSR
-#define MSR_RI			0x40	// Current state of RI
-#define MSR_CD			0x80	// Current state of CD
+#define EDGEPORT_MSR_DELTA_CTS		0x01	// CTS changed from last read
+#define EDGEPORT_MSR_DELTA_DSR		0x02	// DSR changed from last read
+#define EDGEPORT_MSR_DELTA_RI		0x04	// RI  changed from 0 -> 1
+#define EDGEPORT_MSR_DELTA_CD		0x08	// CD  changed from last read
+#define EDGEPORT_MSR_CTS			0x10	// Current state of CTS
+#define EDGEPORT_MSR_DSR			0x20	// Current state of DSR
+#define EDGEPORT_MSR_RI			0x40	// Current state of RI
+#define EDGEPORT_MSR_CD			0x80	// Current state of CD
 
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/io_edgeport.c linux-2.4.21/drivers/usb/serial/io_edgeport.c
--- linux-2.4.20/drivers/usb/serial/io_edgeport.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/serial/io_edgeport.c	2002-12-18 18:58:02.000000000 +0000
@@ -1790,10 +1790,10 @@
 
 	result = ((mcr & MCR_DTR)	? TIOCM_DTR: 0)	  /* 0x002 */
 		  | ((mcr & MCR_RTS)	? TIOCM_RTS: 0)   /* 0x004 */
-		  | ((msr & MSR_CTS)	? TIOCM_CTS: 0)   /* 0x020 */
-		  | ((msr & MSR_CD)	? TIOCM_CAR: 0)   /* 0x040 */
-		  | ((msr & MSR_RI)	? TIOCM_RI:  0)   /* 0x080 */
-		  | ((msr & MSR_DSR)	? TIOCM_DSR: 0);  /* 0x100 */
+		  | ((msr & EDGEPORT_MSR_CTS)	? TIOCM_CTS: 0)   /* 0x020 */
+		  | ((msr & EDGEPORT_MSR_CD)	? TIOCM_CAR: 0)   /* 0x040 */
+		  | ((msr & EDGEPORT_MSR_RI)	? TIOCM_RI:  0)   /* 0x080 */
+		  | ((msr & EDGEPORT_MSR_DSR)	? TIOCM_DSR: 0);  /* 0x100 */
 
 
 	dbg("%s -- %x", __FUNCTION__, result);
@@ -2219,20 +2219,20 @@
 
 	dbg("%s %02x", __FUNCTION__, newMsr);
 
-	if (newMsr & (MSR_DELTA_CTS | MSR_DELTA_DSR | MSR_DELTA_RI | MSR_DELTA_CD)) {
+	if (newMsr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR | EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) {
 		icount = &edge_port->icount;
 
 		/* update input line counters */
-		if (newMsr & MSR_DELTA_CTS) {
+		if (newMsr & EDGEPORT_MSR_DELTA_CTS) {
 			icount->cts++;
 		}
-		if (newMsr & MSR_DELTA_DSR) {
+		if (newMsr & EDGEPORT_MSR_DELTA_DSR) {
 			icount->dsr++;
 		}
-		if (newMsr & MSR_DELTA_CD) {
+		if (newMsr & EDGEPORT_MSR_DELTA_CD) {
 			icount->dcd++;
 		}
-		if (newMsr & MSR_DELTA_RI) {
+		if (newMsr & EDGEPORT_MSR_DELTA_RI) {
 			icount->rng++;
 		}
 		wake_up_interruptible(&edge_port->delta_msr_wait);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/io_ti.c linux-2.4.21/drivers/usb/serial/io_ti.c
--- linux-2.4.20/drivers/usb/serial/io_ti.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/serial/io_ti.c	2002-12-18 18:58:08.000000000 +0000
@@ -1549,17 +1549,17 @@
 
 	dbg ("%s - %02x", __FUNCTION__, msr);
 
-	if (msr & (MSR_DELTA_CTS | MSR_DELTA_DSR | MSR_DELTA_RI | MSR_DELTA_CD)) {
+	if (msr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR | EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) {
 		icount = &edge_port->icount;
 
 		/* update input line counters */
-		if (msr & MSR_DELTA_CTS)
+		if (msr & EDGEPORT_MSR_DELTA_CTS)
 			icount->cts++;
-		if (msr & MSR_DELTA_DSR)
+		if (msr & EDGEPORT_MSR_DELTA_DSR)
 			icount->dsr++;
-		if (msr & MSR_DELTA_CD)
+		if (msr & EDGEPORT_MSR_DELTA_CD)
 			icount->dcd++;
-		if (msr & MSR_DELTA_RI)
+		if (msr & EDGEPORT_MSR_DELTA_RI)
 			icount->rng++;
 		wake_up_interruptible (&edge_port->delta_msr_wait);
 	}
@@ -2416,10 +2416,10 @@
 
 	result = ((mcr & MCR_DTR)	? TIOCM_DTR: 0)	  /* 0x002 */
 		  | ((mcr & MCR_RTS)	? TIOCM_RTS: 0)   /* 0x004 */
-		  | ((msr & MSR_CTS)	? TIOCM_CTS: 0)   /* 0x020 */
-		  | ((msr & MSR_CD)	? TIOCM_CAR: 0)   /* 0x040 */
-		  | ((msr & MSR_RI)	? TIOCM_RI:  0)   /* 0x080 */
-		  | ((msr & MSR_DSR)	? TIOCM_DSR: 0);  /* 0x100 */
+		  | ((msr & EDGEPORT_MSR_CTS)	? TIOCM_CTS: 0)   /* 0x020 */
+		  | ((msr & EDGEPORT_MSR_CD)	? TIOCM_CAR: 0)   /* 0x040 */
+		  | ((msr & EDGEPORT_MSR_RI)	? TIOCM_RI:  0)   /* 0x080 */
+		  | ((msr & EDGEPORT_MSR_DSR)	? TIOCM_DSR: 0);  /* 0x100 */
 
 
 	dbg("%s -- %x", __FUNCTION__, result);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/ipaq.c linux-2.4.21/drivers/usb/serial/ipaq.c
--- linux-2.4.20/drivers/usb/serial/ipaq.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/serial/ipaq.c	2002-12-18 18:58:09.000000000 +0000
@@ -9,6 +9,10 @@
  *	the Free Software Foundation; either version 2 of the License, or
  *	(at your option) any later version.
  *
+ * (26/11/2002) ganesh
+ * 	Added insmod options to specify product and vendor id.
+ * 	Use modprobe ipaq vendor=0xfoo product=0xbar
+ *
  * (26/7/2002) ganesh
  * 	Fixed up broken error handling in ipaq_open. Retry the "kickstart"
  * 	packet much harder - this drastically reduces connection failures.
@@ -63,10 +67,13 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.2"
+
+#define DRIVER_VERSION "v0.4"
 #define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>"
 #define DRIVER_DESC "USB Compaq iPAQ, HP Jornada, Casio EM500 driver"
 
+static int	product, vendor;
+
 /* Function prototypes for an ipaq */
 static int  ipaq_open (struct usb_serial_port *port, struct file *filp);
 static void ipaq_close (struct usb_serial_port *port, struct file *filp);
@@ -85,6 +92,8 @@
 
 
 static struct usb_device_id ipaq_id_table [] = {
+	/* The first entry is a placeholder for the insmod-specified device */
+	{ USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) },
 	{ USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) },
 	{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_548_ID) },
 	{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_568_ID) },
@@ -516,8 +525,13 @@
 
 static int __init ipaq_init(void)
 {
-	usb_serial_register(&ipaq_device);
+	spin_lock_init(&write_list_lock);
 	info(DRIVER_DESC " " DRIVER_VERSION);
+	if (vendor) {
+		ipaq_id_table[0].idVendor = vendor;
+		ipaq_id_table[0].idProduct = product;
+	}
+	usb_serial_register(&ipaq_device);
 
 	return 0;
 }
@@ -539,3 +553,8 @@
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 
+MODULE_PARM(vendor, "h");
+MODULE_PARM_DESC(vendor, "User specified USB idVendor");
+
+MODULE_PARM(product, "h");
+MODULE_PARM_DESC(product, "User specified USB idProduct");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/keyspan.c linux-2.4.21/drivers/usb/serial/keyspan.c
--- linux-2.4.20/drivers/usb/serial/keyspan.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/serial/keyspan.c	2002-12-18 18:58:03.000000000 +0000
@@ -343,7 +343,7 @@
 		if (this_urb->status == -EINPROGRESS) {
 			if (this_urb->transfer_flags & USB_ASYNC_UNLINK)
 				break;
-			if (jiffies - p_priv->tx_start_time[flip] < 10 * HZ)
+			if (time_before(jiffies, p_priv->tx_start_time[flip] + 10 * HZ))
 				break;
 			this_urb->transfer_flags |= USB_ASYNC_UNLINK;
 			usb_unlink_urb(this_urb);
@@ -530,6 +530,7 @@
 		dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
 	}
 exit:
+	;
 }
 
 static void	usa26_glocont_callback(struct urb *urb)
@@ -665,6 +666,7 @@
 		dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
 	}
 exit:	
+	;
 }
 
 static void	usa28_glocont_callback(struct urb *urb)
@@ -758,6 +760,7 @@
 		dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
 	}
 exit:	
+	;
 }
 
 static void	usa49_inack_callback(struct urb *urb)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/kobil_sct.c linux-2.4.21/drivers/usb/serial/kobil_sct.c
--- linux-2.4.20/drivers/usb/serial/kobil_sct.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/usb/serial/kobil_sct.c	2002-12-18 18:58:05.000000000 +0000
@@ -0,0 +1,713 @@
+/*
+ *  KOBIL USB Smart Card Terminal Driver
+ *
+ *  Copyright (C) 2002  KOBIL Systems GmbH 
+ *  Author: Thomas Wahrenbruch
+ *
+ *  Contact: linuxusb@kobil.de
+ *
+ *  This program is largely derived from work by the linux-usb group
+ *  and associated source files.  Please see the usb/serial files for
+ *  individual credits and copyrights.
+ *
+ *  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.
+ *
+ *  Thanks to Greg Kroah-Hartman (greg@kroah.com) for his help and
+ *  patience.
+ *
+ * Supported readers: USB TWIN, KAAN Standard Plus and SecOVID Reader Plus
+ * (Adapter K), B1 Professional and KAAN Professional (Adapter B)
+ * 
+ * TODO: High baudrates
+ *
+ * (12/03/2002) tw
+ *      Fixed bug with Pro-readers and PNP
+ *
+ * (11/13/2002) tw
+ *      Initial version.
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <asm/uaccess.h>
+#include <linux/usb.h>
+
+#include <linux/ioctl.h>
+
+
+#include "kobil_sct.h"
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	static int debug = 1;
+#else
+	static int debug;
+#endif
+
+#include "usb-serial.h"
+
+/* Version Information */
+#define DRIVER_VERSION "12/03/2002"
+#define DRIVER_AUTHOR "KOBIL Systems GmbH - http://www.kobil.com"
+#define DRIVER_DESC "KOBIL USB Smart Card Terminal Driver (experimental)"
+
+#define KOBIL_VENDOR_ID	           0x0D46
+#define KOBIL_ADAPTER_B_PRODUCT_ID 0x2011
+#define KOBIL_ADAPTER_K_PRODUCT_ID 0x2012
+#define KOBIL_USBTWIN_PRODUCT_ID   0x0078
+
+#define KOBIL_TIMEOUT    500
+#define KOBIL_BUF_LENGTH 300
+
+
+/* Function prototypes */
+static int  kobil_startup (struct usb_serial *serial);
+static void kobil_shutdown (struct usb_serial *serial);
+static int  kobil_open (struct usb_serial_port *port, struct file *filp);
+static void kobil_close (struct usb_serial_port *port, struct file *filp);
+static int  kobil_write (struct usb_serial_port *port, int from_user, 
+			 const unsigned char *buf, int count);
+static int  kobil_write_room(struct usb_serial_port *port);
+static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
+			unsigned int cmd, unsigned long arg);
+static void kobil_read_int_callback( struct urb *urb );
+static void kobil_write_callback( struct urb *purb );
+
+
+static struct usb_device_id id_table [] = {
+	{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_B_PRODUCT_ID) },
+	{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_K_PRODUCT_ID) },
+	{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_USBTWIN_PRODUCT_ID) },
+	{ }			/* Terminating entry */
+};
+
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+struct usb_serial_device_type kobil_device = {
+	.owner =                THIS_MODULE,
+	.name =			"KOBIL USB smart card terminal",
+	.id_table =		id_table,
+	.num_interrupt_in =	NUM_DONT_CARE,
+	.num_bulk_in =		0,
+	.num_bulk_out =		0,
+	.num_ports =		1,
+	.startup =		kobil_startup,
+	.shutdown =		kobil_shutdown,
+	.ioctl =		kobil_ioctl,
+	.open =			kobil_open,
+	.close =		kobil_close,
+	.write =		kobil_write,
+	.write_room =           kobil_write_room,
+	.read_int_callback =	kobil_read_int_callback,
+};
+
+
+struct kobil_private {
+	int write_int_endpoint_address;
+	int read_int_endpoint_address;
+	unsigned char buf[KOBIL_BUF_LENGTH]; // buffer for the APDU to send
+	int filled;  // index of the last char in buf
+	int cur_pos; // index of the next char to send in buf
+	__u16 device_type;
+	int line_state;
+	struct termios internal_termios;
+};
+
+
+static int kobil_startup (struct usb_serial *serial)
+{
+	int i;
+	struct kobil_private *priv;
+	struct usb_device *pdev;
+	struct usb_config_descriptor *actconfig;
+	struct usb_interface *interface;
+	struct usb_interface_descriptor *altsetting;
+	struct usb_endpoint_descriptor *endpoint;
+
+	serial->port->private = kmalloc(sizeof(struct kobil_private), GFP_KERNEL);
+	if (!serial->port->private){
+		return -1;
+	}
+ 
+	priv = (struct kobil_private *) serial->port->private;
+	priv->filled = 0;
+	priv->cur_pos = 0;
+	priv->device_type = serial->product;
+	priv->line_state = 0;
+	
+	switch (priv->device_type){
+	case KOBIL_ADAPTER_B_PRODUCT_ID:
+		printk(KERN_DEBUG "KOBIL B1 PRO / KAAN PRO detected\n");
+		break;
+	case KOBIL_ADAPTER_K_PRODUCT_ID:
+		printk(KERN_DEBUG "KOBIL KAAN Standard Plus / SecOVID Reader Plus detected\n");
+		break;
+	case KOBIL_USBTWIN_PRODUCT_ID:
+		printk(KERN_DEBUG "KOBIL USBTWIN detected\n");
+		break;
+	}
+
+	// search for the neccessary endpoints
+	pdev = serial->dev;
+ 	actconfig = pdev->actconfig;
+ 	interface = actconfig->interface;
+	altsetting = interface->altsetting;
+ 	endpoint = altsetting->endpoint;
+  
+ 	for (i = 0; i < altsetting->bNumEndpoints; i++) {
+		endpoint = &altsetting->endpoint[i];
+		if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) && 
+ 		    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
+		 	dbg("%s Found interrupt out endpoint. Address: %d", __FUNCTION__, endpoint->bEndpointAddress);
+		 	priv->write_int_endpoint_address = endpoint->bEndpointAddress;
+ 		}
+ 		if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) && 
+ 		    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
+		 	dbg("%s Found interrupt in  endpoint. Address: %d", __FUNCTION__, endpoint->bEndpointAddress);
+		 	priv->read_int_endpoint_address = endpoint->bEndpointAddress;
+	 	}
+	}
+	return 0;
+}
+
+
+static void kobil_shutdown (struct usb_serial *serial)
+{
+	int i;
+  	dbg("%s - port %d", __FUNCTION__, serial->port->number);
+
+	for (i=0; i < serial->num_ports; ++i) {
+		while (serial->port[i].open_count > 0) {
+			kobil_close (&serial->port[i], NULL);
+		}
+		if (serial->port[i].private) {
+			kfree(serial->port[i].private);
+		}
+	} 
+}
+
+
+static int kobil_open (struct usb_serial_port *port, struct file *filp)
+{
+	int i, result = 0;
+	struct kobil_private *priv;
+	unsigned char *transfer_buffer;
+	int transfer_buffer_length = 8;
+	int write_urb_transfer_buffer_length = 8;
+	
+  	dbg("%s - port %d", __FUNCTION__, port->number);
+	priv = (struct kobil_private *) port->private;
+	priv->line_state = 0;
+
+	if (port_paranoia_check (port, __FUNCTION__))
+		return -ENODEV;
+	
+	// someone sets the dev to 0 if the close method has been called
+	port->interrupt_in_urb->dev = port->serial->dev;
+
+	
+	/* force low_latency on so that our tty_push actually forces
+	 * the data through, otherwise it is scheduled, and with high
+	 * data rates (like with OHCI) data can get lost.
+	 */
+	port->tty->low_latency = 1;
+
+	// without this, every push_tty_char is echoed :-(  
+	port->tty->termios->c_lflag = 0;
+	port->tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE);
+	port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
+	port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D)
+	
+	// set up internal termios structure 
+	priv->internal_termios.c_iflag = port->tty->termios->c_iflag;
+	priv->internal_termios.c_oflag = port->tty->termios->c_oflag;
+	priv->internal_termios.c_cflag = port->tty->termios->c_cflag;
+	priv->internal_termios.c_lflag = port->tty->termios->c_lflag;
+	
+	for (i=0; i<NCCS; i++) {
+		priv->internal_termios.c_cc[i] = port->tty->termios->c_cc[i];
+	}
+	
+	// allocate memory for transfer buffer
+	transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);  
+	if (! transfer_buffer) {
+		return -1;
+	} else {
+		memset(transfer_buffer, 0, transfer_buffer_length);
+	}
+	
+	// allocate write_urb
+	if (!port->write_urb) { 
+		dbg("%s - port %d  Allocating port->write_urb", __FUNCTION__, port->number);
+		port->write_urb = usb_alloc_urb(0);  
+		if (!port->write_urb) {
+			dbg("%s - port %d usb_alloc_urb failed", __FUNCTION__, port->number);
+			return -1;
+		}
+	}
+ 
+	// allocate memory for write_urb transfer buffer
+	port->write_urb->transfer_buffer = (unsigned char *) kmalloc(write_urb_transfer_buffer_length, GFP_KERNEL);
+	if (! port->write_urb->transfer_buffer) {
+		return -1;
+	} 
+
+	// get hardware version
+	result = usb_control_msg( port->serial->dev, 
+				  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+				  SUSBCRequest_GetMisc,
+				  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN,
+				  SUSBCR_MSC_GetHWVersion,
+				  0,
+				  transfer_buffer,
+				  transfer_buffer_length,
+				  KOBIL_TIMEOUT
+		);
+	dbg("%s - port %d Send get_HW_version URB returns: %i", __FUNCTION__, port->number, result);
+	dbg("Harware version: %i.%i.%i", transfer_buffer[0], transfer_buffer[1], transfer_buffer[2] );
+	
+	// get firmware version
+	result = usb_control_msg( port->serial->dev, 
+				  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+				  SUSBCRequest_GetMisc,
+				  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN,
+				  SUSBCR_MSC_GetFWVersion,
+				  0,
+				  transfer_buffer,
+				  transfer_buffer_length,
+				  KOBIL_TIMEOUT
+		);
+	dbg("%s - port %d Send get_FW_version URB returns: %i", __FUNCTION__, port->number, result);
+	dbg("Firmware version: %i.%i.%i", transfer_buffer[0], transfer_buffer[1], transfer_buffer[2] );
+
+	if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) {
+		// Setting Baudrate, Parity and Stopbits
+		result = usb_control_msg( port->serial->dev, 
+					  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+					  SUSBCRequest_SetBaudRateParityAndStopBits,
+					  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+					  SUSBCR_SBR_9600 | SUSBCR_SPASB_EvenParity | SUSBCR_SPASB_1StopBit,
+					  0,
+					  transfer_buffer,
+					  0,
+					  KOBIL_TIMEOUT
+			);
+		dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result);
+		
+		// reset all queues
+		result = usb_control_msg( port->serial->dev, 
+					  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+					  SUSBCRequest_Misc,
+					  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+					  SUSBCR_MSC_ResetAllQueues,
+					  0,
+					  transfer_buffer,
+					  0,
+					  KOBIL_TIMEOUT
+			);
+		dbg("%s - port %d Send reset_all_queues URB returns: %i", __FUNCTION__, port->number, result);
+	}
+
+	if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) {
+		// start reading (Adapter B 'cause PNP string)
+		result = usb_submit_urb( port->interrupt_in_urb ); 
+		dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
+	}
+
+	kfree(transfer_buffer);
+	return 0;
+}
+
+
+static void kobil_close (struct usb_serial_port *port, struct file *filp)
+{
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (port->write_urb){
+		usb_unlink_urb( port->write_urb );
+		usb_free_urb( port->write_urb );
+		port->write_urb = 0;
+	}
+	if (port->interrupt_in_urb){
+		usb_unlink_urb (port->interrupt_in_urb);
+	}
+}
+
+
+static void kobil_read_int_callback( struct urb *purb )
+{  
+	int i;
+	struct usb_serial_port *port = (struct usb_serial_port *) purb->context;
+	struct tty_struct *tty;
+	unsigned char *data = purb->transfer_buffer;
+	char *dbg_data;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (purb->status) {
+		dbg("%s - port %d Read int status not zero: %d", __FUNCTION__, port->number, purb->status);
+		return;
+	}
+	
+	tty = port->tty; 
+	if (purb->actual_length) {
+		
+		// BEGIN DEBUG
+		dbg_data = (unsigned char *) kmalloc((3 *  purb->actual_length + 10) * sizeof(char), GFP_KERNEL);  
+		if (! dbg_data) {
+			return;
+		}
+		memset(dbg_data, 0, (3 *  purb->actual_length + 10));
+		for (i = 0; i < purb->actual_length; i++) { 
+			sprintf(dbg_data +3*i, "%02X ", data[i]); 
+		}
+		dbg(" <-- %s", dbg_data );
+		kfree(dbg_data);
+		// END DEBUG
+
+		for (i = 0; i < purb->actual_length; ++i) {
+			// if we insert more than TTY_FLIPBUF_SIZE characters, we drop them.
+			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				tty_flip_buffer_push(tty);
+			}
+			// this doesn't actually push the data through unless tty->low_latency is set
+			tty_insert_flip_char(tty, data[i], 0);
+		}
+		tty_flip_buffer_push(tty);
+	}
+}
+
+
+static void kobil_write_callback( struct urb *purb )
+{
+}
+
+
+static int kobil_write (struct usb_serial_port *port, int from_user, 
+			const unsigned char *buf, int count)
+{
+	int length = 0;
+	int result = 0;
+	int todo = 0;
+	struct kobil_private * priv;
+	int i;
+	char *data;
+
+	if (count == 0) {
+		dbg("%s - port %d write request of 0 bytes", __FUNCTION__, port->number);
+		return 0;
+	}
+
+	priv = (struct kobil_private *) port->private;
+
+	if (count > (KOBIL_BUF_LENGTH - priv->filled)) {
+		dbg("%s - port %d Error: write request bigger than buffer size", __FUNCTION__, port->number);
+		return -ENOMEM;
+	}
+	
+	// BEGIN DEBUG
+	data = (unsigned char *) kmalloc((3 * count + 10) * sizeof(char), GFP_KERNEL);  
+	if (! data) {
+		return (-1);
+	}
+	memset(data, 0, (3 * count + 10));
+	for (i = 0; i < count; i++) { 
+		sprintf(data +3*i, "%02X ", buf[i]); 
+	} 
+	dbg(" %d --> %s", port->number, data );
+	kfree(data);
+	// END DEBUG
+
+	// Copy data to buffer
+	if (from_user) {
+		if (copy_from_user(priv->buf + priv->filled, buf, count)) {
+			return -EFAULT;
+		}
+	} else {
+		memcpy (priv->buf + priv->filled, buf, count);
+	}
+
+	priv->filled = priv->filled + count;
+  
+
+	// only send complete block. TWIN and adapter K use the same protocol.
+	if ( ((priv->device_type != KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 2) && (priv->filled >= (priv->buf[1] + 3))) || 
+	     ((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 3) && (priv->filled >= (priv->buf[2] + 4))) ) {
+		
+		// stop reading (except TWIN)
+		if (priv->device_type != KOBIL_USBTWIN_PRODUCT_ID) {
+			usb_unlink_urb( port->interrupt_in_urb );
+		}
+		
+		todo = priv->filled - priv->cur_pos;
+
+		while(todo > 0) {
+			// max 8 byte in one urb (endpoint size)
+			length = (todo < 8) ? todo : 8;
+			// copy data to transfer buffer
+			memcpy(port->write_urb->transfer_buffer, priv->buf + priv->cur_pos, length );
+			
+			usb_fill_bulk_urb( port->write_urb,
+					   port->serial->dev,
+					   usb_sndbulkpipe( port->serial->dev, priv->write_int_endpoint_address),
+					   port->write_urb->transfer_buffer,
+					   length,
+					   kobil_write_callback,
+					   port
+				);
+
+			priv->cur_pos = priv->cur_pos + length;
+			result = usb_submit_urb( port->write_urb );
+			dbg("%s - port %d Send write URB returns: %i", __FUNCTION__, port->number, result);
+			todo = priv->filled - priv->cur_pos;
+
+			if (todo > 0) {
+				//mdelay(16);
+				set_current_state(TASK_UNINTERRUPTIBLE);
+				schedule_timeout(24 * HZ / 1000);
+			}
+
+		} // end while
+		
+		priv->filled = 0;
+		priv->cur_pos = 0;
+				
+		// start reading (except TWIN)	
+		if (priv->device_type != KOBIL_USBTWIN_PRODUCT_ID) {
+			// someone sets the dev to 0 if the close method has been called
+			port->interrupt_in_urb->dev = port->serial->dev;
+		
+			// start reading
+			result = usb_submit_urb( port->interrupt_in_urb ); 
+			dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
+		}
+		
+	}
+	return count;  
+}
+
+
+static int kobil_write_room (struct usb_serial_port *port)
+{
+	return 8;
+}
+
+
+static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	struct kobil_private * priv;
+	int mask;
+	int result;
+	unsigned short urb_val = 0;
+	unsigned char *transfer_buffer;
+	int transfer_buffer_length = 8;
+	char *settings;
+
+	priv = (struct kobil_private *) port->private;
+	if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) {
+		// This device doesn't support ioctl calls
+		return 0;
+	}
+
+	switch (cmd) {
+	case TCGETS:   // 0x5401
+		result = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct termios));
+		if (result) {
+			dbg("%s - port %d Error in verify_area", __FUNCTION__, port->number);
+			return(result);
+		}
+		kernel_termios_to_user_termios((struct termios *)arg, &priv->internal_termios);
+		return 0;
+
+	case TCSETS:   // 0x5402
+		if (! &port->tty->termios) {
+			dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number);
+			return -ENOTTY;
+		}
+		result = verify_area(VERIFY_READ, (void *)arg, sizeof(struct termios));
+		if (result) {
+			dbg("%s - port %d Error in verify_area", __FUNCTION__, port->number);
+			return result;
+		}
+		user_termios_to_kernel_termios( &priv->internal_termios, (struct termios *)arg);
+		
+		settings = (unsigned char *) kmalloc(50, GFP_KERNEL);  
+		if (! settings) {
+			return -ENOBUFS;
+		}
+		memset(settings, 0, 50);
+
+		switch (priv->internal_termios.c_cflag & CBAUD) {
+		case B1200:
+			urb_val = SUSBCR_SBR_1200;
+			strcat(settings, "1200 ");
+			break;
+		case B9600:
+		default:
+			urb_val = SUSBCR_SBR_9600;
+			strcat(settings, "9600 ");
+			break;
+		}
+
+		urb_val |= (priv->internal_termios.c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
+		strcat(settings, (priv->internal_termios.c_cflag & CSTOPB) ? "2 StopBits " : "1 StopBit ");
+		
+		if (priv->internal_termios.c_cflag & PARENB) {
+			if  (priv->internal_termios.c_cflag & PARODD) {
+				urb_val |= SUSBCR_SPASB_OddParity;
+				strcat(settings, "Odd Parity");
+			} else {
+				urb_val |= SUSBCR_SPASB_EvenParity;
+				strcat(settings, "Even Parity");
+			}
+		} else {
+			urb_val |= SUSBCR_SPASB_NoParity;
+			strcat(settings, "No Parity");
+		}
+		dbg("%s - port %d setting port to: %s", __FUNCTION__, port->number, settings );
+
+		result = usb_control_msg( port->serial->dev, 
+					  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+					  SUSBCRequest_SetBaudRateParityAndStopBits,
+					  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+					  urb_val,
+					  0,
+					  settings,
+					  0,
+					  KOBIL_TIMEOUT
+			);
+		
+		dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result);
+		kfree(settings);
+		return 0;
+    
+	case TCFLSH:   // 0x540B
+		result = usb_control_msg( port->serial->dev, 
+		 			  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+					  SUSBCRequest_Misc,
+					  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+					  SUSBCR_MSC_ResetAllQueues,
+					  0,
+					  NULL,
+					  0,
+					  KOBIL_TIMEOUT
+			);
+		
+		dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result);
+		return ((result < 0) ? -EFAULT : 0);
+
+	case TIOCMGET: // 0x5415
+		// allocate memory for transfer buffer
+		transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);  
+		if (! transfer_buffer) {
+			return -ENOBUFS;
+		} else {
+			memset(transfer_buffer, 0, transfer_buffer_length);
+		}
+
+		result = usb_control_msg( port->serial->dev, 
+					  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+					  SUSBCRequest_GetStatusLineState,
+					  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN,
+					  0,
+					  0,
+					  transfer_buffer,
+					  transfer_buffer_length,
+					  KOBIL_TIMEOUT
+			);
+	
+		dbg("%s - port %d Send get_status_line_state (TIOCMGET) URB returns: %i. Statusline: %02x", 
+		    __FUNCTION__, port->number, result, transfer_buffer[0]);
+	
+		if ((transfer_buffer[0] & SUSBCR_GSL_DSR) != 0) {
+			priv->line_state |= TIOCM_DSR;
+		} else {
+			priv->line_state &= ~TIOCM_DSR; 
+		}
+		
+		kfree(transfer_buffer);
+		return put_user(priv->line_state, (unsigned long *) arg);
+		
+	case TIOCMSET: // 0x5418
+		if (get_user(mask, (unsigned long *) arg)){
+			return -EFAULT;
+		}
+		if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) {
+			if ((mask & TIOCM_DTR) != 0){
+				dbg("%s - port %d Setting DTR", __FUNCTION__, port->number);
+			} else {
+				dbg("%s - port %d Clearing DTR", __FUNCTION__, port->number);
+			} 
+			result = usb_control_msg( port->serial->dev, 
+						  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+						  SUSBCRequest_SetStatusLinesOrQueues,
+						  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+						  ( ((mask & TIOCM_DTR) != 0) ? SUSBCR_SSL_SETDTR : SUSBCR_SSL_CLRDTR),
+						  0,
+						  NULL,
+						  0,
+						  KOBIL_TIMEOUT
+				);
+			
+		} else {
+			if ((mask & TIOCM_RTS) != 0){
+				dbg("%s - port %d Setting RTS", __FUNCTION__, port->number);
+			} else {
+				dbg("%s - port %d Clearing RTS", __FUNCTION__, port->number);
+			}
+			result = usb_control_msg( port->serial->dev, 
+						  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+						  SUSBCRequest_SetStatusLinesOrQueues,
+						  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+						  (((mask & TIOCM_RTS) != 0) ? SUSBCR_SSL_SETRTS : SUSBCR_SSL_CLRRTS),
+						  0,
+						  NULL,
+						  0,
+						  KOBIL_TIMEOUT
+				);
+		}
+		dbg("%s - port %d Send set_status_line (TIOCMSET) URB returns: %i", __FUNCTION__, port->number, result);
+		return ((result < 0) ? -EFAULT : 0);
+	}
+	return 0;
+}
+
+
+static int __init kobil_init (void)
+{
+	usb_serial_register (&kobil_device);
+
+	info(DRIVER_VERSION " " DRIVER_AUTHOR);
+	info(DRIVER_DESC);
+
+	return 0;
+}
+
+
+static void __exit kobil_exit (void)
+{
+	usb_serial_deregister (&kobil_device);
+}
+
+module_init(kobil_init);
+module_exit(kobil_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE( "GPL" );
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/kobil_sct.h linux-2.4.21/drivers/usb/serial/kobil_sct.h
--- linux-2.4.20/drivers/usb/serial/kobil_sct.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/drivers/usb/serial/kobil_sct.h	2002-12-18 18:58:08.000000000 +0000
@@ -0,0 +1,60 @@
+#define SUSBCRequest_SetBaudRateParityAndStopBits       1
+#define SUSBCR_SBR_MASK				0xFF00
+#define SUSBCR_SBR_1200				0x0100
+#define SUSBCR_SBR_9600				0x0200
+#define SUSBCR_SBR_19200			0x0400
+#define SUSBCR_SBR_28800			0x0800
+#define SUSBCR_SBR_38400			0x1000
+#define SUSBCR_SBR_57600			0x2000
+#define SUSBCR_SBR_115200			0x4000
+
+#define SUSBCR_SPASB_MASK			0x0070
+#define SUSBCR_SPASB_NoParity			0x0010
+#define SUSBCR_SPASB_OddParity			0x0020
+#define SUSBCR_SPASB_EvenParity			0x0040
+
+#define SUSBCR_SPASB_STPMASK			0x0003
+#define SUSBCR_SPASB_1StopBit			0x0001
+#define SUSBCR_SPASB_2StopBits			0x0002
+
+#define SUSBCRequest_SetStatusLinesOrQueues	2
+#define SUSBCR_SSL_SETRTS			0x0001
+#define SUSBCR_SSL_CLRRTS			0x0002
+#define SUSBCR_SSL_SETDTR			0x0004
+#define SUSBCR_SSL_CLRDTR			0x0010
+
+#define SUSBCR_SSL_PURGE_TXABORT		0x0100  // Kill the pending/current writes to the comm port.
+#define SUSBCR_SSL_PURGE_RXABORT		0x0200  // Kill the pending/current reads to the comm port.
+#define SUSBCR_SSL_PURGE_TXCLEAR		0x0400  // Kill the transmit queue if there.
+#define SUSBCR_SSL_PURGE_RXCLEAR		0x0800  // Kill the typeahead buffer if there.
+
+#define SUSBCRequest_GetStatusLineState		4
+#define SUSBCR_GSL_RXCHAR			0x0001  // Any Character received
+#define SUSBCR_GSL_TXEMPTY			0x0004  // Transmitt Queue Empty
+#define SUSBCR_GSL_CTS				0x0008  // CTS changed state
+#define SUSBCR_GSL_DSR				0x0010  // DSR changed state
+#define SUSBCR_GSL_RLSD				0x0020  // RLSD changed state
+#define SUSBCR_GSL_BREAK			0x0040  // BREAK received
+#define SUSBCR_GSL_ERR				0x0080  // Line status error occurred
+#define SUSBCR_GSL_RING				0x0100  // Ring signal detected
+
+#define SUSBCRequest_Misc			8
+#define SUSBCR_MSC_ResetReader			0x0001	// use a predefined reset sequence
+#define SUSBCR_MSC_ResetAllQueues	        0x0002	// use a predefined sequence to reset the internal queues
+
+#define SUSBCRequest_GetMisc			0x10
+#define SUSBCR_MSC_GetFWVersion			0x0001	/* get the firmware version from device,
+							   coded like this 0xHHLLBBPP
+							   with HH = Firmware Version High Byte
+							   LL = Firmware Version Low Byte
+							   BB = Build Number
+							   PP = Further Attributes
+							*/
+
+#define SUSBCR_MSC_GetHWVersion			0x0002	/* get the hardware version from device
+							   coded like this 0xHHLLPPRR
+							   with HH = Software Version High Byte
+							   LL = Software Version Low Byte
+							   PP = Further Attributes
+							   RR = Reserved for the hardware ID 
+							*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/pl2303.c linux-2.4.21/drivers/usb/serial/pl2303.c
--- linux-2.4.20/drivers/usb/serial/pl2303.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/serial/pl2303.c	2002-12-18 18:58:08.000000000 +0000
@@ -69,6 +69,7 @@
 	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
 	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
 	{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
+	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
 	{ }					/* Terminating entry */
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/pl2303.h linux-2.4.21/drivers/usb/serial/pl2303.h
--- linux-2.4.20/drivers/usb/serial/pl2303.h	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/serial/pl2303.h	2002-12-18 18:58:09.000000000 +0000
@@ -25,3 +25,6 @@
 
 #define MA620_VENDOR_ID		0x0df7
 #define MA620_PRODUCT_ID	0x0620
+
+#define RATOC_VENDOR_ID		0x0584
+#define RATOC_PRODUCT_ID	0xb000
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/visor.c linux-2.4.21/drivers/usb/serial/visor.c
--- linux-2.4.20/drivers/usb/serial/visor.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/serial/visor.c	2002-12-18 18:58:06.000000000 +0000
@@ -174,11 +174,14 @@
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) },
+	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID) },
 	{ }					/* Terminating entry */
 };
 
@@ -195,11 +198,14 @@
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) },
+	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID) },
 	{ }					/* Terminating entry */
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/visor.h linux-2.4.21/drivers/usb/serial/visor.h
--- linux-2.4.20/drivers/usb/serial/visor.h	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/serial/visor.h	2002-12-18 18:58:05.000000000 +0000
@@ -27,6 +27,8 @@
 #define PALM_I705_ID			0x0020
 #define PALM_M125_ID			0x0040
 #define PALM_M130_ID			0x0050
+#define PALM_TUNGSTEN_T_ID		0x0060
+#define PALM_TUNGSTEN_Z_ID		0x0031
 #define PALM_ZIRE_ID			0x0070
 
 #define SONY_VENDOR_ID			0x054C
@@ -34,6 +36,7 @@
 #define SONY_CLIE_4_0_ID		0x0066
 #define SONY_CLIE_S360_ID		0x0095
 #define SONY_CLIE_4_1_ID		0x009A
+#define SONY_CLIE_NX60_ID		0x00DA
 
 /****************************************************************************
  * Handspring Visor Vendor specific request codes (bRequest values)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/storage/unusual_devs.h linux-2.4.21/drivers/usb/storage/unusual_devs.h
--- linux-2.4.20/drivers/usb/storage/unusual_devs.h	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/storage/unusual_devs.h	2002-12-18 18:58:04.000000000 +0000
@@ -207,9 +207,9 @@
 		US_FL_FIX_INQUIRY | US_FL_START_STOP ),
 
 /* This entry is needed because the device reports Sub=ff */
-UNUSUAL_DEV(  0x054c, 0x0010, 0x0106, 0x0422, 
+UNUSUAL_DEV(  0x054c, 0x0010, 0x0106, 0x0440, 
 		"Sony",
-		"DSC-S30/S70/S75/505V/F505/F707", 
+		"DSC-S30/S70/S75/505V/F505/F707/F717", 
 		US_SC_SCSI, US_PR_CB, NULL,
 		US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ),
 
@@ -487,6 +487,18 @@
 		US_FL_MODE_XLATE ),
 #endif
 
+/* Datafab KECF-USB / Sagatek DCS-CF / Simpletech Flashlink UCF-100
+ * Only revision 1.13 tested (same for all of the above devices,
+ * based on the Datafab DF-UG-07 chip).  Needed for US_FL_FIX_INQUIRY.
+ * Submitted by Marek Michalkiewicz <marekm@amelek.gda.pl>.
+ * See also http://martin.wilck.bei.t-online.de/#kecf .
+ */
+UNUSUAL_DEV(  0x07c4, 0xa400, 0x0000, 0xffff,
+		"Datafab",
+		"KECF-USB",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_FIX_INQUIRY ),
+
 /* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant
  * to the USB storage specification in two ways:
  * - They tell us they are using transport protocol CBI. In reality they
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/tiglusb.c linux-2.4.21/drivers/usb/tiglusb.c
--- linux-2.4.20/drivers/usb/tiglusb.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/tiglusb.c	2002-12-18 18:58:10.000000000 +0000
@@ -14,17 +14,11 @@
  * and the website at:  http://lpg.ticalc.org/prj_usb/
  * for more info.
  *
- * History :
- *  16/07/2002 : v1.04 -- Julien BLACHE <jb@jblache.org>
- *    + removed useless usblp_cleanup()
- *    + removed {un,}lock_kernel() as suggested on lkml
- *    + inlined clear_pipes() (used once)
- *    + inlined clear_device() (small, used twice)
- *    + removed tiglusb_find_struct() (used once, simple code)
- *    + replaced down() with down_interruptible() wherever possible
- *    + fixed double unregistering wrt devfs, causing devfs
- *      to force an oops when the device is deconnected
- *    + removed unused fields from struct tiglusb_t
+ *   1.0x, Romain & Julien: initial submit.
+ *   1.03, Greg Kroah: modifications.
+ *   1.04, Julien: clean-up & fixes; Romain: 2.4 backport.
+ *   1.05, Randy Dunlap: bug fix with the timeout parameter (divide-by-zero).
+ *   1.06, Romain: synched with 2.5, version/firmware changed (confusing).
  */
 
 #include <linux/module.h>
@@ -44,7 +38,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "1.04"
+#define DRIVER_VERSION "1.06"
 #define DRIVER_AUTHOR  "Romain Lievin <roms@lpg.ticalc.org> & Julien Blache <jb@jblache.org>"
 #define DRIVER_DESC    "TI-GRAPH LINK USB (aka SilverLink) driver"
 #define DRIVER_LICENSE "GPL"
@@ -185,7 +179,7 @@
 
 	pipe = usb_rcvbulkpipe (s->dev, 1);
 	result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_read,
-			       &bytes_read, HZ / (timeout / 10));
+			       &bytes_read, HZ * 10 / timeout);
 	if (result == -ETIMEDOUT) {	/* NAK */
 		ret = result;
 		if (!bytes_read) {
@@ -242,7 +236,7 @@
 
 	pipe = usb_sndbulkpipe (s->dev, 2);
 	result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_write,
-			       &bytes_written, HZ / (timeout / 10));
+			       &bytes_written, HZ * 10 / timeout);
 
 	if (result == -ETIMEDOUT) {	/* NAK */
 		warn ("tiglusb_write, NAK received.");
@@ -315,6 +309,7 @@
 /* ----- kernel module registering ------------------------------------ */
 
 static struct file_operations tiglusb_fops = {
+	.owner =        THIS_MODULE,
 	.llseek =	no_llseek,
 	.read =		tiglusb_read,
 	.write =	tiglusb_write,
@@ -385,7 +380,7 @@
 			    &tiglusb_fops, NULL);
 
 	/* Display firmware version */
-	info ("link cable version %i.%02x",
+	info ("firmware revision %i.%02x",
 		dev->descriptor.bcdDevice >> 8,
 		dev->descriptor.bcdDevice & 0xff);
 
@@ -424,6 +419,7 @@
 MODULE_DEVICE_TABLE (usb, tiglusb_ids);
 
 static struct usb_driver tiglusb_driver = {
+	.owner =        THIS_MODULE,
 	.name =		"tiglusb",
 	.probe =	tiglusb_probe,
 	.disconnect =	tiglusb_disconnect,
@@ -446,6 +442,8 @@
 	if (ints[0] > 0) {
 		timeout = ints[1];
 	}
+	if (!timeout)
+		timeout = TIMAXTIME;
 
 	return 1;
 }
@@ -468,9 +466,11 @@
 		init_waitqueue_head (&s->wait);
 		init_waitqueue_head (&s->remove_ok);
 	}
+	if (timeout <= 0)
+               timeout = TIMAXTIME;
 
 	/* register device */
-	if (devfs_register_chrdev (TIUSB_MAJOR, "tiglusb", &tiglusb_fops)) {
+	if (register_chrdev (TIUSB_MAJOR, "tiglusb", &tiglusb_fops)) {
 		err ("unable to get major %d", TIUSB_MAJOR);
 		return -EIO;
 	}
@@ -481,11 +481,17 @@
 	/* register USB module */
 	result = usb_register (&tiglusb_driver);
 	if (result < 0) {
-		devfs_unregister_chrdev (TIUSB_MAJOR, "tiglusb");
+		unregister_chrdev (TIUSB_MAJOR, "tiglusb");
 		return -1;
 	}
 
-	info (DRIVER_DESC ", " DRIVER_VERSION);
+	info (DRIVER_DESC ", version " DRIVER_VERSION);
+
+       if (timeout <= 0)
+               timeout = TIMAXTIME;
+
+	if (!timeout)
+		timeout = TIMAXTIME;
 
 	return 0;
 }
@@ -495,7 +501,7 @@
 {
 	usb_deregister (&tiglusb_driver);
 	devfs_unregister (devfs_handle);
-	devfs_unregister_chrdev (TIUSB_MAJOR, "tiglusb");
+	unregister_chrdev (TIUSB_MAJOR, "tiglusb");
 }
 
 /* --------------------------------------------------------------------- */
@@ -509,6 +515,6 @@
 MODULE_LICENSE (DRIVER_LICENSE);
 
 MODULE_PARM (timeout, "i");
-MODULE_PARM_DESC (timeout, "Timeout (default=1.5 seconds)");
+MODULE_PARM_DESC (timeout, "Timeout in tenths of seconds (default=1.5 seconds)");
 
 /* --------------------------------------------------------------------- */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/uhci.c linux-2.4.21/drivers/usb/uhci.c
--- linux-2.4.20/drivers/usb/uhci.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/uhci.c	2002-12-18 18:58:11.000000000 +0000
@@ -1498,7 +1498,6 @@
 
 	uhci = (struct uhci *)urb->dev->bus->hcpriv;
 
-	INIT_LIST_HEAD(&urb->urb_list);
 	usb_inc_dev_use(urb->dev);
 
 	spin_lock_irqsave(&uhci->urb_list_lock, flags);
@@ -1515,6 +1514,7 @@
 		return ret;
 	}
 
+	INIT_LIST_HEAD(&urb->urb_list);
 	if (!uhci_alloc_urb_priv(uhci, urb)) {
 		ret = -ENOMEM;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/usb-midi.c linux-2.4.21/drivers/usb/usb-midi.c
--- linux-2.4.20/drivers/usb/usb-midi.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/usb-midi.c	2002-12-18 18:58:02.000000000 +0000
@@ -370,7 +370,7 @@
 {
 	struct midi_in_endpoint *ep = (struct midi_in_endpoint *)(urb->context);
 	unsigned char *data = urb->transfer_buffer;
-	int i, l, wake;
+	int i, j, wake;
 	unsigned long int flags;
 
 	if ( !ep->urbSubmitted ) {
@@ -381,14 +381,14 @@
 		wake = 0;
 		spin_lock_irqsave( &ep->lock, flags );
 
-		for(l = 0; l < urb->actual_length; l += 4) {
-			int cin = (data[l]>>0)&0xf;
-			int cab = (data[l]>>4)&0xf;
+		for(j = 0; j < urb->actual_length; j += 4) {
+			int cin = (data[j]>>0)&0xf;
+			int cab = (data[j]>>4)&0xf;
 			struct usb_mididev *cable = ep->cables[cab];
 			if ( cable ) {
 				int len = cin_to_len[cin]; /** length of MIDI data **/
 				for (i = 0; i < len; i++) {
-					cable->min.buf[cable->min.bufWrPtr] = data[1+i];
+					cable->min.buf[cable->min.bufWrPtr] = data[1+i+j];
 					cable->min.bufWrPtr = (cable->min.bufWrPtr+1)%MIDI_IN_BUFSIZ;
 					if (cable->min.bufRemains < MIDI_IN_BUFSIZ)
 						cable->min.bufRemains += 1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/usb-uhci.c linux-2.4.21/drivers/usb/usb-uhci.c
--- linux-2.4.20/drivers/usb/usb-uhci.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/usb-uhci.c	2002-12-18 18:58:08.000000000 +0000
@@ -2514,6 +2514,7 @@
 			}
 			else {
 				uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
+				uhci_clean_iso_step2(s, urb_priv);
 				// correct toggle after unlink
 				usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
 				clr_td_ioc(desc); // inactivate TD
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/usb.c linux-2.4.21/drivers/usb/usb.c
--- linux-2.4.20/drivers/usb/usb.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/usb.c	2002-12-18 18:58:09.000000000 +0000
@@ -1785,17 +1785,17 @@
  * These are the actual routines to send
  * and receive control messages.
  */
-#ifdef CONFIG_USB_LONG_TIMEOUT
-#define GET_TIMEOUT 4
-#else
-#define GET_TIMEOUT 3
-#endif
-#define SET_TIMEOUT 3
+
+/* USB spec identifies 5 second timeouts.
+ * Some devices (MGE Ellipse UPSes, etc) need it, too.
+ */
+#define GET_TIMEOUT 5
+#define SET_TIMEOUT 5
 
 int usb_set_address(struct usb_device *dev)
 {
 	return usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS,
-		0, dev->devnum, 0, NULL, 0, HZ * GET_TIMEOUT);
+		0, dev->devnum, 0, NULL, 0, HZ * SET_TIMEOUT);
 }
 
 int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/usbnet.c linux-2.4.21/drivers/usb/usbnet.c
--- linux-2.4.20/drivers/usb/usbnet.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/usbnet.c	2002-12-18 18:58:01.000000000 +0000
@@ -1,6 +1,21 @@
 /*
  * USB Host-to-Host Links
  * Copyright (C) 2000-2002 by David Brownell <dbrownell@users.sourceforge.net>
+ * Copyright (C) 2002 Pavel Machek <pavel@ucw.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 /*
@@ -18,13 +33,15 @@
  *	- Belkin, eTEK (interops with Win32 drivers)
  *	- EPSON USB clients
  *	- GeneSys GL620USB-A
- *	- "Linux Devices" (like iPaq and similar SA-1100 based PDAs)
  *	- NetChip 1080 (interoperates with NetChip Win32 drivers)
  *	- Prolific PL-2301/2302 (replaces "plusb" driver)
+ *	- PXA-250 or SA-1100 Linux PDAs like iPaq, Yopy, and Zaurus
  *
  * USB devices can implement their side of this protocol at the cost
  * of two bulk endpoints; it's not restricted to "cable" applications.
- * See the LINUXDEV or EPSON device/client support.
+ * See the SA1110, Zaurus, or EPSON device/client support in this driver;
+ * slave/target drivers such as "usb-eth" (on most SA-1100 PDAs) are
+ * used inside USB slave/target devices.
  *
  * 
  * Status:
@@ -37,10 +54,6 @@
  *   handshaking; it'd be worth implementing those as "carrier detect".
  *   Prefer generic hooks, not minidriver-specific hacks.
  *
- * - Linux devices ... the www.handhelds.org SA-1100 support works nicely,
- *   but the Sharp Zaurus uses an incompatible protocol (extra checksums).
- *   No reason not to merge the Zaurus protocol here too (got patch? :)
- *
  * - For Netchip, should use keventd to poll via control requests to detect
  *   hardware level "carrier detect". 
  *
@@ -48,11 +61,15 @@
  *   sheets, sometimes it's not needed and sometimes it hangs.  Prolific has
  *   not responded to repeated support/information requests.
  *
+ * - SA-1100 PDAs ... the standard ARM Linux SA-1100 support works nicely,
+ *   as found in www.handhelds.org and other kernels.  The Sharp/Lineo
+ *   kernels use different drivers, which also talk to this code.
+ *
  * Interop with more Win32 drivers may be a good thing.
  *
  * Seems like reporting "peer connected" (carrier present) events may end
- * up going through the netlink event system, not hotplug ... that may be
- * awkward in terms of automatic configuration though.
+ * up going through the netlink event system, not hotplug ... so new links
+ * would likely be handled with a link monitoring thread in some daemon.
  *
  * There are reports that bridging gives lower-than-usual throughput.
  *
@@ -100,6 +117,10 @@
  * 07-may-2002	Generalize/cleanup keventd support, handling rx stalls (mostly
  *		for USB 2.0 TTs) and memory shortages (potential) too. (db)
  *		Use "locally assigned" IEEE802 address space. (Brad Hards)
+ * 18-oct-2002	Support for Zaurus (Pavel Machek), related cleanup (db).
+ * 15-dec-2002	Partial sync with 2.5 code: cleanups and stubbed PXA-250
+ * 		support (db), fix for framing issues on Z, net1080, and
+ * 		gl620a (Toby Milne)
  *
  *-------------------------------------------------------------------------*/
 
@@ -139,12 +160,13 @@
 #define	CONFIG_USB_BELKIN
 #define	CONFIG_USB_EPSON2888
 #define	CONFIG_USB_GENESYS
-#define	CONFIG_USB_LINUXDEV
 #define	CONFIG_USB_NET1080
 #define	CONFIG_USB_PL2301
+#define	CONFIG_USB_SA1100
+#define	CONFIG_USB_ZAURUS
 
 
-#define DRIVER_VERSION		"17-Jul-2002"
+#define DRIVER_VERSION		"18-Oct-2002"
 
 /*-------------------------------------------------------------------------*/
 
@@ -152,6 +174,8 @@
  * Nineteen USB 1.1 max size bulk transactions per frame (ms), max.
  * Several dozen bytes of IPv4 data can fit in two such transactions.
  * One maximum size Ethernet packet takes twenty four of them.
+ * For high speed, each frame comfortably fits almost 36 max size
+ * Ethernet packets (so queues should be bigger).
  */
 #ifdef REALLY_QUEUE
 #define	RX_QLEN		4
@@ -223,6 +247,7 @@
 	int		flags;
 #define FLAG_FRAMING_NC	0x0001		/* guard against device dropouts */ 
 #define FLAG_FRAMING_GL	0x0002		/* genelink batches packets */
+#define FLAG_FRAMING_Z	0x0004		/* zaurus adds a trailer */
 #define FLAG_NO_SETINT	0x0010		/* device can't set_interface() */
 
 	/* reset device ... can sleep */
@@ -277,6 +302,12 @@
 #define	RUN_CONTEXT (in_irq () ? "in_irq" \
 			: (in_interrupt () ? "in_interrupt" : "can sleep"))
 
+/* mostly for PDA style devices, which are always present */
+static int always_connected (struct usbnet *dev)
+{
+	return 0;
+}
+
 /*-------------------------------------------------------------------------*/
 
 #ifdef DEBUG
@@ -345,7 +376,7 @@
  *
  * EPSON USB clients
  *
- * This is the same idea as "linuxdev" (below) except the firmware in the
+ * This is the same idea as Linux PDAs (below) except the firmware in the
  * device might not be Tux-powered.  Epson provides reference firmware that
  * implements this interface.  Product developers can reuse or modify that
  * code, such as by using their own product and vendor codes.
@@ -354,6 +385,7 @@
 
 static const struct driver_info	epson2888_info = {
 	.description =	"Epson USB Device",
+	.check_connect = always_connected,
 
 	.in = 4, .out = 3,
 	.epsize = 64,
@@ -439,10 +471,28 @@
 {
 	int status = urb->status;
 	
+	switch (status) {
+	case 0:
+		/* success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		dbg("%s - urb shutting down with status: %d",
+				__FUNCTION__, status);
+		return;
+	default:
+		dbg("%s - nonzero urb status received: %d",
+				__FUNCTION__, urb->status);
+	}
+
+	// NOTE:  2.4 still has automagic resubmit, so this would be
+	// wrong ... but this code has never worked, is always disabled.
+	status = usb_submit_urb (urb, GFP_ATOMIC);
 	if (status)
-		dbg ("gl_interrupt_complete fail - %X", status);
-	else
-		dbg ("gl_interrupt_complete success...");
+		err ("%s - usb_submit_urb failed with result %d",
+		     __FUNCTION__, status);
 }
 
 static int gl_interrupt_read (struct usbnet *dev)
@@ -508,7 +558,7 @@
 	}
 
 	// fill irq urb
-	FILL_INT_URB (priv->irq_urb, dev->udev,
+	usb_fill_int_urb (priv->irq_urb, dev->udev,
 		usb_rcvintpipe (dev->udev, GENELINK_INTERRUPT_PIPE),
 		priv->irq_buf, INTERRUPT_BUFSIZE,
 		gl_interrupt_complete, 0,
@@ -682,34 +732,6 @@
 
 
 
-#ifdef	CONFIG_USB_LINUXDEV
-
-/*-------------------------------------------------------------------------
- *
- * This could talk to a device that uses Linux, such as a PDA or
- * an embedded system, or in fact to any "smart" device using this
- * particular mapping of USB and Ethernet.
- *
- * Such a Linux host would need a "USB Device Controller" hardware
- * (not "USB Host Controller"), and a network driver talking to that
- * hardware.
- *
- * One example is Intel's SA-1100 chip, which integrates basic USB
- * support (arch/arm/sa1100/usb-eth.c); it's used in the iPaq PDA.
- * And others too, like the Yopy.
- *
- *-------------------------------------------------------------------------*/
-
-static const struct driver_info	linuxdev_info = {
-	.description =	"Linux Device",
-
-	.in = 2, .out = 1,
-	.epsize = 64,
-};
-
-#endif	/* CONFIG_USB_LINUXDEV */
-
-
 #ifdef	CONFIG_USB_NET1080
 
 /*-------------------------------------------------------------------------
@@ -1228,6 +1250,178 @@
 
 
 
+#ifdef	CONFIG_USB_PXA
+
+/*-------------------------------------------------------------------------
+ *
+ * PXA250 and PXA210 use XScale cores (ARM v5TE) with better USB support,
+ * and different USB endpoint numbering than the SA1100 devices.
+ *
+ *-------------------------------------------------------------------------*/
+
+static const struct driver_info	pxa_info = {
+	.description =	"PXA-250 Linux Device",
+	.check_connect = always_connected,
+
+	.in = 1, .out = 2,
+	.epsize = 64,
+};
+
+#endif	/* CONFIG_USB_PXA */
+
+
+
+#ifdef	CONFIG_USB_SA1100
+
+/*-------------------------------------------------------------------------
+ *
+ * Intel's SA-1100 chip integrates basic USB support, and is used
+ * in PDAs like some iPaqs, the Yopy, some Zaurus models, and more.
+ * When they run Linux, arch/arm/mach-sa1100/usb-eth.c may be used to
+ * network using minimal USB framing data.
+ *
+ * This describes the driver currently in standard ARM Linux kernels.
+ * The Zaurus uses a different driver (see later).
+ *
+ *-------------------------------------------------------------------------*/
+
+static const struct driver_info	linuxdev_info = {
+	.description =	"SA-1100 Linux Device",
+	.check_connect = always_connected,
+
+	.in = 2, .out = 1,
+	.epsize = 64,
+};
+
+static const struct driver_info	yopy_info = {
+	.description =	"Yopy",
+	.check_connect = always_connected,
+
+	.in = 2, .out = 1,
+	.epsize = 64,
+};
+
+#endif	/* CONFIG_USB_SA1100 */
+
+
+#ifdef CONFIG_USB_ZAURUS
+
+/*-------------------------------------------------------------------------
+ *
+ * Zaurus is also a SA-1110 based PDA, but one using a different driver
+ * (and framing) for its USB slave/gadget controller than the case above.
+ *
+ * For the current version of that driver, the main way that framing is
+ * nonstandard (also from perspective of the CDC ethernet model!) is a
+ * crc32, added to help detect when some sa1100 usb-to-memory DMA errata
+ * haven't been fully worked around.
+ *
+ *-------------------------------------------------------------------------*/
+
+// NOTE: so far on 2.4 <linux/crc32.h> isn't for "bulk data" like this.
+// On 2.5 crc32_le() handles this for us.
+
+static const u32 crc32_table [256] = {
+    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+    0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+    0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+    0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+    0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+    0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+    0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+    0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+    0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+    0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+    0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+    0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+    0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+    0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+    0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+    0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+    0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+    0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+#define CRC32_INITFCS     0xffffffff  // Initial FCS value 
+#define CRC32_FCS(fcs, c) (((fcs) >> 8) ^ crc32_table[((fcs) ^ (c)) & 0xff])
+
+/* fcs_compute32 - memcpy and calculate fcs
+ * Perform a memcpy and calculate fcs using ppp 32bit CRC algorithm.
+ */
+static inline u32 fcs_compute32 (unsigned char *sp, int len, u32 fcs)
+{
+	for (;len-- > 0; fcs = CRC32_FCS (fcs, *sp++))
+		continue;
+	return fcs;
+}
+
+static struct sk_buff *
+zaurus_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags)
+{
+	int			padlen;
+	struct sk_buff		*skb2;
+
+	padlen = 2;
+	if (!skb_cloned (skb)) {
+		int	tailroom = skb_tailroom (skb);
+		if ((padlen + 4) <= tailroom)
+			goto done;
+	}
+	skb2 = skb_copy_expand (skb, 0, 4 + padlen, flags);
+	dev_kfree_skb_any (skb);
+	skb = skb2;
+	if (skb) {
+		u32		fcs;
+done:
+		fcs = fcs_compute32 (skb->data, skb->len, CRC32_INITFCS);
+		fcs = ~fcs;
+
+		*skb_put (skb, 1) = fcs       & 0xff;
+		*skb_put (skb, 1) = (fcs>> 8) & 0xff;
+		*skb_put (skb, 1) = (fcs>>16) & 0xff;
+		*skb_put (skb, 1) = (fcs>>24) & 0xff;
+	}
+	return skb;
+}
+
+static const struct driver_info	zaurus_sl5x00_info = {
+	.description =	"Sharp Zaurus SL-5x00",
+	.flags =	FLAG_FRAMING_Z,
+	.check_connect = always_connected,
+	.tx_fixup = 	zaurus_tx_fixup,
+
+	.in = 2, .out = 1,
+	.epsize = 64,
+};
+static const struct driver_info	zaurus_sla300_info = {
+	.description =	"Sharp Zaurus SL-A300",
+	.flags =	FLAG_FRAMING_Z,
+	.check_connect = always_connected,
+	.tx_fixup = 	zaurus_tx_fixup,
+
+	.in = 1, .out = 2,
+	.epsize = 64,
+};
+
+// SL-5600 and C-700 are PXA based; should resemble A300
+
+#endif
+
+
 /*-------------------------------------------------------------------------
  *
  * Network Device Driver (peer link to "Host Device", from USB host)
@@ -1267,7 +1461,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* urb completions are currently in_irq; avoid doing real work then. */
+/* urb completions may be in_irq; avoid doing real work then. */
 
 static void defer_bh (struct usbnet *dev, struct sk_buff *skb)
 {
@@ -1321,6 +1515,11 @@
 		size = GL_RCV_BUF_SIZE;
 	else
 #endif
+#ifdef CONFIG_USB_ZAURUS
+	if (dev->driver_info->flags & FLAG_FRAMING_Z)
+		size = 6 + (sizeof (struct ethhdr) + dev->net.mtu);
+	else
+#endif
 		size = (sizeof (struct ethhdr) + dev->net.mtu);
 
 	if ((skb = alloc_skb (size, flags)) == 0) {
@@ -1336,15 +1535,10 @@
 	entry->state = rx_start;
 	entry->length = 0;
 
-	FILL_BULK_URB (urb, dev->udev,
+	usb_fill_bulk_urb (urb, dev->udev,
 		usb_rcvbulkpipe (dev->udev, dev->driver_info->in),
 		skb->data, size, rx_complete, skb);
 	urb->transfer_flags |= USB_ASYNC_UNLINK;
-#if 0
-	// Idle-but-posted reads with UHCI really chew up
-	// PCI bandwidth unless FSBR is disabled
-	urb->transfer_flags |= USB_NO_FSBR;
-#endif
 
 	spin_lock_irqsave (&dev->rxq.lock, lockflags);
 
@@ -1388,8 +1582,6 @@
 	if (skb->len) {
 		int	status;
 
-// FIXME: eth_copy_and_csum "small" packets to new SKB (small < ~200 bytes) ?
-
 		skb->dev = &dev->net;
 		skb->protocol = eth_type_trans (skb, &dev->net);
 		dev->stats.rx_packets++;
@@ -1662,7 +1854,7 @@
 	/* could also map RINGPARAM to RX/TX QLEN */
 
 	}
-        /* Note that the ethtool user space code requires EOPNOTSUPP */
+	/* Note that the ethtool user space code requires EOPNOTSUPP */
 	return -EOPNOTSUPP;
 }
 
@@ -1768,7 +1960,7 @@
 static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
 {
 	struct usbnet		*dev = (struct usbnet *) net->priv;
-	int			length = skb->len;
+	int			length;
 	int			retval = NET_XMIT_SUCCESS;
 	struct urb		*urb = 0;
 	struct skb_data		*entry;
@@ -1788,6 +1980,7 @@
 			goto drop;
 		}
 	}
+	length = skb->len;
 
 	if (!(urb = ALLOC_URB (0, GFP_ATOMIC))) {
 		dbg ("no urb");
@@ -1802,6 +1995,7 @@
 
 	// FIXME: reorganize a bit, so that fixup() fills out NetChip
 	// framing too. (Packet ID update needs the spinlock...)
+	// [ BETTER:  we already own net->xmit_lock, that's enough ]
 
 #ifdef	CONFIG_USB_NET1080
 	if (info->flags & FLAG_FRAMING_NC) {
@@ -1818,11 +2012,10 @@
 	if ((length % EP_SIZE (dev)) == 0)
 		skb->len++;
 
-	FILL_BULK_URB (urb, dev->udev,
+	usb_fill_bulk_urb (urb, dev->udev,
 			usb_sndbulkpipe (dev->udev, info->out),
 			skb->data, skb->len, tx_complete, skb);
 	urb->transfer_flags |= USB_ASYNC_UNLINK;
-	// FIXME urb->timeout = ... jiffies ... ;
 
 	spin_lock_irqsave (&dev->txq.lock, flags);
 
@@ -1982,21 +2175,26 @@
 {
 	struct usbnet			*dev;
 	struct net_device 		*net;
-	struct usb_interface_descriptor	*interface;
 	struct driver_info		*info;
 	int				altnum = 0;
 
 	info = (struct driver_info *) prod->driver_info;
 
-	// sanity check; expect dedicated interface/devices for now.
-	interface = &udev->actconfig->interface [ifnum].altsetting [altnum];
-	if (udev->descriptor.bNumConfigurations != 1
-			|| udev->config[0].bNumInterfaces != 1
-//			|| interface->bInterfaceClass != USB_CLASS_VENDOR_SPEC
-			) {
-		dbg ("Bogus config info");
-		return 0;
+#ifdef CONFIG_USB_ZAURUS
+	if (info == &zaurus_sl5x00_info) {
+		int	status;
+
+		/* old ROMs have more than one config
+		 * so we have to make sure config="1" (?)
+		 */
+		status = usb_set_configuration (udev, 1);
+		if (status < 0) {
+			err ("set_config failed, %d", status);
+			return 0;
+		}
+		altnum = 1;
 	}
+#endif
 
 	// more sanity (unless the device is broken)
 	if (!(info->flags & FLAG_NO_SETINT)) {
@@ -2099,7 +2297,7 @@
 #ifdef	CONFIG_USB_EPSON2888
 {
 	USB_DEVICE (0x0525, 0x2888),	// EPSON USB client
-	driver_info:	(unsigned long) &epson2888_info,
+	.driver_info	= (unsigned long) &epson2888_info,
 },
 #endif
 
@@ -2113,23 +2311,6 @@
 	 */
 #endif
 
-#ifdef	CONFIG_USB_LINUXDEV
-/*
- * for example, this can be a host side talk-to-PDA driver.
- * this driver is NOT what runs _inside_ a Linux device !!
- */
-{
-	// 1183 = 0x049F, both used as hex values?
-	USB_DEVICE (0x049F, 0x505A),	// Compaq "Itsy"
-	.driver_info =	(unsigned long) &linuxdev_info,
-}, {
-	USB_DEVICE (0x0E7E, 0x1001),	// G.Mate "Yopy"
-	.driver_info =	(unsigned long) &linuxdev_info,
-},
-	// NOTE:  the Sharp Zaurus uses a modified version of
-	// this driver, which is not interoperable with this.
-#endif
-
 #ifdef	CONFIG_USB_NET1080
 {
 	USB_DEVICE (0x0525, 0x1080),	// NetChip ref design
@@ -2150,7 +2331,61 @@
 },
 #endif
 
-/* KC2190 from www.sepoong.co.kr "InstaNET" */
+#ifdef	CONFIG_USB_PXA
+/*
+ * PXA250 or PXA210 ...  these use a "usb-eth" driver much like
+ * the sa1100 one.
+ */
+{
+	// Compaq "Itsy" vendor/product id, version "2.0"
+	USB_DEVICE_VER (0x049F, 0x505A, 0x0200, 0x0200),
+	.driver_info =	(unsigned long) &pxa_info,
+}, 
+#endif
+
+#ifdef	CONFIG_USB_SA1100
+/*
+ * SA-1100 using standard ARM Linux kernels, or compatible.
+ * Often used when talking to Linux PDAs (iPaq, Yopy, etc).
+ * The sa-1100 "usb-eth" driver handles the basic framing.
+ */
+{
+	// 1183 = 0x049F, both used as hex values?
+	// Compaq "Itsy" vendor/product id, version "0.0"
+	USB_DEVICE_VER (0x049F, 0x505A, 0, 0),
+	.driver_info =	(unsigned long) &linuxdev_info,
+}, {
+	USB_DEVICE (0x0E7E, 0x1001),	// G.Mate "Yopy"
+	.driver_info =	(unsigned long) &yopy_info,
+}, 
+#endif
+
+#ifdef	CONFIG_USB_ZAURUS
+/*
+ * SA-1100 based Sharp Zaurus ("collie"), or compatible.
+ * Same idea as above, but different framing.
+ */
+{
+	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
+			  | USB_DEVICE_ID_MATCH_DEVICE, 
+	.idVendor		= 0x04DD,
+	.idProduct		= 0x8004,
+	.bInterfaceClass	= 0x0a,
+	.bInterfaceSubClass	= 0x00,
+	.bInterfaceProtocol	= 0x00,
+	.driver_info =  (unsigned long) &zaurus_sl5x00_info,
+},
+{
+	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
+			  | USB_DEVICE_ID_MATCH_DEVICE, 
+	.idVendor		= 0x04DD,
+	.idProduct		= 0x8005,
+	.bInterfaceClass	= 0x02,
+	.bInterfaceSubClass	= 0x0a,
+	.bInterfaceProtocol	= 0x00,
+	.driver_info =  (unsigned long) &zaurus_sla300_info,
+},
+#endif
 
 	{ },		// END
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/vicam.c linux-2.4.21/drivers/usb/vicam.c
--- linux-2.4.20/drivers/usb/vicam.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/vicam.c	2002-12-18 18:58:04.000000000 +0000
@@ -1,649 +1,1022 @@
-/* -*- linux-c -*-
- * USB ViCAM driver
- *
- * Copyright (c) 2001 Christopher L Cheney (ccheney@cheney.cx)
- * Copyright (c) 2001 Pavel Machek (pavel@suse.cz) sponsored by SuSE
- *
- *      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 driver is for the Vista Imaging ViCAM and 3Com HomeConnect USB
- *
- * Thanks to Greg Kroah-Hartman for the USB Skeleton driver
- *
- * TODO:
- *	- find out the ids for the Vista Imaging ViCAM
+/*
+ * USB ViCam WebCam driver
+ * Copyright (c) 2002 Joe Burks (jburks@wavicle.org)
  *
- * History:
+ * Supports 3COM HomeConnect PC Digital WebCam
  *
- * 2001_07_07 - 0.1 - christopher: first version
- * 2001_08_28 - 0.2 - pavel: messed it up, but for some fun, try 
- 			while true; do dd if=/dev/video of=/dev/fb0 bs=$[0x1e480] count=1 2> /dev/null; done
-		      yep, moving pictures.
- * 2001_08_29 - 0.3 - pavel: played a little bit more. Experimental mmap support. For some fun,
- 			get gqcam-0.9, compile it and run. Better than dd ;-).
- * 2001_08_29 - 0.4 - pavel: added shutter speed control (not much functional)
- 			kill update_params if it does not seem to work for you.
- * 2001_08_30 - 0.5 - pavel: fixed stupid bug with update_params & vicam_bulk
-
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * FIXME: It crashes on rmmod with camera plugged.
- */
-#define DEBUG 1
+ * This source code is based heavily on the CPiA webcam driver
+ * */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/fcntl.h>
+#include <linux/wrapper.h>
 #include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/smp_lock.h>
-#include <linux/devfs_fs_kernel.h>
+#include <linux/init.h>
+#include <linux/videodev.h>
 #include <linux/usb.h>
-
-#include <asm/io.h>
-#include <linux/wrapper.h>
 #include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include "usbvideo.h"
 
-#include <linux/videodev.h>
+// #define VICAM_DEBUG
+
+#ifndef MODULE_LICENSE
+#define MODULE_LICENSE(a)
+#endif
+
+#ifndef bool
+#define bool int
+#endif
 
-#include "vicam.h"
-#include "vicamurbs.h"
+#ifdef VICAM_DEBUG
+#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args)
+#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
+#else
+#define DBG(fmn,args...) do {} while(0)
+#endif
 
 /* Version Information */
-#define DRIVER_VERSION "v0"
-#define DRIVER_AUTHOR "Christopher L Cheney <ccheney@cheney.cx>, Pavel Machek <pavel@suse.cz>"
-#define DRIVER_DESC "USB ViCAM Driver"
+#define DRIVER_VERSION "v1.0"
+#define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org"
+#define DRIVER_DESC "ViCam WebCam Driver"
 
 /* Define these values to match your device */
-#define USB_VICAM_VENDOR_ID	0x04C1
-#define USB_VICAM_PRODUCT_ID	0x009D
+#define USB_VICAM_VENDOR_ID	0x04c1
+#define USB_VICAM_PRODUCT_ID	0x009d
 
-/* table of devices that work with this driver */
-static struct usb_device_id vicam_table [] = {
-	{ USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID) },
-	{ }					/* Terminating entry */
+#define VICAM_BYTES_PER_PIXEL 3
+#define VICAM_MAX_READ_SIZE (512*242+128)
+#define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240)
+#define VICAM_FRAMES 2
+
+/* Not sure what all the bytes in these char
+ * arrays do, but they're necessary to make
+ * the camera work.
+ */
+
+static unsigned char setup1[] = {
+	0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67,
+	0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00,
+	0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17,
+	0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00,
+	0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
 };
 
-MODULE_DEVICE_TABLE (usb, vicam_table);
+static unsigned char setup2[] = {
+	0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
+	0x00, 0x00
+};
 
-static int video_nr = -1; 		/* next avail video device */
-static struct usb_driver vicam_driver;
+static unsigned char setup3[] = {
+	0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
+};
 
-static char *buf, *buf2;
-static volatile int change_pending = 0; 
+static unsigned char setup4[] = {
+	0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07,
+	0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00,
+	0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00,
+	0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07,
+	0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00,
+	0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00,
+	0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07,
+	0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF,
+	0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0,
+	0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07,
+	0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00,
+	0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0,
+	0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1,
+	0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09,
+	0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00,
+	0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF,
+	0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02,
+	0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00,
+	0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF,
+	0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00,
+	0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00,
+	0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05,
+	0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA,
+	0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06,
+	0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF,
+	0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05,
+	0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01,
+	0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09,
+	0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06,
+	0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05,
+	0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA,
+	0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05,
+	0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
+	0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00,
+	0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF,
+	0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00,
+	0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0,
+	0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06,
+	0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00,
+	0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07,
+	0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF,
+	0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00,
+	0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
+	0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57,
+	0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57,
+	0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00,
+	0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0,
+	0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B,
+	0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06,
+	0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06,
+	0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E,
+	0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00,
+	0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05,
+	0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00,
+	0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
+	0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF,
+	0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0,
+	0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
+	0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05,
+	0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF,
+	0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0,
+	0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07,
+	0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07,
+	0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF,
+	0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF,
+	0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
+	0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
+	0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1,
+	0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
+	0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00,
+	0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07,
+	0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07,
+	0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07,
+	0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00,
+	0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06,
+	0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67,
+	0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8,
+	0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0,
+	0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF,
+	0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02,
+	0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
+	0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06,
+	0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05,
+	0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
+	0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00,
+	0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06,
+	0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
+	0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05,
+	0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05,
+	0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
+	0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04,
+	0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF,
+	0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06,
+	0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+	0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00,
+	0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05,
+	0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07,
+	0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07,
+	0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07,
+	0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF,
+	0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07,
+	0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06,
+	0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05,
+	0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07,
+	0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00,
+	0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00,
+	0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77,
+	0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04,
+	0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0,
+	0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1,
+	0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07,
+	0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF,
+	0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
+	0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
+	0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
+	0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77,
+	0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1,
+	0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07,
+	0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF,
+	0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06,
+	0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
+	0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07,
+	0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07,
+	0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00,
+	0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00,
+	0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+	0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
+	0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F,
+	0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00,
+	0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00,
+	0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA,
+	0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
+	0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06,
+	0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF,
+	0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B,
+	0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+	0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09,
+	0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05,
+	0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07,
+	0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00,
+	0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF,
+	0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05,
+	0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00,
+	0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00,
+	0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05,
+	0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05,
+	0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00,
+	0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF,
+	0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09,
+	0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+	0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1,
+	0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00,
+	0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+	0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00,
+	0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00,
+	0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+	0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0,
+	0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67,
+	0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87,
+	0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9,
+	0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1,
+	0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF,
+	0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00,
+	0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0,
+	0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87,
+	0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
+	0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67,
+	0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
+	0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
+	0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67,
+	0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
+	0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
+	0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
+	0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00,
+	0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF,
+	0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
+	0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
+	0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09,
+	0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
+	0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA,
+	0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87,
+	0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
+	0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
+	0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
+	0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
+	0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02,
+	0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09,
+	0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+	0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
 
-static int vicam_parameters(struct usb_vicam *vicam);
+static unsigned char setup5[] = {
+	0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00,
+	0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00,
+	0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00,
+	0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00,
+	0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00,
+	0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00,
+	0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00,
+	0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01,
+	0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01,
+	0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01,
+	0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01,
+	0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01,
+	0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01,
+	0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01,
+	0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01,
+	0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02,
+	0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02,
+	0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02,
+	0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02,
+	0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02,
+	0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02,
+	0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02,
+	0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02,
+	0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03,
+	0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03,
+	0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03,
+	0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03,
+	0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03,
+	0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03,
+	0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03,
+	0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04,
+	0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04,
+	0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04,
+	0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04,
+	0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04,
+	0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04,
+	0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04,
+	0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05,
+	0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
+};
 
-/******************************************************************************
- *
- *  Memory management functions
- *
- *  Taken from bttv-drivers.c 2.4.7-pre3
- *
- ******************************************************************************/
+struct vicam_camera {
+	u16 shutter_speed;	// capture shutter speed
+	u16 gain;		// capture gain
 
-/* Here we want the physical address of the memory.
- * This is used when initializing the contents of the area.
- */
-static inline unsigned long kvirt_to_pa(unsigned long adr)
-{
-	unsigned long kva, ret;
+	u8 *raw_image;		// raw data captured from the camera
+	u8 *framebuf;		// processed data in RGB24 format
 
-	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
-	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
-	ret = __pa(kva);
-	return ret;
-}
+	struct video_device vdev;	// v4l video device
+	struct usb_device *udev;	// usb device
 
-static void * rvmalloc(unsigned long size)
-{
-	void * mem;
-	unsigned long adr;
+	struct semaphore busy_lock;	// guard against SMP multithreading
 
-	size=PAGE_ALIGN(size);
-	mem=vmalloc_32(size);
-	if (mem)
-	{
-		memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-		adr=(unsigned long) mem;
-		while (size > 0)
-		{
-			mem_map_reserve(vmalloc_to_page((void *)adr));
-			adr+=PAGE_SIZE;
-			size-=PAGE_SIZE;
-		}
-	}
-	return mem;
-}
+	bool is_initialized;
+	u8 open_count;
+	u8 bulkEndpoint;
+	bool needsDummyRead;
 
-static void rvfree(void * mem, unsigned long size)
-{
-	unsigned long adr;
+	u32 framebuf_size;	// # of valid bytes in framebuf
+	u32 framebuf_read_start;	// position in frame buf that a read is happening at.
 
-	if (mem)
-	{
-		adr=(unsigned long) mem;
-		while ((long) size > 0)
-		{
-			mem_map_unreserve(vmalloc_to_page((void *)adr));
-			adr+=PAGE_SIZE;
-			size-=PAGE_SIZE;
-		}
-		vfree(mem);
-	}
-}
-
-/******************************************************************************
- *
- *  Foo Bar
- *
- ******************************************************************************/
-
-/**
- *	usb_vicam_debug_data
- */
-static inline void usb_vicam_debug_data (const char *function, int size, const unsigned char *data)
-{
-	int i;
-
-	if (!debug)
-		return;
-
-	printk (KERN_DEBUG __FILE__": %s - length = %d, data = ",
-		function, size);
-	for (i = 0; i < size; ++i) {
-		printk ("%.2x ", data[i]);
-	}
-	printk ("\n");
-}
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *proc_entry;
+#endif
 
-/*****************************************************************************
- *
- *  Send command to vicam
- *
- *****************************************************************************/
+};
 
-static int vicam_sndctrl(int set, struct usb_vicam *vicam, unsigned short req,
-	unsigned short value, unsigned char *cp, int size)
-{
-	int ret;
-	unsigned char *transfer_buffer = kmalloc (size, GFP_KERNEL);
+static void *vicam_probe(struct usb_device *dev, unsigned int ifnum,
+			       const struct usb_device_id *id);
+static void vicam_disconnect(struct usb_device *dev, void *ptr);
+static void read_frame(struct vicam_camera *cam, int framenum);
+
+static int
+send_control_msg(struct usb_device *udev, u8 request, u16 value, u16 index,
+		 unsigned char *cp, u16 size)
+{
+	int status;
+
+	// for reasons not yet known to me, you can't send USB control messages
+	// with data in the module (if you are compiled as a module).  Whatever
+	// the reason, copying it to memory allocated as kernel memory then
+	// doing the usb control message fixes the problem.
 
-	/* Needs to return data I think, works for sending though */
+	unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL);
 	memcpy(transfer_buffer, cp, size);
-	
-	ret = usb_control_msg ( vicam->udev, set ? usb_sndctrlpipe(vicam->udev, 0) : usb_rcvctrlpipe(vicam->udev, 0), req, (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, 0, transfer_buffer, size, HZ);
+
+	status = usb_control_msg(udev,
+				 usb_sndctrlpipe(udev, 0),
+				 request,
+				 USB_DIR_OUT | USB_TYPE_VENDOR |
+				 USB_RECIP_DEVICE, value, index,
+				 transfer_buffer, size, HZ);
 
 	kfree(transfer_buffer);
-	if (ret)
-		printk("vicam: error: %d\n", ret);
-	mdelay(100);
-	return ret;
-}
 
-
-/*****************************************************************************
- *
- *  Video4Linux Helpers
- * 
- *****************************************************************************/
-
-static int vicam_get_capability(struct usb_vicam *vicam, struct video_capability *b)
-{
-	dbg("vicam_get_capability");
-
-	strcpy(b->name, vicam->camera_name);
-	b->type = VID_TYPE_CAPTURE | VID_TYPE_MONOCHROME;
-	b->channels = 1;
-	b->audios = 0;
-
-	b->maxwidth = vicam->width[vicam->sizes-1];
-	b->maxheight = vicam->height[vicam->sizes-1];
-	b->minwidth = vicam->width[0];
-	b->minheight = vicam->height[0];
+	if (status < 0) {
+		printk(KERN_INFO "Failed sending control message, error %d.\n",
+		       status);
+	}
+
+	return status;
+}
+
+static int
+initialize_camera(struct vicam_camera *cam)
+{
+	struct usb_device *udev = cam->udev;
+	int status;
+
+	if ((status =
+	     send_control_msg(udev, 0xff, 0, 0, setup1, sizeof (setup1))) < 0)
+		return status;
+	if ((status =
+	     send_control_msg(udev, 0xff, 0, 0, setup2, sizeof (setup2))) < 0)
+		return status;
+	if ((status =
+	     send_control_msg(udev, 0xff, 0, 0, setup3, sizeof (setup3))) < 0)
+		return status;
+	if ((status =
+	     send_control_msg(udev, 0xff, 0, 0, setup4, sizeof (setup4))) < 0)
+		return status;
+	if ((status =
+	     send_control_msg(udev, 0xff, 0, 0, setup5, sizeof (setup5))) < 0)
+		return status;
+	if ((status =
+	     send_control_msg(udev, 0xff, 0, 0, setup3, sizeof (setup3))) < 0)
+		return status;
 
 	return 0;
 }
-		
-static int vicam_get_channel(struct usb_vicam *vicam, struct video_channel *v)
+
+static int
+set_camera_power(struct vicam_camera *cam, int state)
 {
-	dbg("vicam_get_channel");
+	int status;
 
-	if (v->channel != 0)
-		return -EINVAL;
- 
-	v->flags = 0;
-	v->tuners = 0;
-	v->type = VIDEO_TYPE_CAMERA;
-	strcpy(v->name, "Camera");
+	if ((status = send_control_msg(cam->udev, 0x50, state, 0, NULL, 0)) < 0)
+		return status;
 
-	return 0;
-} 
-		
-static int vicam_set_channel(struct usb_vicam *vicam, struct video_channel *v)
-{
-	dbg("vicam_set_channel");
+	if (state) {
+		send_control_msg(cam->udev, 0x55, 1, 0, NULL, 0);
+	}
 
-	if (v->channel != 0)
-		return -EINVAL;
-	
 	return 0;
 }
-		
-static int vicam_get_mmapbuffer(struct usb_vicam *vicam, struct video_mbuf *vm)
-{
-	int i;
 
-	dbg("vicam_get_mmapbuffer");
+static int
+vicam_ioctl(struct video_device *dev, unsigned int ioctlnr, void *arg)
+{
+	struct vicam_camera *cam = dev->priv;
+	int retval = 0;
 
-	memset(vm, 0, sizeof(vm));
-	vm->size = VICAM_NUMFRAMES * vicam->maxframesize;
-	vm->frames = VICAM_NUMFRAMES;
+	if (!cam)
+		return -ENODEV;
 
-	for (i=0; i<VICAM_NUMFRAMES; i++)
-		vm->offsets[i] = vicam->maxframesize * i;
+	/* make this _really_ smp-safe */
+	if (down_interruptible(&cam->busy_lock))
+		return -EINTR;
 
-	return 0;
-}
+	switch (ioctlnr) {
+		/* query capabilites */
+	case VIDIOCGCAP:
+		{
+			struct video_capability b;
 
-static int vicam_get_picture(struct usb_vicam *vicam, struct video_picture *p)
-{
-	dbg("vicam_get_picture");
+			DBG("VIDIOCGCAP\n");
+			strcpy(b.name, "ViCam-based Camera");
+			b.type = VID_TYPE_CAPTURE;
+			b.channels = 1;
+			b.audios = 0;
+			b.maxwidth = 320;	/* VIDEOSIZE_CIF */
+			b.maxheight = 240;
+			b.minwidth = 320;	/* VIDEOSIZE_48_48 */
+			b.minheight = 240;
 
-	/* This is probably where that weird 0x56 call goes */
-	p->brightness = vicam->win.brightness;
-	p->hue = vicam->win.hue;
-	p->colour = vicam->win.colour;
-	p->contrast = vicam->win.contrast;
-	p->whiteness = vicam->win.whiteness;
-	p->depth = vicam->win.depth;
-	p->palette = vicam->win.palette;
+			if (copy_to_user(arg, &b, sizeof (b)))
+				retval = -EFAULT;
 
-	return 0;
-}
+			break;
+		}
+		/* get/set video source - we are a camera and nothing else */
+	case VIDIOCGCHAN:
+		{
+			struct video_channel v;
 
-static void synchronize(struct usb_vicam *vicam)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	change_pending = 1;
-	set_current_state(TASK_INTERRUPTIBLE);
-	add_wait_queue(&vicam->wait, &wait);
-	if (change_pending)
-		schedule();
-	remove_wait_queue(&vicam->wait, &wait);
-	set_current_state(TASK_RUNNING);
-	vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0);
-	mdelay(10);
-	vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0);
-	mdelay(10);
-}
-
-static void params_changed(struct usb_vicam *vicam)
-{
-#if 1
-	synchronize(vicam);
-	mdelay(10);
-	vicam_parameters(vicam);
-	printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb));
-#endif
-}
+			DBG("VIDIOCGCHAN\n");
+			if (copy_from_user(&v, arg, sizeof (v))) {
+				retval = -EFAULT;
+				break;
+			}
+			if (v.channel != 0) {
+				retval = -EINVAL;
+				break;
+			}
+
+			v.channel = 0;
+			strcpy(v.name, "Camera");
+			v.tuners = 0;
+			v.flags = 0;
+			v.type = VIDEO_TYPE_CAMERA;
+			v.norm = 0;
+
+			if (copy_to_user(arg, &v, sizeof (v)))
+				retval = -EFAULT;
+			break;
+		}
 
-static int vicam_set_picture(struct usb_vicam *vicam, struct video_picture *p)
-{
-	int changed = 0;
-	info("vicam_set_picture (%d)", p->brightness);
+	case VIDIOCSCHAN:
+		{
+			int v;
 
+			if (copy_from_user(&v, arg, sizeof (v)))
+				retval = -EFAULT;
+			DBG("VIDIOCSCHAN %d\n", v);
 
-#define SET(x) \
-	if (vicam->win.x != p->x) \
-		vicam->win.x = p->x, changed = 1;
-	SET(brightness);
-	SET(hue);
-	SET(colour);
-	SET(contrast);
-	SET(whiteness);
-	SET(depth);
-	SET(palette);
-	if (changed)
-		params_changed(vicam);
+			if (retval == 0 && v != 0)
+				retval = -EINVAL;
 
-	return 0;
-	/* Investigate what should be done maybe 0x56 type call */
-	if (p->depth != 8) return 1;
-	if (p->palette != VIDEO_PALETTE_GREY) return 1;
+			break;
+		}
 
-	return 0;
-}
+		/* image properties */
+	case VIDIOCGPICT:
+		{
+			struct video_picture vp;
+			DBG("VIDIOCGPICT\n");
+			memset(&vp, 0, sizeof (struct video_picture));
+			vp.brightness = cam->gain << 8;
+			vp.depth = 24;
+			vp.palette = VIDEO_PALETTE_RGB24;
+			if (copy_to_user
+			    (arg, &vp, sizeof (struct video_picture)))
+				retval = -EFAULT;
+			break;
+		}
 
-/* FIXME - vicam_sync_frame - important */
-static int vicam_sync_frame(struct usb_vicam *vicam, int frame)
-{
-	dbg("vicam_sync_frame");
+	case VIDIOCSPICT:
+		{
+			struct video_picture *vp = (struct video_picture *) arg;
 
-	if(frame <0 || frame >= VICAM_NUMFRAMES)
-		return -EINVAL;
+			DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp->depth,
+			    vp->palette);
 
-	/* Probably need to handle various cases */
-/*	ret=vicam_newframe(vicam, frame);
-	vicam->frame[frame].grabstate=FRAME_UNUSED;
-*/
-	return 0;
-}
-	
-static int vicam_get_window(struct usb_vicam *vicam, struct video_window *vw)
-{
-	dbg("vicam_get_window");
+			cam->gain = vp->brightness >> 8;
 
-	vw->x = 0;
-	vw->y = 0;
-	vw->chromakey = 0;
-	vw->flags = 0;
-	vw->clipcount = 0;
-	vw->width = vicam->win.width;
-	vw->height = vicam->win.height;
+			if (vp->depth != 24
+			    || vp->palette != VIDEO_PALETTE_RGB24)
+				retval = -EINVAL;
 
-	return 0;
-}
+			break;
+		}
 
-static int vicam_set_window(struct usb_vicam *vicam, struct video_window *vw)
-{
-	info("vicam_set_window");
-		
-	if (vw->flags)
-		return -EINVAL;
-	if (vw->clipcount)
-		return -EINVAL;
+		/* get/set capture window */
+	case VIDIOCGWIN:
+		{
+			struct video_window vw;
+			vw.x = 0;
+			vw.y = 0;
+			vw.width = 320;
+			vw.height = 240;
+			vw.chromakey = 0;
+			vw.flags = 0;
+			vw.clips = NULL;
+			vw.clipcount = 0;
+
+			DBG("VIDIOCGWIN\n");
+
+			if (copy_to_user
+			    ((void *) arg, (void *) &vw, sizeof (vw)))
+				retval = -EFAULT;
+
+			// I'm not sure what the deal with a capture window is, it is very poorly described
+			// in the doc.  So I won't support it now.
+			break;
+		}
 
-	if (vicam->win.width == vw->width && vicam->win.height == vw->height)
-		return 0;
+	case VIDIOCSWIN:
+		{
 
-	/* Pick largest mode that is smaller than specified res */
-	/* If specified res is too small reject                 */
+			struct video_window *vw = (struct video_window *) arg;
+			DBG("VIDIOCSWIN %d x %d\n", vw->width, vw->height);
 
-	/* Add urb send to device... */
+			if ( vw->width != 320 || vw->height != 240 )
+				retval = -EFAULT;
+			
+			break;
+		}
 
-	vicam->win.width = vw->width;
-	vicam->win.height = vw->height;
-	params_changed(vicam);
+		/* mmap interface */
+	case VIDIOCGMBUF:
+		{
+			struct video_mbuf vm;
+			int i;
 
-	return 0;
-}
+			DBG("VIDIOCGMBUF\n");
+			memset(&vm, 0, sizeof (vm));
+			vm.size =
+			    VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
+			vm.frames = VICAM_FRAMES;
+			for (i = 0; i < VICAM_FRAMES; i++)
+				vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
+
+			if (copy_to_user
+			    ((void *) arg, (void *) &vm, sizeof (vm)))
+				retval = -EFAULT;
 
-/* FIXME - vicam_mmap_capture - important */
-static int vicam_mmap_capture(struct usb_vicam *vicam, struct video_mmap *vm)
-{
-	dbg("vicam_mmap_capture");
+			break;
+		}
 
-	/* usbvideo.c looks good for using here */
+	case VIDIOCMCAPTURE:
+		{
+			struct video_mmap vm;
+			// int video_size;
 
-	/* 
-	if (vm->frame >= VICAM_NUMFRAMES)
-		return -EINVAL;
-	if (vicam->frame[vm->frame].grabstate != FRAME_UNUSED)
-		return -EBUSY;
-	vicam->frame[vm->frame].grabstate=FRAME_READY;
-	*/
+			if (copy_from_user
+			    ((void *) &vm, (void *) arg, sizeof (vm))) {
+				retval = -EFAULT;
+				break;
+			}
+
+			DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
+
+			if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
+				retval = -EINVAL;
+
+			// in theory right here we'd start the image capturing
+			// (fill in a bulk urb and submit it asynchronously)
+			//
+			// Instead we're going to do a total hack job for now and
+			// retrieve the frame in VIDIOCSYNC
 
-	/* No need to vicam_set_window here according to Alan */
+			break;
+		}
 
-	/*
-	if (!vicam->streaming)
-		vicam_start_stream(vicam);
-	*/
+	case VIDIOCSYNC:
+		{
+			int frame;
 
-	/* set frame as ready */
+			if (copy_from_user((void *) &frame, arg, sizeof (int))) {
+				retval = -EFAULT;
+				break;
+			}
+			DBG("VIDIOCSYNC: %d\n", frame);
 
-	return 0;
-}
+			read_frame(cam, frame);
 
-/*****************************************************************************
- *
- *  Video4Linux
- * 
- *****************************************************************************/
+			break;
+		}
 
-static int vicam_v4l_open(struct video_device *vdev, int flags)
-{
-	struct usb_vicam *vicam = (struct usb_vicam *)vdev;
-	int err = 0;
-	
-	dbg("vicam_v4l_open");
+		/* pointless to implement overlay with this camera */
+	case VIDIOCCAPTURE:
+	case VIDIOCGFBUF:
+	case VIDIOCSFBUF:
+	case VIDIOCKEY:
+		retval = -EINVAL;
+		break;
 
-	MOD_INC_USE_COUNT; 
-	down(&vicam->sem);
+		/* tuner interface - we have none */
+	case VIDIOCGTUNER:
+	case VIDIOCSTUNER:
+	case VIDIOCGFREQ:
+	case VIDIOCSFREQ:
+		retval = -EINVAL;
+		break;
 
-	if (vicam->open_count)		/* Maybe not needed? */
-		err = -EBUSY;
-	else {
-		vicam->fbuf = rvmalloc(vicam->maxframesize * VICAM_NUMFRAMES);
-		if (!vicam->fbuf)
-			err=-ENOMEM;
-		else {
-			vicam->open_count = 1;
-		}
-#ifdef BLINKING
-		vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0);
-		info ("led on");
-		vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0);
-#endif
+		/* audio interface - we have none */
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
+		retval = -EINVAL;
+		break;
+	default:
+		retval = -ENOIOCTLCMD;
+		break;
 	}
 
-	up(&vicam->sem);
-	if (err)
-		MOD_DEC_USE_COUNT;
-	return err;
+	up(&cam->busy_lock);
+	return retval;
 }
 
-static void vicam_v4l_close(struct video_device *vdev)
+static int
+vicam_open(struct video_device *dev, int flags)
 {
-	struct usb_vicam *vicam = (struct usb_vicam *)vdev;
+	struct vicam_camera *cam =
+	    (struct vicam_camera *) dev->priv;
+	DBG("open\n");
 
-	dbg("vicam_v4l_close");
-	
-	down(&vicam->sem);
+	if (!cam) {
+		printk(KERN_ERR
+		       "vicam video_device improperly initialized");
+	}
 
-#ifdef BLINKING
-	info ("led off");
-	vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0);
-//	vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); Leave it on
-#endif
+	down_interruptible(&cam->busy_lock);
+
+	if (cam->open_count > 0) {
+		printk(KERN_INFO
+		       "vicam_open called on already opened camera");
+		up(&cam->busy_lock);
+		return -EBUSY;
+	}
+
+	if (!cam->raw_image) {
+		cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
+		if (!cam->raw_image) {
+			up(&cam->busy_lock);
+			return -ENOMEM;
+		}
+	}
+
+	if (!cam->framebuf) {
+		cam->framebuf =
+		    usbvideo_rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
+		if (!cam->framebuf) {
+			kfree(cam->raw_image);
+			up(&cam->busy_lock);
+			return -ENOMEM;
+		}
+	}
+	// First upload firmware, then turn the camera on
 
-	rvfree(vicam->fbuf, vicam->maxframesize * VICAM_NUMFRAMES);
-	vicam->fbuf = 0;
-	vicam->open_count=0;
+	if (!cam->is_initialized) {
+		initialize_camera(cam);
 
-	up(&vicam->sem);
-	/* Why does se401.c have a usbdevice check here? */
-	/* If device is unplugged while open, I guess we only may unregister now */
-	MOD_DEC_USE_COUNT;
+		cam->is_initialized = 1;
+	}
+
+	set_camera_power(cam, 1);
+
+	cam->needsDummyRead = 1;
+	cam->open_count++;
+
+	up(&cam->busy_lock);
+
+	return 0;
 }
 
-static long vicam_v4l_read(struct video_device *vdev, char *user_buf, unsigned long buflen, int noblock)
+static void
+vicam_close(struct video_device *dev)
 {
-	//struct usb_vicam *vicam = (struct usb_vicam *)vdev;
+	DBG("close\n");
+	set_camera_power((struct vicam_camera *) dev->priv, 0);
 
-	dbg("vicam_v4l_read(%ld)", buflen);
+	((struct vicam_camera *) dev->priv)->open_count--;
+}
 
-	if (!vdev || !buf)
-		return -EFAULT;
-	
-	if(buflen > 0x1e480)
-		buflen = 0x1e480;
-	if (copy_to_user(user_buf, buf2, buflen))
-		return -EFAULT;
-	return buflen;
+inline int pin(int x)
+{
+	return((x > 255) ? 255 : ((x < 0) ? 0 : x));
 }
 
-static long vicam_v4l_write(struct video_device *dev, const char *buf, unsigned long count, int noblock)
+inline void writepixel(char *rgb, int Y, int Cr, int Cb)
 {
-	info("vicam_v4l_write");
-	return -EINVAL;
+	Y = 1160 * (Y - 16);
+	
+	rgb[2] = pin( ( ( Y + ( 1594 * Cr ) ) + 500 ) / 1300 );
+	rgb[1] = pin( ( ( Y - (  392 * Cb ) - ( 813 * Cr ) ) + 500 ) / 1000 );
+	rgb[0] = pin( ( ( Y + ( 2017 * Cb ) ) + 500 ) / 900 );
 }
 
-static int vicam_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
+#define DATA_HEADER_SIZE 64
+
+// --------------------------------------------------------------------------------
+//	vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
+//
+//   Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
+// --------------------------------------------------------------------------------
+
+void vicam_decode_color( char *data, char *rgb)
 {
-	struct usb_vicam *vicam = (struct usb_vicam *)vdev;
-	int ret = -EL3RST;
+	int x,y;
+	int Cr, Cb;
+	int sign;
+	int prevX, nextX, prevY, nextY;
+	int skip;
+	unsigned char *src;
+	unsigned char *dst;
 
-	if (!vicam->udev)
-		return -EIO;
+	prevY = 512;
+	nextY = 512;
 
-	down(&vicam->sem);
+	src = data + DATA_HEADER_SIZE;
+	dst = rgb;
 
-	switch (cmd) {
-	case VIDIOCGCAP:
-	{
-		struct video_capability b;
-		ret = vicam_get_capability(vicam,&b);
-		dbg("name %s",b.name);
-		if (copy_to_user(arg, &b, sizeof(b)))
-			ret = -EFAULT;
-	}
-	case VIDIOCGFBUF:
+	for(y = 1; y < 241; y += 2)
 	{
-		struct video_buffer vb;
-		info("vicam_v4l_ioctl - VIDIOCGBUF - query frame buffer param");
-		/* frame buffer not supported, not used */
-		memset(&vb, 0, sizeof(vb));
-		vb.base = NULL;
+		// even line
+		sign = 1;
+		prevX = 1;
+		nextX = 1;
+
+		skip = 0;
+
+		dst = rgb + (y-1)*320*3;
 		
-		/* FIXME - VIDIOCGFBUF - why the void */
-		if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
-			ret = -EFAULT;
-		ret = 0;
-	}
-	case VIDIOCGWIN:
-	{
-		struct video_window vw;
-		ret = vicam_get_window(vicam, &vw);
-		if (copy_to_user(arg, &vw, sizeof(vw)))
-			ret = -EFAULT;
-	}
-	case VIDIOCSWIN:
-	{
-		struct video_window vw;
-		if (copy_from_user(&vw, arg, sizeof(vw)))
-			ret = -EFAULT;
-		else
-			ret = vicam_set_window(vicam, &vw);
-		return ret;
-	}
-	case VIDIOCGCHAN:
-	{
-		struct video_channel v;
+		for(x = 0; x < 512; x++)
+		{
+			if(x == 512-1)
+				nextX = -1;
 
-		if (copy_from_user(&v, arg, sizeof(v)))
-			ret = -EFAULT;
-		else {
-			ret = vicam_get_channel(vicam,&v);
-			if (copy_to_user(arg, &v, sizeof(v)))
-				ret = -EFAULT;
+			Cr = sign * ((src[prevX] - src[0]) + (src[nextX] - src[0])) >> 1;
+			Cb = sign * ((src[prevY] - src[prevX + prevY]) + (src[prevY] - src[nextX + prevY]) + (src[nextY] - src[prevX + nextY]) + (src[nextY] - src[nextX + nextY])) >> 2;
+
+			writepixel(
+					dst + ((x*5)>>3)*3,
+					src[0] + (sign * (Cr >> 1)),
+					Cr,
+					Cb);
+
+			src++;
+			sign *= -1;
+			prevX = -1;
+		}
+
+		prevY = -512;
+
+		if(y == (242 - 2))
+			nextY = -512;
+
+		// odd line
+		sign = 1;
+		prevX = 1;
+		nextX = 1;
+
+		skip = 0;
+
+		dst = rgb + (y)*320*3;
+		
+		for(x = 0; x < 512; x++)
+		{
+			if(x == 512-1)
+				nextX = -1;
+			
+			Cr = sign * ((src[prevX + prevY] - src[prevY]) + (src[nextX + prevY] - src[prevY]) + (src[prevX + nextY] - src[nextY]) + (src[nextX + nextY] - src[nextY])) >> 2;
+			Cb = sign * ((src[0] - src[prevX]) + (src[0] - src[nextX])) >> 1;
+
+			writepixel(
+					dst + ((x * 5)>>3)*3,
+					src[0] - (sign * (Cb >> 1)),
+					Cr,
+					Cb);
+
+			src++;
+			sign *= -1;
+			prevX = -1;
 		}
 	}
-	case VIDIOCSCHAN:
-	{
-		struct video_channel v;
-		if (copy_from_user(&v, arg, sizeof(v)))
-			ret = -EFAULT;
-		else
-			ret = vicam_set_channel(vicam,&v);
- 	}
-	case VIDIOCGPICT:
-	{
-		struct video_picture p;
-		ret = vicam_get_picture(vicam, &p);
-		if (copy_to_user(arg, &p, sizeof(p)))
-			ret = -EFAULT;
-	}
-	case VIDIOCSPICT:
-	{
-		struct video_picture p;
-		if (copy_from_user(&p, arg, sizeof(p)))
-			ret = -EFAULT;
-		else
-			ret = vicam_set_picture(vicam, &p);
-	}
-	case VIDIOCGMBUF:
-	{
-		struct video_mbuf vm;
-		ret = vicam_get_mmapbuffer(vicam,&vm);
-		/* FIXME - VIDIOCGMBUF - why the void */
-		if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
-			ret = -EFAULT;
+}
+
+static void
+read_frame(struct vicam_camera *cam, int framenum)
+{
+	unsigned char request[16];
+	int realShutter;
+	int n;
+	int actual_length;
+
+	memset(request, 0, 16);
+	request[0] = cam->gain;	// 0 = 0% gain, FF = 100% gain
+
+	request[1] = 0;	// 512x242 capture
+
+	request[2] = 0x90;	// the function of these two bytes
+	request[3] = 0x07;	// is not yet understood
+
+	if (cam->shutter_speed > 60) {
+		// Short exposure
+		realShutter =
+		    ((-15631900 / cam->shutter_speed) + 260533) / 1000;
+		request[4] = realShutter & 0xFF;
+		request[5] = (realShutter >> 8) & 0xFF;
+		request[6] = 0x03;
+		request[7] = 0x01;
+	} else {
+		// Long exposure
+		realShutter = 15600 / cam->shutter_speed - 1;
+		request[4] = 0;
+		request[5] = 0;
+		request[6] = realShutter & 0xFF;
+		request[7] = realShutter >> 8;
+	}
+
+	// Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
+	request[8] = 0;
+	// bytes 9-15 do not seem to affect exposure or image quality
+
+	n = send_control_msg(cam->udev, 0x51, 0x80, 0, request, 16);
+
+	if (n < 0) {
+		printk(KERN_ERR
+		       " Problem sending frame capture control message");
+		return;
 	}
-	case VIDIOCMCAPTURE:
-	{
-		struct video_mmap vm;
-		ret = vicam_mmap_capture(vicam, &vm);
-		/* FIXME: This is probably not right */
+
+	n = usb_bulk_msg(cam->udev,
+			 usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
+			 cam->raw_image,
+			 512 * 242 + 128, &actual_length, 500);
+
+	if (n < 0) {
+		printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
+		       n);
 	}
-	case VIDIOCSYNC:
-	{
-		int frame;
-		/* FIXME - VIDIOCSYNC - why the void */
-		if (copy_from_user((void *)&frame, arg, sizeof(int)))
-			ret = -EFAULT;
-		else
-			ret = vicam_sync_frame(vicam,frame);
+
+	vicam_decode_color(cam->raw_image,
+			 cam->framebuf +
+			 framenum * VICAM_MAX_FRAME_SIZE );
+
+	cam->framebuf_size =
+	    320 * 240 * VICAM_BYTES_PER_PIXEL;
+	cam->framebuf_read_start = 0;
+
+	return;
+
+}
+
+static long
+vicam_read(struct video_device *dev, char *buf,
+		 unsigned long count, int noblock)
+{
+	struct vicam_camera *cam = dev->priv;
+	DBG("read %d bytes.\n", (int) count);
+
+	if (!buf)
+		return -EINVAL;
+
+	if (!count)
+		return -EINVAL;
+
+	// This is some code that will hopefully allow us to do shell copies from
+	// the /dev/videoX to a file and have it actually work.
+	if (cam->framebuf_size != 0) {
+		if (cam->framebuf_read_start == cam->framebuf_size) {
+			cam->framebuf_size = cam->framebuf_read_start = 0;
+			return 0;
+		} else {
+			if (cam->framebuf_read_start + count <=
+			    cam->framebuf_size) {
+				// count does not exceed available bytes
+				copy_to_user(buf,
+					     (cam->framebuf) +
+					     cam->framebuf_read_start, count);
+				cam->framebuf_read_start += count;
+				return count;
+			} else {
+				count =
+				    cam->framebuf_size -
+				    cam->framebuf_read_start;
+				copy_to_user(buf,
+					     (cam->framebuf) +
+					     cam->framebuf_read_start, count);
+				cam->framebuf_read_start = cam->framebuf_size;
+				return count;
+			}
+		}
 	}
 
-	case VIDIOCKEY:
-		ret = 0;
- 
-	case VIDIOCCAPTURE:
-	case VIDIOCSFBUF:
-	case VIDIOCGTUNER:
-	case VIDIOCSTUNER:
-	case VIDIOCGFREQ:
-	case VIDIOCSFREQ:
-	case VIDIOCGAUDIO:
-	case VIDIOCSAUDIO:
-	case VIDIOCGUNIT:
-		ret = -EINVAL;
+	down_interruptible(&cam->busy_lock);
 
-	default:
-	{
-		info("vicam_v4l_ioctl - %ui",cmd);
-		ret = -ENOIOCTLCMD;
+	if (cam->needsDummyRead) {
+		read_frame(cam, 0);
+		cam->needsDummyRead = 0;
 	}
-	} /* end switch */
+	// read_frame twice because the camera doesn't seem to take the shutter speed for the first one.
+
+	read_frame(cam, 0);
 
-	up(&vicam->sem);
-        return ret;
+	if (count > cam->framebuf_size)
+		count = cam->framebuf_size;
+
+	copy_to_user(buf, cam->framebuf, count);
+
+	if (count != cam->framebuf_size)
+		cam->framebuf_read_start = count;
+	else
+		cam->framebuf_size = 0;
+
+	up(&cam->busy_lock);
+
+	return count;
 }
 
-static int vicam_v4l_mmap(struct video_device *dev, const char *adr, unsigned long size)
+static int
+vicam_mmap(struct video_device *dev, const char *adr, unsigned long size)
 {
-	struct usb_vicam *vicam = (struct usb_vicam *)dev;
-	unsigned long start = (unsigned long)adr;
+	// TODO: allocate the raw frame buffer if necessary
+	unsigned long start = (unsigned long) adr;
 	unsigned long page, pos;
+	struct vicam_camera *cam = dev->priv;
 
-	down(&vicam->sem);
-	
-	if (vicam->udev == NULL) {
-		up(&vicam->sem);
-		return -EIO;
-	}
-#if 0
-	if (size > (((VICAM_NUMFRAMES * vicam->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
-		up(&vicam->sem);
-		return -EINVAL;
+	if (!cam)
+		return -ENODEV;
+
+	DBG("vicam_mmap: %ld\n", size);
+
+	/* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
+	 * to the size the application requested for mmap and it was screwing apps up.
+	 if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
+	 return -EINVAL;
+	 */
+
+	/* make this _really_ smp-safe */
+	if (down_interruptible(&cam->busy_lock))
+		return -EINTR;
+
+	if (!cam->framebuf) {	/* we do lazy allocation */
+		cam->framebuf =
+		    usbvideo_rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
+		if (!cam->framebuf) {
+			up(&cam->busy_lock);
+			return -ENOMEM;
+		}
 	}
-#endif
-	pos = (unsigned long)vicam->fbuf;
+
+	pos = (unsigned long) (cam->framebuf);
 	while (size > 0) {
-		page = kvirt_to_pa(pos);
+		page = usbvideo_kvirt_to_pa(pos);
 		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
-			up(&vicam->sem);
+			up(&cam->busy_lock);
 			return -EAGAIN;
 		}
 		start += PAGE_SIZE;
@@ -653,288 +1026,316 @@
 		else
 			size = 0;
 	}
-	up(&vicam->sem);
 
-        return 0;
+	up(&cam->busy_lock);
+
+	return 0;
 }
 
-/* FIXME - vicam_v4l_init */
-static int vicam_v4l_init(struct video_device *dev)
+#ifdef CONFIG_PROC_FS
+
+static struct proc_dir_entry *vicam_proc_root = NULL;
+
+static int
+vicam_read_proc(char *page, char **start, off_t off,
+		      int count, int *eof, void *data)
 {
-	/* stick proc fs stuff in here if wanted */
-	dbg("vicam_v4l_init");
-	return 0;
+	char *out = page;
+	int len;
+	struct vicam_camera *cam = (struct vicam_camera *) data;
+
+	out +=
+	    sprintf(out, "Vicam-based WebCam Linux Driver.\n");
+	out += sprintf(out, "(c) 2002 Joe Burks (jburks@wavicle.org)\n");
+	out += sprintf(out, "vicam stats:\n");
+	out += sprintf(out, "    Shutter Speed: 1/%d\n", cam->shutter_speed);
+	out += sprintf(out, "             Gain: %d\n", cam->gain);
+
+	len = out - page;
+	len -= off;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0)
+			return 0;
+	} else
+		len = count;
+
+	*start = page + off;
+	return len;
 }
 
-/* FIXME - vicam_template - important */
-static struct video_device vicam_template = {
-	name:		"vicam USB camera",
-	type:		VID_TYPE_CAPTURE,
-	hardware:	VID_HARDWARE_SE401, /* need to ask for own id */
-	open:		vicam_v4l_open,
-	close:		vicam_v4l_close,
-	read:		vicam_v4l_read,
-	write:		vicam_v4l_write,
-	ioctl:		vicam_v4l_ioctl,
-	mmap:		vicam_v4l_mmap,
-	initialize:	vicam_v4l_init,
-};
+static int
+vicam_write_proc(struct file *file, const char *buffer,
+		       unsigned long count, void *data)
+{
+	char *in;
+	char *start;
+	struct vicam_camera *cam = (struct vicam_camera *) data;
 
-/******************************************************************************
- *
- *  Some Routines
- *
- ******************************************************************************/
+	in = kmalloc(count + 1, GFP_KERNEL);
+	if (!in)
+		return -ENOMEM;
 
-/*
-Flash the led
-vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0);
-info ("led on");
-vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0);
-info ("led off");
-vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0);
-vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0);
-*/
+	in[count] = 0;		// I'm not sure buffer is gauranteed to be null terminated
+	// so I do this to make sure I have a null in there.
+
+	strncpy(in, buffer, count);
 
-static void vicam_bulk(struct urb *urb)
+	start = strstr(in, "gain=");
+	if (start
+	    && (start == in || *(start - 1) == ' ' || *(start - 1) == ','))
+		cam->gain = simple_strtoul(start + 5, NULL, 10);
+
+	start = strstr(in, "shutter=");
+	if (start
+	    && (start == in || *(start - 1) == ' ' || *(start - 1) == ','))
+		cam->shutter_speed = simple_strtoul(start + 8, NULL, 10);
+
+	kfree(in);
+	return count;
+}
+
+void
+vicam_create_proc_root(void)
 {
-	struct usb_vicam *vicam = urb->context;
+	vicam_proc_root = create_proc_entry("video/vicam", S_IFDIR, 0);
 
-	/*	if (!vicam || !vicam->dev || !vicam->used)
-		return;
-	*/
+	if (vicam_proc_root)
+		vicam_proc_root->owner = THIS_MODULE;
+	else
+		printk(KERN_ERR
+		       "could not create /proc entry for vicam!");
+}
 
-	if (urb->status)
-		printk("vicam%d: nonzero read/write bulk status received: %d",
-			0, urb->status);
-
-	urb->actual_length = 0;
-	urb->dev = vicam->udev;
-
-	memcpy(buf2, buf+64, 0x1e480);
-	if (vicam->fbuf)
-		memcpy(vicam->fbuf, buf+64, 0x1e480);
-
-	if (!change_pending) {
-		if (usb_submit_urb(urb))
-			dbg("failed resubmitting read urb");
-	} else {
-		change_pending = 0;
-		wake_up_interruptible(&vicam->wait);
-	}
+void
+vicam_destroy_proc_root(void)
+{
+	if (vicam_proc_root)
+		remove_proc_entry("video/vicam", 0);
 }
 
-static int vicam_parameters(struct usb_vicam *vicam)
+void
+vicam_create_proc_entry(void *ptr)
 {
-	unsigned char req[0x10];
-	unsigned int shutter;
-	shutter = 10;
+	struct vicam_camera *cam = (struct vicam_camera *) ptr;
 
-	switch (vicam->win.width) {
-	case 512:
-	default:
-		memcpy(req, s512x242bw, 0x10);
-		break;
-	case 256:
-		memcpy(req, s256x242bw, 0x10);
-		break;
-	case 128:
-		memcpy(req, s128x122bw, 0x10);
-		break;
+	char name[7];
+	struct proc_dir_entry *ent;
+
+	DBG(KERN_INFO "vicam: creating proc entry\n");
+
+	if (!vicam_proc_root || !cam) {
+		printk(KERN_INFO
+		       "vicam: could not create proc entry, %s pointer is null.\n",
+		       (!cam ? "camera" : "root"));
+		return;
 	}
 
+	sprintf(name, "video%d", cam->vdev.minor);
 
-	mdelay(10);
-	vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0);
-	info ("led on");
-	vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0);
-
-	mdelay(10);
-
-	shutter = vicam->win.contrast / 256;
-	if (shutter == 0)
-		shutter = 1;
-	printk("vicam_parameters: brightness %d, shutter %d\n", vicam->win.brightness, shutter );
-	req[0] = vicam->win.brightness /256;
-	shutter = 15600/shutter - 1;
-	req[6] = shutter & 0xff;
-	req[7] = (shutter >> 8) & 0xff;
-	vicam_sndctrl(1, vicam, VICAM_REQ_CAPTURE, 0x80, req, 0x10);
-	mdelay(10);
-	vicam_sndctrl(0, vicam, VICAM_REQ_GET_SOMETHIN, 0, buf, 0x10);
-	mdelay(10);
+	ent =
+	    create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR,
+			      vicam_proc_root);
+	if (!ent)
+		return;
 
-	return 0;
+	ent->data = cam;
+	ent->read_proc = vicam_read_proc;
+	ent->write_proc = vicam_write_proc;
+	ent->size = 512;
+	cam->proc_entry = ent;
 }
 
-static int vicam_init(struct usb_vicam *vicam)
+void
+vicam_destroy_proc_entry(void *ptr)
 {
-	int width[] = {128, 256, 512};
-	int height[] = {122, 242, 242};
+	struct vicam_camera *cam = (struct vicam_camera *) ptr;
+	char name[7];
+
+	if (!cam || !cam->proc_entry)
+		return;
 
-	dbg("vicam_init");
-	buf = kmalloc(0x1e480, GFP_KERNEL);
-	buf2 = kmalloc(0x1e480, GFP_KERNEL);
-	if ((!buf) || (!buf2)) {
-		printk("Not enough memory for vicam!\n");
-		goto error;
-	}
-
-	/* do we do aspect correction in kernel or not? */
-	vicam->sizes = 3;
-	vicam->width = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL);
-	vicam->height = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL);
-	memcpy(vicam->width, &width, sizeof(width));
-	memcpy(vicam->height, &height, sizeof(height));
-	vicam->maxframesize = vicam->width[vicam->sizes-1] * vicam->height[vicam->sizes-1];
-
-	/* Download firmware to camera */
-	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware1, sizeof(firmware1));
-	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex1, sizeof(findex1));
-	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup));
-	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware2, sizeof(firmware2));
-	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex2, sizeof(findex2));
-	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup));
-
-	vicam_parameters(vicam);
-
-	FILL_BULK_URB(&vicam->readurb, vicam->udev, usb_rcvbulkpipe(vicam->udev, 0x81),
-		      buf, 0x1e480, vicam_bulk, vicam);
-	printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb));
+	sprintf(name, "video%d", cam->vdev.minor);
+	remove_proc_entry(name, vicam_proc_root);
+	cam->proc_entry = NULL;
 
+}
+
+#endif
+
+int
+vicam_video_init(struct video_device *vdev)
+{
+	// This would normally create the proc entry for this camera
+#ifdef CONFIG_PROC_FS
+	vicam_create_proc_entry(vdev->priv);
+#endif
 	return 0;
-error:
-	if (buf)
-		kfree(buf);
-	if (buf2)
-		kfree(buf2);
-	return 1;
 }
 
-static void * vicam_probe(struct usb_device *udev, unsigned int ifnum,
-	const struct usb_device_id *id)
+static long
+vicam_write(struct video_device *v, const char *buf, unsigned long count,
+		  int nonblock)
 {
-	struct usb_vicam *vicam;
-	char *camera_name=NULL;
 
-	dbg("vicam_probe");
+	return -EINVAL;
+}
+
+static struct video_device vicam_template = {
+	owner:THIS_MODULE,
+	name:"ViCam-based USB Camera",
+	type:VID_TYPE_CAPTURE,
+	hardware:VID_HARDWARE_VICAM,
+	open:vicam_open,
+	close:vicam_close,
+	read:vicam_read,
+	write:vicam_write,
+	ioctl:vicam_ioctl,
+	mmap:vicam_mmap,
+	initialize:vicam_video_init,
+	minor:-1,
+};
+
+/* table of devices that work with this driver */
+static struct usb_device_id vicam_table[] = {
+	{USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
+	{}			/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, vicam_table);
+
+static struct usb_driver vicam_driver = {
+	name:"vicam",
+	probe:vicam_probe,
+	disconnect:vicam_disconnect,
+	id_table:vicam_table
+};
+
+/**
+ *	vicam_probe
+ *
+ *	Called by the usb core when a new device is connected that it thinks
+ *	this driver might be interested in.
+ */
+static void *
+vicam_probe(struct usb_device *dev, unsigned int ifnum,
+		  const struct usb_device_id *id)
+{
+	int nas, bulkEndpoint = 0;
+	const struct usb_interface_descriptor *interface;
+	const struct usb_endpoint_descriptor *endpoint;
+	struct vicam_camera *cam;
 
 	/* See if the device offered us matches what we can accept */
-	if ((udev->descriptor.idVendor != USB_VICAM_VENDOR_ID) ||
-	    (udev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) {
+	if ((dev->descriptor.idVendor != USB_VICAM_VENDOR_ID) ||
+	    (dev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) {
 		return NULL;
 	}
-	
-	camera_name="3Com HomeConnect USB";
-	info("ViCAM camera found: %s", camera_name);
-	
-	vicam = kmalloc (sizeof(struct usb_vicam), GFP_KERNEL);
-	if (vicam == NULL) {
-		err ("couldn't kmalloc vicam struct");
+
+	printk(KERN_INFO "ViCam based webcam connected\n");
+
+	nas = dev->actconfig->interface[ifnum].num_altsetting;
+	if (nas != 1) {
+		printk(KERN_WARNING
+		       "Expected only one alternate setting for this camera!\n");
 		return NULL;
 	}
-	memset(vicam, 0, sizeof(*vicam));
-	
-	vicam->udev = udev;
-	vicam->camera_name = camera_name;
-	vicam->win.brightness = 128;
-	vicam->win.contrast = 10;
-
-	/* FIXME */
-	if (vicam_init(vicam)) {
-		kfree(vicam);
-		return NULL;
+
+	interface = &dev->actconfig->interface[ifnum].altsetting[0];
+	DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
+	       ifnum, (unsigned) (interface->bNumEndpoints));
+	endpoint = &interface->endpoint[0];
+
+	if ((endpoint->bEndpointAddress & 0x80) &&
+	    ((endpoint->bmAttributes & 3) == 0x02)) {
+		/* we found a bulk in endpoint */
+		bulkEndpoint = endpoint->bEndpointAddress;
+	} else {
+		printk(KERN_ERR
+		       "No bulk in endpoint was found ?! (this is bad)\n");
 	}
-	memcpy(&vicam->vdev, &vicam_template, sizeof(vicam_template));
-	memcpy(vicam->vdev.name, vicam->camera_name, strlen(vicam->camera_name));
-	
-	if (video_register_device(&vicam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
-		err("video_register_device");
-		kfree(vicam);
+
+	if ((cam =
+	     kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
+		printk(KERN_WARNING
+		       "could not allocate kernel memory for vicam_camera struct\n");
 		return NULL;
 	}
 
-	info("registered new video device: video%d", vicam->vdev.minor);
-	
-	init_MUTEX (&vicam->sem);
-	init_waitqueue_head(&vicam->wait);
-	
-	return vicam;
-}
+	memset(cam, 0, sizeof (struct vicam_camera));
 
+	cam->shutter_speed = 15;
 
-/* FIXME - vicam_disconnect - important */
-static void vicam_disconnect(struct usb_device *udev, void *ptr)
-{
-	struct usb_vicam *vicam;
+	init_MUTEX(&cam->busy_lock);
 
-	vicam = (struct usb_vicam *) ptr;
+	memcpy(&cam->vdev, &vicam_template,
+	       sizeof (vicam_template));
+	cam->vdev.priv = cam;	// sort of a reverse mapping for those functions that get vdev only
 
-	if (!vicam->open_count)
-		video_unregister_device(&vicam->vdev);
-	vicam->udev = NULL;
-/*
-	vicam->frame[0].grabstate = FRAME_ERROR;
-	vicam->frame[1].grabstate = FRAME_ERROR;
-*/
+	cam->udev = dev;
+	cam->bulkEndpoint = bulkEndpoint;
 
-	/* Free buffers and shit */
+	if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
+		kfree(cam);
+		printk(KERN_WARNING "video_register_device failed\n");
+		return NULL;
+	}
 
-	info("%s disconnected", vicam->camera_name);
-	synchronize(vicam);
+	printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
 
-	if (!vicam->open_count) {
-		/* Other random junk */
-		kfree(vicam);
-		vicam = NULL;
-	}
+	return cam;
 }
 
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver vicam_driver = {
-	name:		"vicam",
-	probe:		vicam_probe,
-	disconnect:	vicam_disconnect,
-	id_table:	vicam_table,
-};
-
-/******************************************************************************
- *
- *  Module Routines
- *
- ******************************************************************************/
+static void
+vicam_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct vicam_camera *cam = ptr;
+	video_unregister_device(&cam->vdev);
 
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
+#ifdef CONFIG_PROC_FS
+	vicam_destroy_proc_entry(cam);
+#endif
 
-/* Module paramaters */
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "Debug enabled or not");
+	if (cam->raw_image)
+		kfree(cam->raw_image);
+	if (cam->framebuf)
+		usbvideo_rvfree(cam->framebuf,
+		       VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
 
-static int __init usb_vicam_init(void)
-{
-	int result;
+	kfree(cam);
 
-	printk("VICAM: initializing\n");
-	/* register this driver with the USB subsystem */
-	result = usb_register(&vicam_driver);
-	if (result < 0) {
-		err("usb_register failed for the "__FILE__" driver. Error number %d",
-		    result);
-		return -1;
-	}
+	printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
+}
 
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+/*
+ */
+static int __init
+usb_vicam_init(void)
+{
+	DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
+#ifdef CONFIG_PROC_FS
+	vicam_create_proc_root();
+#endif
+	if (usb_register(&vicam_driver) != 0)
+		printk(KERN_WARNING "usb_register failed!\n");
 	return 0;
 }
 
-static void __exit usb_vicam_exit(void)
+static void __exit
+usb_vicam_exit(void)
 {
-	/* deregister this driver with the USB subsystem */
+	DBG(KERN_INFO
+	       "ViCam-based WebCam driver shutdown\n");
+
 	usb_deregister(&vicam_driver);
+#ifdef CONFIG_PROC_FS
+	vicam_destroy_proc_root();
+#endif
 }
 
 module_init(usb_vicam_init);
 module_exit(usb_vicam_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/vicam.h linux-2.4.21/drivers/usb/vicam.h
--- linux-2.4.20/drivers/usb/vicam.h	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/vicam.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,81 +0,0 @@
-/*
- *
- * Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver
- * Christopher L Cheney (C) 2001
- * 
- */
-
-#ifndef __LINUX_VICAM_H
-#define __LINUX_VICAM_H
-
-
-#ifdef CONFIG_USB_DEBUG
-	static int debug = 1;
-#else
-	static int debug;
-#endif
-
-/* Use our own dbg macro */
-#undef dbg
-#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0)
-
-#define VICAM_NUMFRAMES 30
-#define VICAM_NUMSBUF 1
-
-/* USB REQUEST NUMBERS */
-#define VICAM_REQ_VENDOR	0xff
-#define VICAM_REQ_CAMERA_POWER	0x50
-#define VICAM_REQ_CAPTURE	0x51
-#define VICAM_REQ_LED_CONTROL	0x55
-#define VICAM_REQ_GET_SOMETHIN	0x56
- 
-/* not required but lets you know camera is on */
-/* camera must be on to turn on led */
-/* 0x01 always on  0x03 on when picture taken (flashes) */
-
-struct picture_parm
-{
-	int width;
-	int height;
-	int brightness;
-	int hue;
-	int colour;
-	int contrast;
-	int whiteness;
-	int depth;
-	int palette;
-};
-
-struct vicam_scratch {
-        unsigned char *data;
-        volatile int state;
-        int offset;
-        int length;
-};
-
-/* Structure to hold all of our device specific stuff */
-struct usb_vicam
-{
-	struct video_device vdev;
-	struct usb_device *udev;
-
-	int open_count;	/* number of times this port has been opened */
-	struct semaphore sem;			/* locks this structure */
-	wait_queue_head_t wait;			/* Processes waiting */ 
-
-	int streaming;
-
-	/* v4l stuff */
-	char *camera_name;
-	char *fbuf;
-	struct urb *urb[VICAM_NUMSBUF];
-	int sizes;
-	int *width;
-	int *height;
-	int maxframesize;
-	struct picture_parm win;
-	struct proc_dir_entry *proc_entry;      /* /proc/se401/videoX */
-	struct urb readurb;
-};
-
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/vicamurbs.h linux-2.4.21/drivers/usb/vicamurbs.h
--- linux-2.4.20/drivers/usb/vicamurbs.h	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/usb/vicamurbs.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,324 +0,0 @@
-/*
- *
- * Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver
- * Christopher L Cheney (C) 2001
- * 
- */
-
-
-#ifndef __LINUX_VICAMURBS_H
-#define __LINUX_VICAMURBS_H
-
-/* -------------------------------------------------------------------------- */
-
-/* FIXME - Figure out transfers so that this doesn't need to be here
- *
- * Notice: in pieces below, "0" means other code will fill it while "0x00" means this is zero */
-
-/* Request 0x51 Image Setup */
-
-/* 128x122 3D80 size */
-static unsigned char s128x122bw[] = {
-  0,    0x34, 0xF4, 0x00, 0x00, 0x00, 0,    0,
-  0x00, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
-};
-
-/* 256x242 ? 0xF280 size */
-static unsigned char s256x242bw[] = {
-  0,    0x03, 0xC8, 0x03, 0x00, 0x00, 0,    0,
-  0x00, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
-};
-
-/* 512x242 0x1E480 size */
-static unsigned char s512x242bw[] = {
-  0,    0x05, 0x90, 0x07, 0x00, 0x00, 0,    0,
-  0x00, 0x08, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
-};
-
-/* In s512x242:
-   byte 0: gain -- higher number means brighter image
-   byte 6, 7: shutter speed, little-endian; set this to 15600 * (shutter speed) - 1. (Where shutter speed is something like 1/1000).
-*/
-
-/* -------------------------------------------------------------------------- */
-
-static unsigned char fsetup[] = {
-  0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64,
-
-  0x00, 0x00
-};
-
-static unsigned char firmware1[] = {
-  0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64,
-
-  0xE7, 0x67, 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09,
-  0xDE, 0x00, 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03,
-  0xC0, 0x17, 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07,
-  0x00, 0x00, 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
-};
-
-static unsigned char findex1[] = {
-  0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64,
-
-  0x18, 0x00, 0x00, 0x00
-};
-
-static unsigned char firmware2[] = {
-  0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64,
-
-  0xE7, 0x07, 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07,
-  0x00, 0x00, 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01,
-  0xAA, 0x00, 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00,
-  0xE7, 0x07, 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07,
-  0x7C, 0x00, 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00,
-  0x18, 0x00, 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0,
-  0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07,
-  0xFF, 0xFF, 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00,
-  0x24, 0xC0, 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0,
-  0xE7, 0x07, 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87,
-  0x01, 0x00, 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09,
-  0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0,
-  0x09, 0xC1, 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01,
-  0xE7, 0x09, 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07,
-  0x07, 0x00, 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0,
-  0xC0, 0xDF, 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00,
-  0x17, 0x02, 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77,
-  0x01, 0x00, 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57,
-  0xFF, 0xFF, 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57,
-  0x00, 0x00, 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF,
-  0xC6, 0x00, 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05,
-  0xC1, 0x05, 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF,
-  0x27, 0xDA, 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00,
-  0x0B, 0x06, 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01,
-  0x9F, 0xAF, 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09,
-  0xFC, 0x05, 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06,
-  0x26, 0x01, 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0,
-  0xE7, 0x09, 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09,
-  0x02, 0x06, 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06,
-  0xFC, 0x05, 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06,
-  0x27, 0xDA, 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00,
-  0xFA, 0x05, 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF,
-  0x9F, 0xAF, 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07,
-  0x40, 0x00, 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05,
-  0x9F, 0xAF, 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17,
-  0x02, 0x00, 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06,
-  0x9F, 0xA0, 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00,
-  0x09, 0x06, 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57,
-  0x01, 0x00, 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03,
-  0xE7, 0x07, 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF,
-  0x47, 0xAF, 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07,
-  0x2E, 0x00, 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00,
-  0x09, 0x06, 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00,
-  0xC0, 0x57, 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02,
-  0xC0, 0x57, 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57,
-  0x55, 0x00, 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00,
-  0x9F, 0xC0, 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02,
-  0xC1, 0x0B, 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90,
-  0x08, 0x06, 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B,
-  0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF,
-  0x2F, 0x0E, 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07,
-  0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF,
-  0x28, 0x05, 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E,
-  0x02, 0x00, 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00,
-  0x09, 0x06, 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67,
-  0x7F, 0xFF, 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD,
-  0x22, 0xC0, 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0,
-  0xE7, 0x87, 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF,
-  0xB8, 0x05, 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0,
-  0x9F, 0xAF, 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00,
-  0x24, 0xC0, 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0,
-  0xC8, 0x07, 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00,
-  0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
-  0x9F, 0xAF, 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00,
-  0x9F, 0xAF, 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE,
-  0x24, 0xC0, 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87,
-  0x00, 0x01, 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02,
-  0x0F, 0xC1, 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0,
-  0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
-  0x08, 0x00, 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1,
-  0xEF, 0x07, 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF,
-  0xEF, 0x07, 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF,
-  0xEF, 0x07, 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07,
-  0x00, 0x00, 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF,
-  0x09, 0x06, 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06,
-  0xE7, 0x67, 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67,
-  0x17, 0xD8, 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00,
-  0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0,
-  0x97, 0xCF, 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF,
-  0xDA, 0x02, 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05,
-  0xE7, 0x07, 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07,
-  0x0E, 0x06, 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02,
-  0xF8, 0x05, 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07,
-  0x00, 0x80, 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C,
-  0x02, 0x00, 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00,
-  0x06, 0x06, 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05,
-  0xE7, 0x07, 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07,
-  0xE2, 0x05, 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02,
-  0xF8, 0x05, 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07,
-  0x00, 0x80, 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF,
-  0x66, 0x04, 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF,
-  0x97, 0xCF, 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B,
-  0x0C, 0x06, 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05,
-  0xC0, 0x07, 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05,
-  0x68, 0x00, 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF,
-  0x44, 0x05, 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00,
-  0xE0, 0x07, 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06,
-  0xE8, 0x07, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02,
-  0xE0, 0x07, 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF,
-  0x97, 0xCF, 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05,
-  0xEF, 0x07, 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07,
-  0x0E, 0x06, 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06,
-  0xFE, 0x05, 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01,
-  0xE7, 0x07, 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07,
-  0x07, 0x00, 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07,
-  0x02, 0x00, 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01,
-  0xEF, 0x77, 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0,
-  0x14, 0x04, 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06,
-  0x37, 0xC0, 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06,
-  0x0F, 0xC1, 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06,
-  0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
-  0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00,
-  0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05,
-  0xC8, 0x07, 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05,
-  0xC0, 0x07, 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05,
-  0xC1, 0x77, 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA,
-  0x75, 0xC1, 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1,
-  0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00,
-  0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00,
-  0x06, 0x06, 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00,
-  0xC1, 0x07, 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05,
-  0xEF, 0x07, 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF,
-  0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57,
-  0x01, 0x00, 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07,
-  0x01, 0x00, 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF,
-  0x28, 0x05, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
-  0x30, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
-  0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
-  0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67,
-  0x03, 0x00, 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0,
-  0x08, 0xDA, 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00,
-  0xC1, 0x07, 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00,
-  0x06, 0x06, 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00,
-  0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00,
-  0xC1, 0x0B, 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05,
-  0xC0, 0x07, 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05,
-  0xE7, 0x09, 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8,
-  0xFA, 0x05, 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05,
-  0xE7, 0x07, 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07,
-  0x40, 0x00, 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05,
-  0x9F, 0xAF, 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B,
-  0xE2, 0x05, 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17,
-  0x23, 0x00, 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07,
-  0x04, 0x00, 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF,
-  0x28, 0x05, 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09,
-  0xE6, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
-  0x07, 0x00, 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1,
-  0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00,
-  0xC1, 0x09, 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05,
-  0xC0, 0x07, 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05,
-  0xC1, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
-  0x0D, 0x00, 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF,
-  0x28, 0x05, 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07,
-  0x32, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
-  0x0F, 0x00, 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF,
-  0x28, 0x05, 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9,
-  0x24, 0xC0, 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00,
-  0xC0, 0x67, 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0,
-  0xE7, 0x87, 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67,
-  0xFF, 0xF9, 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA,
-  0x72, 0xC1, 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0,
-  0x97, 0xCF, 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87,
-  0xFF, 0x00, 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF,
-  0x24, 0xC0, 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0,
-  0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF,
-  0x9F, 0xAF, 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0,
-  0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
-  0x40, 0x00, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
-  0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05,
-  0xE7, 0x67, 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67,
-  0xFF, 0xFE, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
-  0x24, 0xC0, 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87,
-  0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07,
-  0x40, 0x00, 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67,
-  0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
-  0x24, 0xC0, 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0,
-  0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA,
-  0xE8, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00,
-  0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
-  0x00, 0xDA, 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1,
-  0xE7, 0x87, 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF,
-  0xE7, 0x07, 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77,
-  0x00, 0x80, 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF,
-  0xE7, 0x07, 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77,
-  0x00, 0x80, 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF,
-  0x09, 0x02, 0x19, 0x00, 0x01, 0x01, 0x00, 0x80,
-  0x96, 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static unsigned char findex2[] = {
-  0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64,
-
-  0x0E, 0x00, 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00,
-  0x26, 0x00, 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00,
-  0x92, 0x00, 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00,
-  0xB8, 0x00, 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00,
-  0xCE, 0x00, 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00,
-  0xE0, 0x00, 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00,
-  0xEC, 0x00, 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01,
-  0x0A, 0x01, 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01,
-  0x22, 0x01, 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01,
-  0x36, 0x01, 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01,
-  0x72, 0x01, 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01,
-  0x88, 0x01, 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01,
-  0xA0, 0x01, 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01,
-  0xB4, 0x01, 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01,
-  0xF6, 0x01, 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02,
-  0x3C, 0x02, 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02,
-  0x56, 0x02, 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02,
-  0x84, 0x02, 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02,
-  0x8E, 0x02, 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02,
-  0xAE, 0x02, 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02,
-  0xC0, 0x02, 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02,
-  0xD4, 0x02, 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02,
-  0xF8, 0x02, 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03,
-  0x24, 0x03, 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03,
-  0x3C, 0x03, 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03,
-  0x58, 0x03, 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03,
-  0x7A, 0x03, 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03,
-  0xB2, 0x03, 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03,
-  0xD4, 0x03, 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03,
-  0xFC, 0x03, 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04,
-  0x32, 0x04, 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04,
-  0x42, 0x04, 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04,
-  0x54, 0x04, 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04,
-  0x62, 0x04, 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04,
-  0x80, 0x04, 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04,
-  0x9A, 0x04, 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04,
-  0xB4, 0x04, 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04,
-  0x2A, 0x05, 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
-};
-
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/clgenfb.c linux-2.4.21/drivers/video/clgenfb.c
--- linux-2.4.20/drivers/video/clgenfb.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/video/clgenfb.c	2002-12-18 18:58:06.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * drivers/video/clgenfb.c - driver for Cirrus Logic chipsets
  *
- * Copyright 1999-2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+ * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
  *
  * Contributors (thanks, all!)
  *
@@ -15,6 +15,9 @@
  *	Lars Hecking:
  *	Amiga updates and testing.
  *
+ *	Cliff Matthews <ctm@ardi.com>:
+ *	16bpp fix for CL-GD7548 (uses info from XFree86 4.2.0 source)
+ *
  * Original clgenfb author:  Frank Neumann
  *
  * Based on retz3fb.c and clgen.c:
@@ -403,6 +406,9 @@
 
 #ifdef CONFIG_PCI
 	struct pci_dev *pdev;
+#define IS_7548(x) ((x)->pdev->device == PCI_DEVICE_ID_CIRRUS_7548)
+#else
+#define IS_7548(x) (FALSE)
 #endif
 };
 
@@ -970,7 +976,10 @@
 
 	DPRINTK ("desired pixclock: %ld kHz\n", freq);
 
-	maxclock = clgen_board_info[fb_info->btype].maxclock;
+	if (IS_7548(fb_info))
+		maxclock = 80100;
+	else
+		maxclock = clgen_board_info[fb_info->btype].maxclock;
 	_par->multiplexing = 0;
 
 	/* If the frequency is greater than we can support, we might be able
@@ -1478,10 +1487,17 @@
 
 		case BT_ALPINE:
 			DPRINTK (" (for GD543x)\n");
-			if (_par->HorizRes >= 1024)
-				vga_wseq (fb_info->regs, CL_SEQR7, 0xa7);
-			else
-				vga_wseq (fb_info->regs, CL_SEQR7, 0xa3);
+			if (IS_7548(fb_info)) {
+				vga_wseq (fb_info->regs, CL_SEQR7, 
+					  (vga_rseq (fb_info->regs, CL_SEQR7) & 0xE0)
+					  | 0x17);
+				WHDR (fb_info, 0xC1);
+			} else {
+				if (_par->HorizRes >= 1024)
+					vga_wseq (fb_info->regs, CL_SEQR7, 0xa7);
+				else
+					vga_wseq (fb_info->regs, CL_SEQR7, 0xa3);
+			}	
 			clgen_set_mclk (fb_info, _par->mclk, _par->divMCLK);
 			break;
 
@@ -1594,6 +1610,11 @@
 			_par->var.bits_per_pixel);
 	}
 
+	if (IS_7548(fb_info)) {
+		vga_wseq (fb_info->regs, CL_SEQR2D, 
+			vga_rseq (fb_info->regs, CL_SEQR2D) | 0xC0);
+	}
+
 	vga_wcrt (fb_info->regs, VGA_CRTC_OFFSET, offset & 0xff);
 	tmp = 0x22;
 	if (offset & 0x100)
@@ -2884,7 +2905,7 @@
      *  Modularization
      */
 
-MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@mandrakesoft.com>");
+MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>");
 MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
 MODULE_LICENSE("GPL");
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/clgenfb.h linux-2.4.21/drivers/video/clgenfb.h
--- linux-2.4.20/drivers/video/clgenfb.h	2000-01-06 18:23:46.000000000 +0000
+++ linux-2.4.21/drivers/video/clgenfb.h	2002-12-18 18:58:10.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * drivers/video/clgenfb.h - Cirrus Logic chipset constants
  *
- * Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
+ * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
  *
  * Original clgenfb author:  Frank Neumann
  *
@@ -60,6 +60,7 @@
 #define CL_SEQR1D	0x1d	/* VCLK2 Denominator and Post-Scalar Value */
 #define CL_SEQR1E	0x1e	/* VCLK3 Denominator and Post-Scalar Value */
 #define CL_SEQR1F	0x1f	/* BIOS ROM write enable and MCLK Select */
+#define CL_SEQR2D	0x2d	/* unknown, snagged from XFree86 4.2.0 */
 
 /*** CRT Controller Registers ***/
 #define CL_CRT22	0x22	/* Graphics Data Latches ReadBack */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/fbmem.c linux-2.4.21/drivers/video/fbmem.c
--- linux-2.4.20/drivers/video/fbmem.c	2002-12-18 18:27:08.000000000 +0000
+++ linux-2.4.21/drivers/video/fbmem.c	2002-12-18 18:58:01.000000000 +0000
@@ -647,6 +647,8 @@
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 #elif defined(__sh__)
 	pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE;
+#elif defined(__hppa__)
+	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; 
 #elif defined(__ia64__)
 	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
 #elif defined(__hppa__)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/neofb.c linux-2.4.21/drivers/video/neofb.c
--- linux-2.4.20/drivers/video/neofb.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/drivers/video/neofb.c	2002-12-18 18:58:09.000000000 +0000
@@ -2253,7 +2253,7 @@
   /*
    * Our driver data
    */
-  dev->driver_data = info;
+  pci_set_drvdata(dev, info);
 
   return 0;
 
@@ -2267,7 +2267,7 @@
 
 static void __devexit neofb_remove (struct pci_dev *dev)
 {
-  struct neofb_info *info = (struct neofb_info *)dev->driver_data;
+  struct neofb_info *info = pci_get_drvdata(dev);
 
   DBG("neofb_remove");
 
@@ -2289,7 +2289,7 @@
        * Ensure that the driver data is no longer
        * valid.
        */
-      dev->driver_data = NULL;
+      pci_set_drvdata(dev, NULL);
     }
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/riva/nv4ref.h linux-2.4.21/drivers/video/riva/nv4ref.h
--- linux-2.4.20/drivers/video/riva/nv4ref.h	2000-02-29 19:07:04.000000000 +0000
+++ linux-2.4.21/drivers/video/riva/nv4ref.h	2002-12-18 18:58:05.000000000 +0000
@@ -41,7 +41,7 @@
  * GPL licensing note -- nVidia is allowing a liberal interpretation of
  * the documentation restriction above, to merely say that this nVidia's
  * copyright and disclaimer should be included with all code derived
- * from this source.  -- Jeff Garzik <jgarzik@mandrakesoft.com>, 01/Nov/99 
+ * from this source.  -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 
  */
 
  /***************************************************************************\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/riva/riva_hw.c linux-2.4.21/drivers/video/riva/riva_hw.c
--- linux-2.4.20/drivers/video/riva/riva_hw.c	2002-02-25 19:38:07.000000000 +0000
+++ linux-2.4.21/drivers/video/riva/riva_hw.c	2002-12-18 18:58:05.000000000 +0000
@@ -41,7 +41,7 @@
  * GPL licensing note -- nVidia is allowing a liberal interpretation of
  * the documentation restriction above, to merely say that this nVidia's
  * copyright and disclaimer should be included with all code derived
- * from this source.  -- Jeff Garzik <jgarzik@mandrakesoft.com>, 01/Nov/99 
+ * from this source.  -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 
  */
 
 /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_hw.c,v 1.8 2000/02/08 17:19:11 dawes Exp $ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/riva/riva_hw.h linux-2.4.21/drivers/video/riva/riva_hw.h
--- linux-2.4.20/drivers/video/riva/riva_hw.h	2002-02-25 19:38:07.000000000 +0000
+++ linux-2.4.21/drivers/video/riva/riva_hw.h	2002-12-18 18:58:07.000000000 +0000
@@ -41,7 +41,7 @@
  * GPL licensing note -- nVidia is allowing a liberal interpretation of
  * the documentation restriction above, to merely say that this nVidia's
  * copyright and disclaimer should be included with all code derived
- * from this source.  -- Jeff Garzik <jgarzik@mandrakesoft.com>, 01/Nov/99 
+ * from this source.  -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 
  */
 
 /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_hw.h,v 1.6 2000/02/08 17:19:12 dawes Exp $ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/riva/riva_tbl.h linux-2.4.21/drivers/video/riva/riva_tbl.h
--- linux-2.4.20/drivers/video/riva/riva_tbl.h	2001-02-13 21:15:05.000000000 +0000
+++ linux-2.4.21/drivers/video/riva/riva_tbl.h	2002-12-18 18:58:07.000000000 +0000
@@ -41,7 +41,7 @@
  * GPL licensing note -- nVidia is allowing a liberal interpretation of
  * the documentation restriction above, to merely say that this nVidia's
  * copyright and disclaimer should be included with all code derived
- * from this source.  -- Jeff Garzik <jgarzik@mandrakesoft.com>, 01/Nov/99 
+ * from this source.  -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 
  */
 
 /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_tbl.h,v 1.5 2000/02/08 17:19:12 dawes Exp $ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/sti/sticore.c linux-2.4.21/drivers/video/sti/sticore.c
--- linux-2.4.20/drivers/video/sti/sticore.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/drivers/video/sti/sticore.c	2002-12-18 18:58:09.000000000 +0000
@@ -467,6 +467,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_FB
 struct sti_cooked_font * __init
 sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name )
 {
@@ -523,6 +524,13 @@
 
 	return cooked_font;
 }
+#else
+struct sti_cooked_font * __init
+sti_select_fbfont(struct sti_cooked_rom *cooked_rom, char *fbfont_name)
+{
+	return NULL;
+}
+#endif
 
 struct sti_cooked_font * __init
 sti_select_font(struct sti_cooked_rom *rom,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/sti/stifb.c linux-2.4.21/drivers/video/sti/stifb.c
--- linux-2.4.20/drivers/video/sti/stifb.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/drivers/video/sti/stifb.c	2002-12-18 18:58:05.000000000 +0000
@@ -133,7 +133,7 @@
 #endif			
 };
 
-static int stifb_force_bpp[MAX_STI_ROMS] = {0, };
+static int stifb_force_bpp[MAX_STI_ROMS];
 
 /* ------------------- chipset specific functions -------------------------- */
 
@@ -1290,7 +1290,10 @@
 		fb->id = S9000_ID_A1659A;
 		break;
 	case S9000_ID_A1439A:	/* CRX24/A1439A */
-		bpp = 32;
+		if (force_bpp == 8 || force_bpp == 32)
+		  bpp = force_bpp;
+		else
+		  bpp = 32;
 		break;
 	case S9000_ID_HCRX:	/* Hyperdrive/HCRX */
 		memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/vga.h linux-2.4.21/drivers/video/vga.h
--- linux-2.4.20/drivers/video/vga.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/drivers/video/vga.h	2002-12-18 18:58:03.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * linux/include/video/vga.h -- standard VGA chipset interaction
  *
- * Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
+ * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
  * 
  * Copyright history from vga16fb.c:
  *	Copyright 1999 Ben Pfaff and Petr Vandrovec
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/TODO linux-2.4.21/fs/befs/TODO
--- linux-2.4.20/fs/befs/TODO	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/befs/TODO	2002-12-18 18:58:08.000000000 +0000
@@ -3,14 +3,9 @@
 
 * Convert comments to the Kernel-Doc format.
 
-* Befs_fs.h has gotten big and messy. No reason not to break it up into 
-	smaller peices.
-
 * See if Alexander Viro's option parser made it into the kernel tree. 
 	Use that if we can. (include/linux/parser.h)
 
 * See if we really need separate types for on-disk and in-memory 
 	representations of the superblock and inode.
 
-* We need a wrapper around the kernel's disk cache stuff. Then it would be 
-	easy to slip in stuff like using the pagecache.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/attribute.c linux-2.4.21/fs/befs/attribute.c
--- linux-2.4.20/fs/befs/attribute.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/befs/attribute.c	2002-12-18 18:58:01.000000000 +0000
@@ -12,7 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 
-#include "befs_fs.h"
+#include "befs.h"
 #include "endian.h"
 
 #define SD_DATA(sd)\
@@ -27,7 +27,6 @@
 
 befs_small_data *find_small_data(struct super_block *sb, befs_inode * inode,
 				 const char *name);
-
 int
  read_small_data(struct super_block *sb, befs_inode * inode,
 		 befs_small_data * sdata, void *buf, size_t bufsize);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/befs.h linux-2.4.21/fs/befs/befs.h
--- linux-2.4.20/fs/befs/befs.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/fs/befs/befs.h	2002-12-18 18:58:01.000000000 +0000
@@ -0,0 +1,152 @@
+/*
+ * befs_fs.h
+ *
+ * Copyright (C) 2001-2002 Will Dyson <will_dyson@pobox.com>
+ * Copyright (C) 1999 Makoto Kato (m_kato@ga2.so-net.ne.jp)
+ */
+
+#ifndef _LINUX_BEFS_H
+#define _LINUX_BEFS_H
+
+#include "befs_fs_types.h"
+
+/* used in debug.c */
+#define BEFS_VERSION "0.9.3"
+
+typedef u64 befs_blocknr_t;
+typedef u32 vfs_blocknr_t;
+
+/*
+ * BeFS in memory structures
+ */
+
+typedef struct befs_mount_options {
+	gid_t gid;
+	uid_t uid;
+	int use_gid;
+	int use_uid;
+	int debug;
+	char *iocharset;
+} befs_mount_options;
+
+typedef struct befs_sb_info {
+	u32 magic1;
+	u32 block_size;
+	u32 block_shift;
+	int byte_order;
+	befs_off_t num_blocks;
+	befs_off_t used_blocks;
+	u32 inode_size;
+	u32 magic2;
+
+	/* Allocation group information */
+	u32 blocks_per_ag;
+	u32 ag_shift;
+	u32 num_ags;
+
+	/* jornal log entry */
+	befs_block_run log_blocks;
+	befs_off_t log_start;
+	befs_off_t log_end;
+
+	befs_inode_addr root_dir;
+	befs_inode_addr indices;
+	u32 magic3;
+
+	befs_mount_options mount_opts;
+	struct nls_table *nls;
+
+} befs_sb_info;
+
+typedef struct befs_inode_info {
+	u32 i_flags;
+	u32 i_type;
+
+	befs_inode_addr i_inode_num;
+	befs_inode_addr i_parent;
+	befs_inode_addr i_attribute;
+
+	union {
+		befs_data_stream ds;
+		char symlink[BEFS_SYMLINK_LEN];
+	} i_data;
+
+} befs_inode_info;
+
+enum befs_err {
+	BEFS_OK,
+	BEFS_ERR,
+	BEFS_BAD_INODE,
+	BEFS_BT_END,
+	BEFS_BT_EMPTY,
+	BEFS_BT_MATCH,
+	BEFS_BT_PARMATCH,
+	BEFS_BT_NOT_FOUND
+};
+
+/****************************/
+/* debug.c */
+void befs_error(const struct super_block *sb, const char *fmt, ...);
+void befs_warning(const struct super_block *sb, const char *fmt, ...);
+void befs_debug(const struct super_block *sb, const char *fmt, ...);
+
+void befs_dump_super_block(const struct super_block *sb, befs_super_block *);
+void befs_dump_inode(const struct super_block *sb, befs_inode *);
+void befs_dump_index_entry(const struct super_block *sb, befs_btree_super *);
+void befs_dump_index_node(const struct super_block *sb, befs_btree_nodehead *);
+void befs_dump_inode_addr(const struct super_block *sb, befs_inode_addr);
+/****************************/
+
+/* Gets a pointer to the private portion of the super_block
+ * structure from the public part
+ */
+static inline befs_sb_info *
+BEFS_SB(const struct super_block *super)
+{
+	return (befs_sb_info *) super->u.generic_sbp;
+}
+
+static inline befs_inode_info *
+BEFS_I(const struct inode *inode)
+{
+	return (befs_inode_info *) inode->u.generic_ip;
+}
+
+static inline befs_blocknr_t
+iaddr2blockno(struct super_block *sb, befs_inode_addr * iaddr)
+{
+	return ((iaddr->allocation_group << BEFS_SB(sb)->ag_shift) +
+		iaddr->start);
+}
+
+static inline befs_inode_addr
+blockno2iaddr(struct super_block *sb, befs_blocknr_t blockno)
+{
+	befs_inode_addr iaddr;
+	iaddr.allocation_group = blockno >> BEFS_SB(sb)->ag_shift;
+	iaddr.start =
+	    blockno - (iaddr.allocation_group << BEFS_SB(sb)->ag_shift);
+	iaddr.len = 1;
+
+	return iaddr;
+}
+
+static inline unsigned int
+befs_iaddrs_per_block(struct super_block *sb)
+{
+	return BEFS_SB(sb)->block_size / sizeof (befs_inode_addr);
+}
+
+static inline int
+befs_iaddr_is_empty(befs_inode_addr * iaddr)
+{
+	return (!iaddr->allocation_group) && (!iaddr->start) && (!iaddr->len);
+}
+
+static inline size_t
+befs_brun_size(struct super_block *sb, befs_block_run run)
+{
+	return BEFS_SB(sb)->block_size * run.len;
+}
+
+#endif				/* _LINUX_BEFS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/befs_fs.h linux-2.4.21/fs/befs/befs_fs.h
--- linux-2.4.20/fs/befs/befs_fs.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/befs/befs_fs.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,200 +0,0 @@
-/*
- * befs_fs.h
- *
- * Copyright (C) 2001-2002 Will Dyson <will_dyson@pobox.com>
- * Copyright (C) 1999 Makoto Kato (m_kato@ga2.so-net.ne.jp)
- */
-
-#ifndef _LINUX_BEFS_FS
-#define _LINUX_BEFS_FS
-
-#include "befs_fs_types.h"
-#include "compatibility.h"
-
-/* used in debug.c */
-#define BEFS_VERSION "0.9.2"
-
-typedef __u64 befs_blocknr_t;
-typedef __u32 vfs_blocknr_t;
-
-/*
- * BeFS in memory structures
- */
-
-typedef struct befs_mount_options {
-	gid_t gid;
-	uid_t uid;
-	int use_gid;
-	int use_uid;
-	int debug;
-	char *iocharset;
-} befs_mount_options;
-
-typedef struct befs_sb_info {
-	__u32 magic1;
-	__u32 block_size;
-	__u32 block_shift;
-	__u32 byte_order;
-	befs_off_t num_blocks;
-	befs_off_t used_blocks;
-	__u32 inode_size;
-	__u32 magic2;
-
-	/* Allocation group information */
-	__u32 blocks_per_ag;
-	__u32 ag_shift;
-	__u32 num_ags;
-
-	/* jornal log entry */
-	befs_block_run log_blocks;
-	befs_off_t log_start;
-	befs_off_t log_end;
-
-	befs_inode_addr root_dir;
-	befs_inode_addr indices;
-	__u32 magic3;
-
-	befs_mount_options mount_opts;
-	struct nls_table *nls;
-
-} befs_sb_info;
-
-typedef struct befs_inode_info {
-	__u32 i_flags;
-	__u32 i_type;
-
-	befs_inode_addr i_inode_num;
-	befs_inode_addr i_parent;
-	befs_inode_addr i_attribute;
-
-	union {
-		befs_data_stream ds;
-		char symlink[BEFS_SYMLINK_LEN];
-	} i_data;
-
-} befs_inode_info;
-
-enum befs_err {
-	BEFS_OK,
-	BEFS_ERR,
-	BEFS_BAD_INODE,
-	BEFS_BT_END,
-	BEFS_BT_EMPTY,
-	BEFS_BT_MATCH,
-	BEFS_BT_PARMATCH,
-	BEFS_BT_NOT_FOUND
-};
-
-/****************************/
-/* io.c */
-struct buffer_head *befs_bread_iaddr(struct super_block *sb,
-				     befs_inode_addr iaddr);
-
-struct buffer_head *befs_bread(struct super_block *sb, befs_blocknr_t block);
-/****************************/
-
-/****************************/
-/* datastream.c */
-struct buffer_head *befs_read_datastream(struct super_block *sb,
-					 befs_data_stream * ds, befs_off_t pos,
-					 uint * off);
-
-int befs_fblock2brun(struct super_block *sb, befs_data_stream * data,
-		     befs_blocknr_t fblock, befs_block_run * run);
-
-size_t befs_read_lsymlink(struct super_block *sb, befs_data_stream * data,
-			  void *buff, befs_off_t len);
-
-befs_blocknr_t befs_count_blocks(struct super_block *sb, befs_data_stream * ds);
-
-extern const befs_inode_addr BAD_IADDR;
-/****************************/
-
-/****************************/
-/* debug.c */
-void befs_error(const struct super_block *sb, const char *fmt, ...);
-void befs_warning(const struct super_block *sb, const char *fmt, ...);
-void befs_debug(const struct super_block *sb, const char *fmt, ...);
-
-void befs_dump_super_block(const struct super_block *sb, befs_super_block *);
-void befs_dump_inode(const struct super_block *sb, befs_inode *);
-void befs_dump_index_entry(const struct super_block *sb, befs_btree_super *);
-void befs_dump_index_node(const struct super_block *sb, befs_btree_nodehead *);
-void befs_dump_inode_addr(const struct super_block *sb, befs_inode_addr);
-/****************************/
-
-/****************************/
-/* btree.c */
-int befs_btree_find(struct super_block *sb, befs_data_stream * ds,
-		    const char *key, befs_off_t * value);
-
-int befs_btree_read(struct super_block *sb, befs_data_stream * ds,
-		    loff_t key_no, size_t bufsize, char *keybuf,
-		    size_t * keysize, befs_off_t * value);
-/****************************/
-
-/****************************/
-/* super.c */
-int befs_load_sb(struct super_block *sb, befs_super_block * disk_sb);
-int befs_check_sb(struct super_block *sb);
-/****************************/
-
-/****************************/
-/* inode.c */
-int befs_check_inode(struct super_block *sb, befs_inode * raw_inode,
-		     befs_blocknr_t inode);
-/****************************/
-
-/* Gets a pointer to the private portion of the super_block
- * structure from the public part
- */
-static inline befs_sb_info *
-BEFS_SB(const struct super_block *super)
-{
-	return (befs_sb_info *) super->u.generic_sbp;
-}
-
-static inline befs_inode_info *
-BEFS_I(const struct inode *inode)
-{
-	return (befs_inode_info *) inode->u.generic_ip;
-}
-
-static inline befs_blocknr_t
-iaddr2blockno(struct super_block *sb, befs_inode_addr * iaddr)
-{
-	return ((iaddr->allocation_group << BEFS_SB(sb)->ag_shift) +
-		iaddr->start);
-}
-
-static inline befs_inode_addr
-blockno2iaddr(struct super_block *sb, befs_blocknr_t blockno)
-{
-	befs_inode_addr iaddr;
-	iaddr.allocation_group = blockno >> BEFS_SB(sb)->ag_shift;
-	iaddr.start =
-	    blockno - (iaddr.allocation_group << BEFS_SB(sb)->ag_shift);
-	iaddr.len = 1;
-
-	return iaddr;
-}
-
-static inline unsigned int
-befs_iaddrs_per_block(struct super_block *sb)
-{
-	return BEFS_SB(sb)->block_size / sizeof (befs_inode_addr);
-}
-
-static inline int
-befs_iaddr_is_empty(befs_inode_addr * iaddr)
-{
-	return (!iaddr->allocation_group) && (!iaddr->start) && (!iaddr->len);
-}
-
-static inline size_t
-befs_brun_size(struct super_block *sb, befs_block_run run)
-{
-	return BEFS_SB(sb)->block_size * run.len;
-}
-
-#endif				/* _LINUX_BEFS_FS */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/befs_fs_types.h linux-2.4.21/fs/befs/befs_fs_types.h
--- linux-2.4.20/fs/befs/befs_fs_types.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/befs/befs_fs_types.h	2002-12-18 18:58:04.000000000 +0000
@@ -45,15 +45,17 @@
  */
 
 enum super_flags {
+	BEFS_BYTESEX_BE,
+	BEFS_BYTESEX_LE,
 	BEFS_CLEAN = 0x434c454e,
 	BEFS_DIRTY = 0x44495254,
-	BEFS_BYTESEX_BE = 0x45474942,
-	BEFS_BYTESEX_LE = 0x42494745,
 	BEFS_SUPER_MAGIC1 = 0x42465331,	/* BFS1 */
 	BEFS_SUPER_MAGIC2 = 0xdd121031,
 	BEFS_SUPER_MAGIC3 = 0x15b6830e,
 };
 
+#define BEFS_BYTEORDER_NATIVE 0x42494745
+
 #define BEFS_SUPER_MAGIC BEFS_SUPER_MAGIC1
 
 /*
@@ -77,15 +79,15 @@
  * On-Disk datastructures of BeFS
  */
 
-typedef __u64 befs_off_t;
-typedef __u64 befs_time_t;
+typedef u64 befs_off_t;
+typedef u64 befs_time_t;
 typedef void befs_binode_etc;
 
 /* Block runs */
 typedef struct {
-	__u32 allocation_group;
-	__u16 start;
-	__u16 len;
+	u32 allocation_group;
+	u16 start;
+	u16 len;
 } PACKED befs_block_run;
 
 typedef befs_block_run befs_inode_addr;
@@ -95,29 +97,29 @@
  */
 typedef struct {
 	char name[B_OS_NAME_LENGTH];
-	__u32 magic1;
-	__u32 fs_byte_order;
+	u32 magic1;
+	u32 fs_byte_order;
 
-	__u32 block_size;
-	__u32 block_shift;
+	u32 block_size;
+	u32 block_shift;
 
 	befs_off_t num_blocks;
 	befs_off_t used_blocks;
 
-	__u32 inode_size;
+	u32 inode_size;
 
-	__u32 magic2;
-	__u32 blocks_per_ag;
-	__u32 ag_shift;
-	__u32 num_ags;
+	u32 magic2;
+	u32 blocks_per_ag;
+	u32 ag_shift;
+	u32 num_ags;
 
-	__u32 flags;
+	u32 flags;
 
 	befs_block_run log_blocks;
 	befs_off_t log_start;
 	befs_off_t log_end;
 
-	__u32 magic3;
+	u32 magic3;
 	befs_inode_addr root_dir;
 	befs_inode_addr indices;
 
@@ -139,35 +141,35 @@
 
 /* Attribute */
 typedef struct {
-	__u32 type;
-	__u16 name_size;
-	__u16 data_size;
+	u32 type;
+	u16 name_size;
+	u16 data_size;
 	char name[1];
 } PACKED befs_small_data;
 
 /* Inode structure */
 typedef struct {
-	__u32 magic1;
+	u32 magic1;
 	befs_inode_addr inode_num;
-	__u32 uid;
-	__u32 gid;
-	__u32 mode;
-	__u32 flags;
+	u32 uid;
+	u32 gid;
+	u32 mode;
+	u32 flags;
 	befs_time_t create_time;
 	befs_time_t last_modified_time;
 	befs_inode_addr parent;
 	befs_inode_addr attributes;
-	__u32 type;
+	u32 type;
 
-	__u32 inode_size;
-	__u32 etc;		/* not use */
+	u32 inode_size;
+	u32 etc;		/* not use */
 
 	union {
 		befs_data_stream datastream;
 		char symlink[BEFS_SYMLINK_LEN];
 	} data;
 
-	__u32 pad[4];		/* not use */
+	u32 pad[4];		/* not use */
 	befs_small_data small_data[1];
 } PACKED befs_inode;
 
@@ -188,10 +190,10 @@
 };
 
 typedef struct {
-	__u32 magic;
-	__u32 node_size;
-	__u32 max_depth;
-	__u32 data_type;
+	u32 magic;
+	u32 node_size;
+	u32 max_depth;
+	u32 data_type;
 	befs_off_t root_node_ptr;
 	befs_off_t free_node_ptr;
 	befs_off_t max_size;
@@ -204,8 +206,8 @@
 	befs_off_t left;
 	befs_off_t right;
 	befs_off_t overflow;
-	__u16 all_key_count;
-	__u16 all_key_length;
+	u16 all_key_count;
+	u16 all_key_length;
 } PACKED befs_btree_nodehead;
 
 #endif				/* _LINUX_BEFS_FS_TYPES */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/btree.c linux-2.4.21/fs/befs/btree.c
--- linux-2.4.20/fs/befs/btree.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/befs/btree.c	2002-12-18 18:58:12.000000000 +0000
@@ -26,7 +26,9 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 
-#include "befs_fs.h"
+#include "befs.h"
+#include "btree.h"
+#include "datastream.h"
 #include "endian.h"
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/btree.h linux-2.4.21/fs/befs/btree.h
--- linux-2.4.20/fs/befs/btree.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/fs/befs/btree.h	2002-12-18 18:58:03.000000000 +0000
@@ -0,0 +1,11 @@
+/*
+ * btree.h
+ * 
+ */
+
+int befs_btree_find(struct super_block *sb, befs_data_stream * ds,
+		    const char *key, befs_off_t * value);
+
+int befs_btree_read(struct super_block *sb, befs_data_stream * ds,
+		    loff_t key_no, size_t bufsize, char *keybuf,
+		    size_t * keysize, befs_off_t * value);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/compatibility.h linux-2.4.21/fs/befs/compatibility.h
--- linux-2.4.20/fs/befs/compatibility.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/befs/compatibility.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,26 +0,0 @@
-/*
- * linux/fs/befs/compatiblity.h
- *
- * Copyright (C) 2001 Will Dyson <will_dyson@pobox.com>
- *   AKA <will@cs.earlham.edu>
- *
- * This file trys to take care of differences between
- * kernel versions
- */
-
-#include <linux/version.h>
-
-/* New interfaces in 2.4.10 */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
-
-#define min_t(type,x,y) \
-({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
-
-#define max_t(type,x,y) \
-({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
-
-#define vsnprintf(buf, n, fmt, args) vsprintf(buf, fmt, args)
-
-#define MODULE_LICENSE(x)
-
-#endif				/* LINUX_VERSION_CODE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/datastream.c linux-2.4.21/fs/befs/datastream.c
--- linux-2.4.20/fs/befs/datastream.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/befs/datastream.c	2002-12-18 18:58:05.000000000 +0000
@@ -15,7 +15,9 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 
-#include "befs_fs.h"
+#include "befs.h"
+#include "datastream.h"
+#include "io.h"
 #include "endian.h"
 
 const befs_inode_addr BAD_IADDR = { 0, 0, 0 };
@@ -466,8 +468,7 @@
 	}
 
 	dbl_indir_block = befs_bread(sb,
-				     iaddr2blockno(sb,
-						   &data->double_indirect) +
+				     iaddr2blockno(sb, &data->double_indirect) +
 				     dbl_which_block);
 	if (dbl_indir_block == NULL) {
 		befs_error(sb, "befs_read_brun_dblindirect() couldn't read the "
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/datastream.h linux-2.4.21/fs/befs/datastream.h
--- linux-2.4.20/fs/befs/datastream.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/fs/befs/datastream.h	2002-12-18 18:58:11.000000000 +0000
@@ -0,0 +1,18 @@
+/*
+ * datastream.h
+ *
+ */
+
+struct buffer_head *befs_read_datastream(struct super_block *sb,
+					 befs_data_stream * ds, befs_off_t pos,
+					 uint * off);
+
+int befs_fblock2brun(struct super_block *sb, befs_data_stream * data,
+		     befs_blocknr_t fblock, befs_block_run * run);
+
+size_t befs_read_lsymlink(struct super_block *sb, befs_data_stream * data,
+			  void *buff, befs_off_t len);
+
+befs_blocknr_t befs_count_blocks(struct super_block *sb, befs_data_stream * ds);
+
+extern const befs_inode_addr BAD_IADDR;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/debug.c linux-2.4.21/fs/befs/debug.c
--- linux-2.4.20/fs/befs/debug.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/befs/debug.c	2002-12-18 18:58:07.000000000 +0000
@@ -20,7 +20,7 @@
 
 #endif				/* __KERNEL__ */
 
-#include "befs_fs.h"
+#include "befs.h"
 #include "endian.h"
 
 #define ERRBUFSIZE 1024
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/endian.h linux-2.4.21/fs/befs/endian.h
--- linux-2.4.20/fs/befs/endian.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/befs/endian.h	2002-12-18 18:58:06.000000000 +0000
@@ -10,7 +10,6 @@
 #define LINUX_BEFS_ENDIAN
 
 #include <linux/byteorder/generic.h>
-#include "befs_fs.h"
 
 static inline u64
 fs64_to_cpu(const struct super_block *sb, u64 n)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/inode.c linux-2.4.21/fs/befs/inode.c
--- linux-2.4.20/fs/befs/inode.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/befs/inode.c	2002-12-18 18:58:10.000000000 +0000
@@ -6,7 +6,8 @@
 
 #include <linux/fs.h>
 
-#include "befs_fs.h"
+#include "befs.h"
+#include "inode.h"
 #include "endian.h"
 
 /*
@@ -18,9 +19,9 @@
 befs_check_inode(struct super_block *sb, befs_inode * raw_inode,
 		 befs_blocknr_t inode)
 {
-	__u32 magic1 = fs32_to_cpu(sb, raw_inode->magic1);
+	u32 magic1 = fs32_to_cpu(sb, raw_inode->magic1);
 	befs_inode_addr ino_num = fsrun_to_cpu(sb, raw_inode->inode_num);
-	__u32 flags = fs32_to_cpu(sb, raw_inode->flags);
+	u32 flags = fs32_to_cpu(sb, raw_inode->flags);
 
 	/* check magic header. */
 	if (magic1 != BEFS_INODE_MAGIC1) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/inode.h linux-2.4.21/fs/befs/inode.h
--- linux-2.4.20/fs/befs/inode.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/fs/befs/inode.h	2002-12-18 18:58:08.000000000 +0000
@@ -0,0 +1,7 @@
+/*
+ * inode.h
+ * 
+ */
+
+int befs_check_inode(struct super_block *sb, befs_inode * raw_inode,
+		     befs_blocknr_t inode);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/io.c linux-2.4.21/fs/befs/io.c
--- linux-2.4.20/fs/befs/io.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/befs/io.c	2002-12-18 18:58:04.000000000 +0000
@@ -13,7 +13,8 @@
 
 #include <linux/fs.h>
 
-#include "befs_fs.h"
+#include "befs.h"
+#include "io.h"
 
 /*
  * Converts befs notion of disk addr to a disk offset and uses
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/io.h linux-2.4.21/fs/befs/io.h
--- linux-2.4.20/fs/befs/io.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/fs/befs/io.h	2002-12-18 18:58:01.000000000 +0000
@@ -0,0 +1,8 @@
+/*
+ * io.h
+ */
+
+struct buffer_head *befs_bread_iaddr(struct super_block *sb,
+				     befs_inode_addr iaddr);
+
+struct buffer_head *befs_bread(struct super_block *sb, befs_blocknr_t block);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/linuxvfs.c linux-2.4.21/fs/befs/linuxvfs.c
--- linux-2.4.20/fs/befs/linuxvfs.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/befs/linuxvfs.c	2002-12-18 18:58:09.000000000 +0000
@@ -15,7 +15,12 @@
 #include <linux/string.h>
 #include <linux/nls.h>
 
-#include "befs_fs.h"
+#include "befs.h"
+#include "btree.h"
+#include "inode.h"
+#include "datastream.h"
+#include "super.h"
+#include "io.h"
 #include "endian.h"
 
 EXPORT_NO_SYMBOLS;
@@ -35,42 +40,55 @@
 static void befs_clear_inode(struct inode *ino);
 static int befs_init_inodecache(void);
 static void befs_destroy_inodecache(void);
+
 static int befs_readlink(struct dentry *, char *, int);
 static int befs_follow_link(struct dentry *, struct nameidata *nd);
+
 static int befs_utf2nls(struct super_block *sb, const char *in, int in_len,
 			char **out, int *out_len);
 static int befs_nls2utf(struct super_block *sb, const char *in, int in_len,
 			char **out, int *out_len);
+
 static void befs_put_super(struct super_block *);
 static struct super_block *befs_read_super(struct super_block *, void *, int);
 static int befs_remount(struct super_block *, int *, char *);
 static int befs_statfs(struct super_block *, struct statfs *);
 static int parse_options(char *, befs_mount_options *);
 
+static ssize_t befs_listxattr(struct dentry *dentry, char *buffer, size_t size);
+static ssize_t befs_getxattr(struct dentry *dentry, const char *name,
+			     void *buffer, size_t size);
+static int befs_setxattr(struct dentry *dentry, const char *name, void *value,
+			 size_t size, int flags);
+static int befs_removexattr(struct dentry *dentry, const char *name);
+
+/* slab cache for befs_inode_info objects */
+static kmem_cache_t *befs_inode_cachep;
+
 static const struct super_operations befs_sops = {
 	read_inode:befs_read_inode,	/* initialize & read inode */
 	clear_inode:befs_clear_inode,	/* uninit inode */
 	put_super:befs_put_super,	/* uninit super */
 	statfs:befs_statfs,	/* statfs */
-	remount_fs:befs_remount	/* remount_fs */
+	remount_fs:befs_remount,
 };
 
-/* slab cache for befs_inode_info objects */
-static kmem_cache_t *befs_inode_cachep;
-
 struct file_operations befs_dir_operations = {
-	read:generic_read_dir,	/* read */
-	readdir:befs_readdir,	/* readdir */
+	read:generic_read_dir,
+	readdir:befs_readdir,
 };
 
 struct inode_operations befs_dir_inode_operations = {
-	lookup:befs_lookup,	/* lookup */
+	lookup:befs_lookup,
 };
 
 struct file_operations befs_file_operations = {
 	llseek:default_llseek,
-	read:generic_file_read,	/* read */
-	mmap:generic_file_mmap,	/* mmap */
+	read:generic_file_read,
+	mmap:generic_file_mmap,
+};
+
+struct inode_operations befs_file_inode_operations = {
 };
 
 struct address_space_operations befs_aops = {
@@ -80,8 +98,8 @@
 };
 
 static struct inode_operations befs_symlink_inode_operations = {
-	readlink:befs_readlink,	/* readlink */
-	follow_link:befs_follow_link	/* follow_link */
+	readlink:befs_readlink,
+	follow_link:befs_follow_link,
 };
 
 /* 
@@ -353,12 +371,7 @@
 	    (time_t) (fs64_to_cpu(sb, raw_inode->last_modified_time) >> 16);
 	inode->i_ctime = inode->i_mtime;
 	inode->i_atime = inode->i_mtime;
-
-/* Bloody hell, Linus. Why add this in a stable series? */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,9)
 	inode->i_blkbits = befs_sb->block_shift;
-#endif
-
 	inode->i_blksize = befs_sb->block_size;
 
 	befs_ino->i_inode_num = fsrun_to_cpu(sb, raw_inode->inode_num);
@@ -387,6 +400,7 @@
 
 	if (S_ISREG(inode->i_mode)) {
 		inode->i_fop = &befs_file_operations;
+		inode->i_op = &befs_file_inode_operations;
 	} else if (S_ISDIR(inode->i_mode)) {
 		inode->i_op = &befs_dir_inode_operations;
 		inode->i_fop = &befs_dir_operations;
@@ -539,7 +553,7 @@
 	wchar_t uni;
 	int unilen, utflen;
 	char *result;
-	int maxlen = in_len; /* The utf8->nls conversion cant make more chars */
+	int maxlen = in_len;	/* The utf8->nls conversion cant make more chars */
 
 	befs_debug(sb, "---> utf2nls()");
 
@@ -661,6 +675,37 @@
 	return -EILSEQ;
 }
 
+/****Xattr****/
+
+static ssize_t
+befs_listxattr(struct dentry *dentry, char *buffer, size_t size)
+{
+	printk(KERN_ERR "befs_listxattr called\n");
+	return 0;
+}
+
+static ssize_t
+befs_getxattr(struct dentry *dentry, const char *name,
+	      void *buffer, size_t size)
+{
+	return 0;
+}
+
+static int
+befs_setxattr(struct dentry *dentry, const char *name,
+	      void *value, size_t size, int flags)
+{
+	return 0;
+}
+
+static int
+befs_removexattr(struct dentry *dentry, const char *name)
+{
+	return 0;
+}
+
+/****Superblock****/
+
 static int
 parse_options(char *options, befs_mount_options * opts)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/super.c linux-2.4.21/fs/befs/super.c
--- linux-2.4.20/fs/befs/super.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/befs/super.c	2002-12-18 18:58:07.000000000 +0000
@@ -9,7 +9,8 @@
 
 #include <linux/fs.h>
 
-#include "befs_fs.h"
+#include "befs.h"
+#include "super.h"
 #include "endian.h"
 
 /**
@@ -25,8 +26,11 @@
 {
 	befs_sb_info *befs_sb = BEFS_SB(sb);
 
-	/* byte_order is special, no byte-swap */
-	befs_sb->byte_order = disk_sb->fs_byte_order;
+	/* Check the byte order of the filesystem */
+	if (le32_to_cpu(disk_sb->fs_byte_order) == BEFS_BYTEORDER_NATIVE)
+		befs_sb->byte_order = BEFS_BYTESEX_LE;
+	else if (be32_to_cpu(disk_sb->fs_byte_order) == BEFS_BYTEORDER_NATIVE)
+		befs_sb->byte_order = BEFS_BYTESEX_BE;
 
 	befs_sb->magic1 = fs32_to_cpu(sb, disk_sb->magic1);
 	befs_sb->magic2 = fs32_to_cpu(sb, disk_sb->magic2);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/super.h linux-2.4.21/fs/befs/super.h
--- linux-2.4.20/fs/befs/super.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/fs/befs/super.h	2002-12-18 18:58:06.000000000 +0000
@@ -0,0 +1,7 @@
+/*
+ * super.h
+ */
+
+int befs_load_sb(struct super_block *sb, befs_super_block * disk_sb);
+
+int befs_check_sb(struct super_block *sb);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/buffer.c linux-2.4.21/fs/buffer.c
--- linux-2.4.20/fs/buffer.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/buffer.c	2002-12-18 18:58:09.000000000 +0000
@@ -328,6 +328,8 @@
 	if (sb->s_dirt && sb->s_op && sb->s_op->write_super)
 		sb->s_op->write_super(sb);
 	unlock_super(sb);
+	if (sb->s_op && sb->s_op->sync_fs)
+		sb->s_op->sync_fs(sb);
 	unlock_kernel();
 
 	return sync_buffers(dev, 1);
@@ -346,7 +348,7 @@
 	lock_kernel();
 	sync_inodes(dev);
 	DQUOT_SYNC(dev);
-	sync_supers(dev);
+	sync_supers(dev, 1);
 	unlock_kernel();
 
 	return sync_buffers(dev, 1);
@@ -583,37 +585,29 @@
 	return bh;
 }
 
-void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
+void buffer_insert_list(struct buffer_head *bh, struct list_head *list)
 {
 	spin_lock(&lru_list_lock);
-	if (bh->b_inode)
+	if (buffer_attached(bh))
 		list_del(&bh->b_inode_buffers);
-	bh->b_inode = inode;
-	list_add(&bh->b_inode_buffers, &inode->i_dirty_buffers);
+	set_buffer_attached(bh);
+	list_add(&bh->b_inode_buffers, list);
 	spin_unlock(&lru_list_lock);
 }
 
-void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode)
-{
-	spin_lock(&lru_list_lock);
-	if (bh->b_inode)
-		list_del(&bh->b_inode_buffers);
-	bh->b_inode = inode;
-	list_add(&bh->b_inode_buffers, &inode->i_dirty_data_buffers);
-	spin_unlock(&lru_list_lock);
-}
-
-/* The caller must have the lru_list lock before calling the 
-   remove_inode_queue functions.  */
+/*
+ * The caller must have the lru_list lock before calling the 
+ * remove_inode_queue functions.
+ */
 static void __remove_inode_queue(struct buffer_head *bh)
 {
-	bh->b_inode = NULL;
 	list_del(&bh->b_inode_buffers);
+	clear_buffer_attached(bh);
 }
 
 static inline void remove_inode_queue(struct buffer_head *bh)
 {
-	if (bh->b_inode)
+	if (buffer_attached(bh))
 		__remove_inode_queue(bh);
 }
 
@@ -695,13 +689,13 @@
 			/* All buffers in the lru lists are mapped */
 			if (!buffer_mapped(bh))
 				BUG();
-			if (buffer_dirty(bh))
+			if (buffer_dirty(bh) && destroy_dirty_buffers)
 				printk("invalidate: dirty buffer\n");
 			if (!atomic_read(&bh->b_count)) {
 				if (destroy_dirty_buffers || !buffer_dirty(bh)) {
 					remove_inode_queue(bh);
 				}
-			} else
+			} else if (!bdev->bd_openers)
 				printk("invalidate: busy buffer\n");
 
 			write_unlock(&hash_table_lock);
@@ -831,10 +825,10 @@
 int fsync_buffers_list(struct list_head *list)
 {
 	struct buffer_head *bh;
-	struct inode tmp;
+	struct list_head tmp;
 	int err = 0, err2;
 	
-	INIT_LIST_HEAD(&tmp.i_dirty_buffers);
+	INIT_LIST_HEAD(&tmp);
 	
 	spin_lock(&lru_list_lock);
 
@@ -842,10 +836,10 @@
 		bh = BH_ENTRY(list->next);
 		list_del(&bh->b_inode_buffers);
 		if (!buffer_dirty(bh) && !buffer_locked(bh))
-			bh->b_inode = NULL;
+			clear_buffer_attached(bh);
 		else {
-			bh->b_inode = &tmp;
-			list_add(&bh->b_inode_buffers, &tmp.i_dirty_buffers);
+			set_buffer_attached(bh);
+			list_add(&bh->b_inode_buffers, &tmp);
 			if (buffer_dirty(bh)) {
 				get_bh(bh);
 				spin_unlock(&lru_list_lock);
@@ -865,8 +859,8 @@
 		}
 	}
 
-	while (!list_empty(&tmp.i_dirty_buffers)) {
-		bh = BH_ENTRY(tmp.i_dirty_buffers.prev);
+	while (!list_empty(&tmp)) {
+		bh = BH_ENTRY(tmp.prev);
 		remove_inode_queue(bh);
 		get_bh(bh);
 		spin_unlock(&lru_list_lock);
@@ -1138,7 +1132,7 @@
  */
 static void __put_unused_buffer_head(struct buffer_head * bh)
 {
-	if (bh->b_inode)
+	if (unlikely(buffer_attached(bh)))
 		BUG();
 	if (nr_unused_buffer_heads >= MAX_UNUSED_BUFFERS) {
 		kmem_cache_free(bh_cachep, bh);
@@ -2833,7 +2827,7 @@
 {
 	lock_kernel();
 	sync_unlocked_inodes();
-	sync_supers(0);
+	sync_supers(0, 0);
 	unlock_kernel();
 
 	for (;;) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/ext3/inode.c linux-2.4.21/fs/ext3/inode.c
--- linux-2.4.20/fs/ext3/inode.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/ext3/inode.c	2002-12-18 18:58:10.000000000 +0000
@@ -2270,7 +2270,7 @@
 			}
 		}
 	}
-	raw_inode->i_generation = le32_to_cpu(inode->i_generation);
+	raw_inode->i_generation = cpu_to_le32(inode->i_generation);
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
 		raw_inode->i_block[0] =
 			cpu_to_le32(kdev_t_to_nr(inode->i_rdev));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/ext3/namei.c linux-2.4.21/fs/ext3/namei.c
--- linux-2.4.20/fs/ext3/namei.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/ext3/namei.c	2002-12-18 18:58:02.000000000 +0000
@@ -429,8 +429,11 @@
 {
 	int err = ext3_add_entry(handle, dentry, inode);
 	if (!err) {
-		d_instantiate(dentry, inode);
-		return 0;
+		err = ext3_mark_inode_dirty(handle, inode);
+		if (err == 0) {
+			d_instantiate(dentry, inode);
+			return 0;
+		}
 	}
 	ext3_dec_count(handle, inode);
 	iput(inode);
@@ -465,7 +468,6 @@
 		inode->i_fop = &ext3_file_operations;
 		inode->i_mapping->a_ops = &ext3_aops;
 		err = ext3_add_nondir(handle, dentry, inode);
-		ext3_mark_inode_dirty(handle, inode);
 	}
 	ext3_journal_stop(handle, dir);
 	return err;
@@ -490,7 +492,6 @@
 	if (!IS_ERR(inode)) {
 		init_special_inode(inode, mode, rdev);
 		err = ext3_add_nondir(handle, dentry, inode);
-		ext3_mark_inode_dirty(handle, inode);
 	}
 	ext3_journal_stop(handle, dir);
 	return err;
@@ -934,7 +935,6 @@
 	}
 	inode->u.ext3_i.i_disksize = inode->i_size;
 	err = ext3_add_nondir(handle, dentry, inode);
-	ext3_mark_inode_dirty(handle, inode);
 out_stop:
 	ext3_journal_stop(handle, dir);
 	return err;
@@ -971,7 +971,6 @@
 	atomic_inc(&inode->i_count);
 
 	err = ext3_add_nondir(handle, dentry, inode);
-	ext3_mark_inode_dirty(handle, inode);
 	ext3_journal_stop(handle, dir);
 	return err;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/ext3/super.c linux-2.4.21/fs/ext3/super.c
--- linux-2.4.20/fs/ext3/super.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/ext3/super.c	2002-12-18 18:58:11.000000000 +0000
@@ -47,6 +47,8 @@
 static void ext3_clear_journal_err(struct super_block * sb,
 				   struct ext3_super_block * es);
 
+static int ext3_sync_fs(struct super_block * sb);
+
 #ifdef CONFIG_JBD_DEBUG
 int journal_no_write[2];
 
@@ -454,6 +456,7 @@
 	delete_inode:	ext3_delete_inode,	/* BKL not held.  We take it */
 	put_super:	ext3_put_super,		/* BKL held */
 	write_super:	ext3_write_super,	/* BKL held */
+	sync_fs:	ext3_sync_fs,
 	write_super_lockfs: ext3_write_super_lockfs, /* BKL not held. Take it */
 	unlockfs:	ext3_unlockfs,		/* BKL not held.  We take it */
 	statfs:		ext3_statfs,		/* BKL held */
@@ -1577,24 +1580,22 @@
  * This implicitly triggers the writebehind on sync().
  */
 
-static int do_sync_supers = 0;
-MODULE_PARM(do_sync_supers, "i");
-MODULE_PARM_DESC(do_sync_supers, "Write superblocks synchronously");
-
 void ext3_write_super (struct super_block * sb)
 {
+	if (down_trylock(&sb->s_lock) == 0)
+		BUG();
+	sb->s_dirt = 0;
+	log_start_commit(EXT3_SB(sb)->s_journal, NULL);
+}
+
+static int ext3_sync_fs(struct super_block *sb)
+{
 	tid_t target;
 	
-	if (down_trylock(&sb->s_lock) == 0)
-		BUG();		/* aviro detector */
 	sb->s_dirt = 0;
 	target = log_start_commit(EXT3_SB(sb)->s_journal, NULL);
-
-	if (do_sync_supers) {
-		unlock_super(sb);
-		log_wait_commit(EXT3_SB(sb)->s_journal, target);
-		lock_super(sb);
-	}
+	log_wait_commit(EXT3_SB(sb)->s_journal, target);
+	return 0;
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/inode.c linux-2.4.21/fs/inode.c
--- linux-2.4.20/fs/inode.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/fs/inode.c	2002-12-18 18:58:12.000000000 +0000
@@ -75,13 +75,59 @@
 
 static kmem_cache_t * inode_cachep;
 
-#define alloc_inode() \
-	 ((struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL))
+static struct inode *alloc_inode(struct super_block *sb)
+{
+	static struct address_space_operations empty_aops;
+	static struct inode_operations empty_iops;
+	static struct file_operations empty_fops;
+	struct inode *inode;
+
+	if (sb->s_op->alloc_inode)
+		inode = sb->s_op->alloc_inode(sb);
+	else {
+		inode = (struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL);
+		/* will die */
+		if (inode)
+			memset(&inode->u, 0, sizeof(inode->u));
+	}
+
+	if (inode) {
+		struct address_space * const mapping = &inode->i_data;
+
+		inode->i_sb = sb;
+		inode->i_dev = sb->s_dev;
+		inode->i_blkbits = sb->s_blocksize_bits;
+		inode->i_flags = 0;
+		atomic_set(&inode->i_count, 1);
+		inode->i_sock = 0;
+		inode->i_op = &empty_iops;
+		inode->i_fop = &empty_fops;
+		inode->i_nlink = 1;
+		atomic_set(&inode->i_writecount, 0);
+		inode->i_size = 0;
+		inode->i_blocks = 0;
+		inode->i_generation = 0;
+		memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
+		inode->i_pipe = NULL;
+		inode->i_bdev = NULL;
+		inode->i_cdev = NULL;
+
+		mapping->a_ops = &empty_aops;
+		mapping->host = inode;
+		mapping->gfp_mask = GFP_HIGHUSER;
+		inode->i_mapping = mapping;
+	}
+	return inode;
+}
+
 static void destroy_inode(struct inode *inode) 
 {
 	if (inode_has_buffers(inode))
 		BUG();
-	kmem_cache_free(inode_cachep, (inode));
+	if (inode->i_sb->s_op->destroy_inode)
+		inode->i_sb->s_op->destroy_inode(inode);
+	else
+		kmem_cache_free(inode_cachep, inode);
 }
 
 
@@ -90,27 +136,30 @@
  * once, because the fields are idempotent across use
  * of the inode, so let the slab aware of that.
  */
+void inode_init_once(struct inode *inode)
+{
+	memset(inode, 0, sizeof(*inode));
+	init_waitqueue_head(&inode->i_wait);
+	INIT_LIST_HEAD(&inode->i_hash);
+	INIT_LIST_HEAD(&inode->i_data.clean_pages);
+	INIT_LIST_HEAD(&inode->i_data.dirty_pages);
+	INIT_LIST_HEAD(&inode->i_data.locked_pages);
+	INIT_LIST_HEAD(&inode->i_dentry);
+	INIT_LIST_HEAD(&inode->i_dirty_buffers);
+	INIT_LIST_HEAD(&inode->i_dirty_data_buffers);
+	INIT_LIST_HEAD(&inode->i_devices);
+	sema_init(&inode->i_sem, 1);
+	sema_init(&inode->i_zombie, 1);
+	spin_lock_init(&inode->i_data.i_shared_lock);
+}
+
 static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
 {
 	struct inode * inode = (struct inode *) foo;
 
 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
 	    SLAB_CTOR_CONSTRUCTOR)
-	{
-		memset(inode, 0, sizeof(*inode));
-		init_waitqueue_head(&inode->i_wait);
-		INIT_LIST_HEAD(&inode->i_hash);
-		INIT_LIST_HEAD(&inode->i_data.clean_pages);
-		INIT_LIST_HEAD(&inode->i_data.dirty_pages);
-		INIT_LIST_HEAD(&inode->i_data.locked_pages);
-		INIT_LIST_HEAD(&inode->i_dentry);
-		INIT_LIST_HEAD(&inode->i_dirty_buffers);
-		INIT_LIST_HEAD(&inode->i_dirty_data_buffers);
-		INIT_LIST_HEAD(&inode->i_devices);
-		sema_init(&inode->i_sem, 1);
-		sema_init(&inode->i_zombie, 1);
-		spin_lock_init(&inode->i_data.i_shared_lock);
-	}
+		inode_init_once(inode);
 }
 
 /*
@@ -757,72 +806,28 @@
 	return inode;
 }
 
-/*
- * This just initializes the inode fields
- * to known values before returning the inode..
- *
- * i_sb, i_ino, i_count, i_state and the lists have
- * been initialized elsewhere..
- */
-static void clean_inode(struct inode *inode)
-{
-	static struct address_space_operations empty_aops;
-	static struct inode_operations empty_iops;
-	static struct file_operations empty_fops;
-	memset(&inode->u, 0, sizeof(inode->u));
-	inode->i_sock = 0;
-	inode->i_op = &empty_iops;
-	inode->i_fop = &empty_fops;
-	inode->i_nlink = 1;
-	atomic_set(&inode->i_writecount, 0);
-	inode->i_size = 0;
-	inode->i_blocks = 0;
-	inode->i_generation = 0;
-	memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
-	inode->i_pipe = NULL;
-	inode->i_bdev = NULL;
-	inode->i_cdev = NULL;
-	inode->i_data.a_ops = &empty_aops;
-	inode->i_data.host = inode;
-	inode->i_data.gfp_mask = GFP_HIGHUSER;
-	inode->i_mapping = &inode->i_data;
-}
-
 /**
- * get_empty_inode 	- obtain an inode
- *
- * This is called by things like the networking layer
- * etc that want to get an inode without any inode
- * number, or filesystems that allocate new inodes with
- * no pre-existing information.
+ *	new_inode 	- obtain an inode
+ *	@sb: superblock
  *
- * On a successful return the inode pointer is returned. On a failure
- * a %NULL pointer is returned. The returned inode is not on any superblock
- * lists.
+ *	Allocates a new inode for given superblock.
  */
  
-struct inode * get_empty_inode(void)
+struct inode * new_inode(struct super_block *sb)
 {
 	static unsigned long last_ino;
 	struct inode * inode;
 
 	spin_lock_prefetch(&inode_lock);
 	
-	inode = alloc_inode();
-	if (inode)
-	{
+	inode = alloc_inode(sb);
+	if (inode) {
 		spin_lock(&inode_lock);
 		inodes_stat.nr_inodes++;
 		list_add(&inode->i_list, &inode_in_use);
-		inode->i_sb = NULL;
-		inode->i_dev = 0;
-		inode->i_blkbits = 0;
 		inode->i_ino = ++last_ino;
-		inode->i_flags = 0;
-		atomic_set(&inode->i_count, 1);
 		inode->i_state = 0;
 		spin_unlock(&inode_lock);
-		clean_inode(inode);
 	}
 	return inode;
 }
@@ -837,7 +842,7 @@
 {
 	struct inode * inode;
 
-	inode = alloc_inode();
+	inode = alloc_inode(sb);
 	if (inode) {
 		struct inode * old;
 
@@ -848,17 +853,10 @@
 			inodes_stat.nr_inodes++;
 			list_add(&inode->i_list, &inode_in_use);
 			list_add(&inode->i_hash, head);
-			inode->i_sb = sb;
-			inode->i_dev = sb->s_dev;
-			inode->i_blkbits = sb->s_blocksize_bits;
 			inode->i_ino = ino;
-			inode->i_flags = 0;
-			atomic_set(&inode->i_count, 1);
 			inode->i_state = I_LOCK;
 			spin_unlock(&inode_lock);
 
-			clean_inode(inode);
-
 			/* reiserfs specific hack right here.  We don't
 			** want this to last, and are looking for VFS changes
 			** that will allow us to get rid of it.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/file.c linux-2.4.21/fs/jfs/file.c
--- linux-2.4.20/fs/jfs/file.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/jfs/file.c	2002-12-18 18:58:09.000000000 +0000
@@ -26,6 +26,7 @@
 
 
 extern int jfs_commit_inode(struct inode *, int);
+extern void jfs_truncate(struct inode *);
 
 int jfs_fsync(struct file *file, struct dentry *dentry, int datasync)
 {
@@ -44,59 +45,6 @@
 	return rc ? -EIO : 0;
 }
 
-/*
- * Guts of jfs_truncate.  Called with locks already held.  Can be called
- * with directory for truncating directory index table.
- */
-void jfs_truncate_nolock(struct inode *ip, loff_t length)
-{
-	loff_t newsize;
-	tid_t tid;
-
-	ASSERT(length >= 0);
-
-	if (test_cflag(COMMIT_Nolink, ip)) {
-		xtTruncate(0, ip, length, COMMIT_WMAP);
-		return;
-	}
-
-	do {
-		tid = txBegin(ip->i_sb, 0);
-
-		/*
-		 * The commit_sem cannot be taken before txBegin.
-		 * txBegin may block and there is a chance the inode
-		 * could be marked dirty and need to be committed
-		 * before txBegin unblocks
-		 */
-		down(&JFS_IP(ip)->commit_sem);
-
-		newsize = xtTruncate(tid, ip, length,
-				     COMMIT_TRUNCATE | COMMIT_PWMAP);
-		if (newsize < 0) {
-			txEnd(tid);
-			up(&JFS_IP(ip)->commit_sem);
-			break;
-		}
-
-		ip->i_mtime = ip->i_ctime = CURRENT_TIME;
-		mark_inode_dirty(ip);
-
-		txCommit(tid, 1, &ip, 0);
-		txEnd(tid);
-		up(&JFS_IP(ip)->commit_sem);
-	} while (newsize > length);	/* Truncate isn't always atomic */
-}
-
-static void jfs_truncate(struct inode *ip)
-{
-	jFYI(1, ("jfs_truncate: size = 0x%lx\n", (ulong) ip->i_size));
-
-	IWRITE_LOCK(ip);
-	jfs_truncate_nolock(ip, ip->i_size);
-	IWRITE_UNLOCK(ip);
-}
-
 static int jfs_open(struct inode *inode, struct file *file)
 {
 	int rc;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/inode.c linux-2.4.21/fs/jfs/inode.c
--- linux-2.4.20/fs/jfs/inode.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/jfs/inode.c	2002-12-18 18:58:06.000000000 +0000
@@ -39,6 +39,13 @@
 {
 	struct jfs_inode_info *ji = JFS_IP(inode);
 
+	if (is_bad_inode(inode))
+		/*
+		 * We free the fs-dependent structure before making the
+		 * inode bad
+		 */
+		return;
+
 	jFYI(1, ("jfs_clear_inode called ip = 0x%p\n", inode));
 
 	if (ji->active_ag != -1) {
@@ -48,7 +55,6 @@
 		       inode->i_ino, inode->i_mode);
 	}
 
-	ASSERT(list_empty(&ji->mp_list));
 	ASSERT(list_empty(&ji->anon_inode_list));
 
 	if (ji->atlhead) {
@@ -85,7 +91,7 @@
 		inode->i_mapping->a_ops = &jfs_aops;
 		inode->i_mapping->gfp_mask = GFP_NOFS;
 	} else if (S_ISLNK(inode->i_mode)) {
-		if (inode->i_size > IDATASIZE) {
+		if (inode->i_size >= IDATASIZE) {
 			inode->i_op = &page_symlink_inode_operations;
 			inode->i_mapping->a_ops = &jfs_aops;
 		} else
@@ -339,3 +345,58 @@
 	.bmap		= jfs_bmap,
 	.direct_IO	= jfs_direct_IO,
 };
+
+/*
+ * Guts of jfs_truncate.  Called with locks already held.  Can be called
+ * with directory for truncating directory index table.
+ */
+void jfs_truncate_nolock(struct inode *ip, loff_t length)
+{
+	loff_t newsize;
+	tid_t tid;
+
+	ASSERT(length >= 0);
+
+	if (test_cflag(COMMIT_Nolink, ip)) {
+		xtTruncate(0, ip, length, COMMIT_WMAP);
+		return;
+	}
+
+	do {
+		tid = txBegin(ip->i_sb, 0);
+
+		/*
+		 * The commit_sem cannot be taken before txBegin.
+		 * txBegin may block and there is a chance the inode
+		 * could be marked dirty and need to be committed
+		 * before txBegin unblocks
+		 */
+		down(&JFS_IP(ip)->commit_sem);
+
+		newsize = xtTruncate(tid, ip, length,
+				     COMMIT_TRUNCATE | COMMIT_PWMAP);
+		if (newsize < 0) {
+			txEnd(tid);
+			up(&JFS_IP(ip)->commit_sem);
+			break;
+		}
+
+		ip->i_mtime = ip->i_ctime = CURRENT_TIME;
+		mark_inode_dirty(ip);
+
+		txCommit(tid, 1, &ip, 0);
+		txEnd(tid);
+		up(&JFS_IP(ip)->commit_sem);
+	} while (newsize > length);	/* Truncate isn't always atomic */
+}
+
+void jfs_truncate(struct inode *ip)
+{
+	jFYI(1, ("jfs_truncate: size = 0x%lx\n", (ulong) ip->i_size));
+
+	block_truncate_page(ip->i_mapping, ip->i_size, jfs_get_block);
+
+	IWRITE_LOCK(ip);
+	jfs_truncate_nolock(ip, ip->i_size);
+	IWRITE_UNLOCK(ip);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_debug.c linux-2.4.21/fs/jfs/jfs_debug.c
--- linux-2.4.20/fs/jfs/jfs_debug.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/jfs/jfs_debug.c	2002-12-18 18:58:07.000000000 +0000
@@ -100,6 +100,7 @@
 
 #ifdef CONFIG_JFS_STATISTICS
 extern read_proc_t jfs_lmstats_read;
+extern read_proc_t jfs_txstats_read;
 extern read_proc_t jfs_xtstat_read;
 extern read_proc_t jfs_mpstat_read;
 #endif
@@ -111,6 +112,7 @@
 } Entries[] = {
 #ifdef CONFIG_JFS_STATISTICS
 	{ "lmstats",	jfs_lmstats_read, },
+	{ "txstats",	jfs_txstats_read, },
 	{ "xtstat",	jfs_xtstat_read, },
 	{ "mpstat",	jfs_mpstat_read, },
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_dtree.c linux-2.4.21/fs/jfs/jfs_dtree.c
--- linux-2.4.20/fs/jfs/jfs_dtree.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/jfs/jfs_dtree.c	2002-12-18 18:58:11.000000000 +0000
@@ -200,6 +200,28 @@
 #define ciToUpper(c)	UniStrupr((c)->name)
 
 /*
+ *	read_index_page()
+ *
+ *	Reads a page of a directory's index table.
+ *	Having metadata mapped into the directory inode's address space
+ *	presents a multitude of problems.  We avoid this by mapping to
+ *	the absolute address space outside of the *_metapage routines
+ */
+static struct metapage *read_index_page(struct inode *inode, s64 blkno)
+{
+	int rc;
+	s64 xaddr;
+	int xflag;
+	s32 xlen;
+
+	rc = xtLookup(inode, blkno, 1, &xflag, &xaddr, &xlen, 1);
+	if (rc || (xlen == 0))
+		return NULL;
+
+	return read_metapage(inode, xaddr, PSIZE, 1);
+}
+
+/*
  *	find_index()
  *
  *	Returns dtree page containing directory table entry for specified
@@ -208,7 +230,7 @@
  *	mp must be released by caller.
  */
 static struct dir_table_slot *find_index(struct inode *ip, u32 index,
-					 struct metapage ** mp)
+					 struct metapage ** mp, s64 *lblock)
 {
 	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
 	s64 blkno;
@@ -243,12 +265,14 @@
 		blkno = ((offset + 1) >> L2PSIZE) <<
 		    JFS_SBI(ip->i_sb)->l2nbperpage;
 
-		if (*mp && ((*mp)->index != blkno)) {
+		if (*mp && (*lblock != blkno)) {
 			release_metapage(*mp);
 			*mp = 0;
 		}
-		if (*mp == 0)
-			*mp = read_metapage(ip, blkno, PSIZE, 0);
+		if (*mp == 0) {
+			*lblock = blkno;
+			*mp = read_index_page(ip, blkno);
+		}
 		if (*mp == 0) {
 			jERROR(1,
 			       ("free_index: error reading directory table\n"));
@@ -368,7 +392,7 @@
 		ip->i_size = PSIZE;
 		ip->i_blocks += LBLK2PBLK(sb, sbi->nbperpage);
 
-		if ((mp = get_metapage(ip, 0, ip->i_blksize, 0)) == 0) {
+		if ((mp = read_index_page(ip, 0)) == 0) {
 			jERROR(1, ("add_index: get_metapage failed!\n"));
 			xtTruncate(tid, ip, 0, COMMIT_PWMAP);
 			return -1;
@@ -411,12 +435,12 @@
 		ip->i_size += PSIZE;
 		ip->i_blocks += LBLK2PBLK(sb, sbi->nbperpage);
 
-		if ((mp = get_metapage(ip, blkno, PSIZE, 0)))
+		if ((mp = read_index_page(ip, blkno)))
 			memset(mp->data, 0, PSIZE);	/* Just looks better */
 		else
 			xtTruncate(tid, ip, offset, COMMIT_PWMAP);
 	} else
-		mp = read_metapage(ip, blkno, PSIZE, 0);
+		mp = read_index_page(ip, blkno);
 
 	if (mp == 0) {
 		jERROR(1, ("add_index: get/read_metapage failed!\n"));
@@ -445,9 +469,10 @@
 static void free_index(tid_t tid, struct inode *ip, u32 index, u32 next)
 {
 	struct dir_table_slot *dirtab_slot;
+	s64 lblock;
 	struct metapage *mp = 0;
 
-	dirtab_slot = find_index(ip, index, &mp);
+	dirtab_slot = find_index(ip, index, &mp, &lblock);
 
 	if (dirtab_slot == 0)
 		return;
@@ -470,11 +495,11 @@
  *	Changes an entry in the directory index table
  */
 static void modify_index(tid_t tid, struct inode *ip, u32 index, s64 bn,
-			 int slot, struct metapage ** mp)
+			 int slot, struct metapage ** mp, u64 *lblock)
 {
 	struct dir_table_slot *dirtab_slot;
 
-	dirtab_slot = find_index(ip, index, mp);
+	dirtab_slot = find_index(ip, index, mp, lblock);
 
 	if (dirtab_slot == 0)
 		return;
@@ -497,10 +522,11 @@
 static int read_index(struct inode *ip, u32 index,
 		     struct dir_table_slot * dirtab_slot)
 {
+	s64 lblock;
 	struct metapage *mp = 0;
 	struct dir_table_slot *slot;
 
-	slot = find_index(ip, index, &mp);
+	slot = find_index(ip, index, &mp, &lblock);
 	if (slot == 0) {
 		return -EIO;
 	}
@@ -1491,12 +1517,14 @@
 	 * Update directory index table for entries now in right page
 	 */
 	if ((rp->header.flag & BT_LEAF) && DO_INDEX(ip)) {
+		s64 lblock;
+
 		mp = 0;
 		stbl = DT_GETSTBL(rp);
 		for (n = 0; n < rp->header.nextindex; n++) {
 			ldtentry = (struct ldtentry *) & rp->slot[stbl[n]];
 			modify_index(tid, ip, le32_to_cpu(ldtentry->index),
-				     rbn, n, &mp);
+				     rbn, n, &mp, &lblock);
 		}
 		if (mp)
 			release_metapage(mp);
@@ -1616,6 +1644,8 @@
 		 * Update directory index table to reflect new page address
 		 */
 		if (DO_INDEX(ip)) {
+			s64 lblock;
+
 			mp = 0;
 			stbl = DT_GETSTBL(sp);
 			for (n = 0; n < sp->header.nextindex; n++) {
@@ -1623,7 +1653,7 @@
 				    (struct ldtentry *) & sp->slot[stbl[n]];
 				modify_index(tid, ip,
 					     le32_to_cpu(ldtentry->index),
-					     xaddr, n, &mp);
+					     xaddr, n, &mp, &lblock);
 			}
 			if (mp)
 				release_metapage(mp);
@@ -1911,6 +1941,7 @@
 	 * Update directory index table for entries now in right page
 	 */
 	if ((rp->header.flag & BT_LEAF) && DO_INDEX(ip)) {
+		s64 lblock;
 		struct metapage *mp = 0;
 		struct ldtentry *ldtentry;
 
@@ -1918,7 +1949,7 @@
 		for (n = 0; n < rp->header.nextindex; n++) {
 			ldtentry = (struct ldtentry *) & rp->slot[stbl[n]];
 			modify_index(tid, ip, le32_to_cpu(ldtentry->index),
-				     rbn, n, &mp);
+				     rbn, n, &mp, &lblock);
 		}
 		if (mp)
 			release_metapage(mp);
@@ -2120,6 +2151,8 @@
 		 * Update directory index table for entries moved in stbl
 		 */
 		if (DO_INDEX(ip) && index < p->header.nextindex) {
+			s64 lblock;
+
 			imp = 0;
 			stbl = DT_GETSTBL(p);
 			for (i = index; i < p->header.nextindex; i++) {
@@ -2127,7 +2160,7 @@
 				    (struct ldtentry *) & p->slot[stbl[i]];
 				modify_index(tid, ip,
 					     le32_to_cpu(ldtentry->index),
-					     bn, i, &imp);
+					     bn, i, &imp, &lblock);
 			}
 			if (imp)
 				release_metapage(imp);
@@ -2769,12 +2802,6 @@
 			set_cflag(COMMIT_Stale, ip);
 
 			tblk->xflag = xflag_save;
-			/*
-			 * Tells jfs_metapage code that the metadata pages
-			 * for the index table are no longer useful, and
-			 * remove them from page cache.
-			 */
-			invalidate_inode_metapages(ip);
 		} else
 			ip->i_size = 1;
 
@@ -3919,6 +3946,8 @@
 		memmove(stbl + index + 1, stbl + index, nextindex - index);
 
 		if ((p->header.flag & BT_LEAF) && data->leaf.ip) {
+			s64 lblock;
+
 			/*
 			 * Need to update slot number for entries that moved
 			 * in the stbl
@@ -3928,7 +3957,7 @@
 				lh = (struct ldtentry *) & (p->slot[stbl[n]]);
 				modify_index(data->leaf.tid, data->leaf.ip,
 					     le32_to_cpu(lh->index), bn, n,
-					     &mp);
+					     &mp, &lblock);
 			}
 			if (mp)
 				release_metapage(mp);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_imap.c linux-2.4.21/fs/jfs/jfs_imap.c
--- linux-2.4.20/fs/jfs/jfs_imap.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/jfs/jfs_imap.c	2002-12-18 18:58:08.000000000 +0000
@@ -1175,7 +1175,7 @@
 	 * invalidate any page of the inode extent freed from buffer cache;
 	 */
 	freepxd = iagp->inoext[extno];
-	invalidate_pxd_metapages(ip->i_sb->s_bdev->bd_inode, freepxd);
+	invalidate_pxd_metapages(ip, freepxd);
 
 	/*
 	 *      update iag list(s) (careful update step 2)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_incore.h linux-2.4.21/fs/jfs/jfs_incore.h
--- linux-2.4.20/fs/jfs/jfs_incore.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/jfs/jfs_incore.h	2002-12-18 18:58:04.000000000 +0000
@@ -55,7 +55,6 @@
 	lid_t	atlhead;	/* anonymous tlock list head	*/
 	lid_t	atltail;	/* anonymous tlock list tail	*/
 	struct list_head anon_inode_list; /* inodes having anonymous txns */
-	struct list_head mp_list; /* metapages in inode's address space */
 	/*
 	 * rdwrlock serializes xtree between reads & writes and synchronizes
 	 * changes to special inodes.  It's use would be redundant on
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_logmgr.c linux-2.4.21/fs/jfs/jfs_logmgr.c
--- linux-2.4.20/fs/jfs/jfs_logmgr.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/jfs/jfs_logmgr.c	2002-12-18 18:58:08.000000000 +0000
@@ -196,6 +196,8 @@
 	uint commit;		/* # of commit */
 	uint pagedone;		/* # of page written */
 	uint submitted;		/* # of pages submitted */
+	uint full_page;		/* # of full pages submitted */
+	uint partial_page;	/* # of partial pages submitted */
 } lmStat;
 #endif
 
@@ -597,21 +599,21 @@
 		/* mark tblk for end-of-page */
 		tblk->flag |= tblkGC_EOP;
 
-		/* if page is not already on write queue,
-		 * just enqueue (no lbmWRITE to prevent redrive)
-		 * buffer to wqueue to ensure correct serial order
-		 * of the pages since log pages will be added
-		 * continuously (tblk bound with the page hasn't
-		 * got around to init write of the page, either
-		 * preempted or the page got filled by its COMMIT
-		 * record);
-		 * pages with COMMIT are paged out explicitly by
-		 * tblk in lmGroupCommit();
-		 */
-		if (bp->l_wqnext == NULL) {
-			/* bp->l_ceor = bp->l_eor; */
-			/* lp->h.eor = lp->t.eor = bp->l_ceor; */
-			lbmWrite(log, bp, 0, 0);
+		if (log->cflag & logGC_PAGEOUT) {
+			/* if page is not already on write queue,
+			 * just enqueue (no lbmWRITE to prevent redrive)
+			 * buffer to wqueue to ensure correct serial order
+			 * of the pages since log pages will be added
+			 * continuously
+			 */
+			if (bp->l_wqnext == NULL)
+				lbmWrite(log, bp, 0, 0);
+		} else {
+			/*
+			 * No current GC leader, initiate group commit
+			 */
+			log->cflag |= logGC_PAGEOUT;
+			lmGCwrite(log, 0);
 		}
 	}
 	/* page is not bound with outstanding tblk:
@@ -678,10 +680,17 @@
 		LOGGC_UNLOCK(log);
 		return rc;
 	}
-	jFYI(1,
-	     ("lmGroup Commit: tblk = 0x%p, gcrtc = %d\n", tblk,
-	      log->gcrtc));
+	jFYI(1, ("lmGroup Commit: tblk = 0x%p, gcrtc = %d\n", tblk,
+		 log->gcrtc));
 
+	if (tblk->xflag & COMMIT_LAZY) {
+		/*
+		 * Lazy transactions can leave now
+		 */
+		tblk->flag |= tblkGC_LAZY;
+		LOGGC_UNLOCK(log);
+		return 0;
+	}
 	/*
 	 * group commit pageout in progress
 	 */
@@ -709,12 +718,6 @@
 	/* upcount transaction waiting for completion
 	 */
 	log->gcrtc++;
-
-	if (tblk->xflag & COMMIT_LAZY) {
-		tblk->flag |= tblkGC_LAZY;
-		LOGGC_UNLOCK(log);
-		return 0;
-	}
 	tblk->flag |= tblkGC_READY;
 
 	__SLEEP_COND(tblk->gcwait, (tblk->flag & tblkGC_COMMITTED),
@@ -785,6 +788,7 @@
 			bp->l_ceor));
 		lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmGC,
 			 cant_write);
+		INCREMENT(lmStat.full_page);
 	}
 	/* page is not yet full */
 	else {
@@ -794,6 +798,7 @@
 		       ("gc: tclsn:0x%x, bceor:0x%x\n", tblk->clsn,
 			bp->l_ceor));
 		lbmWrite(log, bp, lbmWRITE | lbmGC, cant_write);
+		INCREMENT(lmStat.partial_page);
 	}
 }
 
@@ -881,11 +886,15 @@
 
 	/* are there any transactions who have entered lnGroupCommit()
 	 * (whose COMMITs are after that of the last log page written.
-	 * They are waiting for new group commit (above at (SLEEP 1)):
+	 * They are waiting for new group commit (above at (SLEEP 1))
+	 * or lazy transactions are on a full (queued) log page,
 	 * select the latest ready transaction as new group leader and
 	 * wake her up to lead her group.
 	 */
-	if ((log->gcrtc > 0) && log->cqueue.head)
+	if ((tblk = log->cqueue.head) &&
+	    ((log->gcrtc > 0) || (tblk->bp->l_wqnext != NULL) ||
+	     test_bit(log_SYNCBARRIER, &log->flag) ||
+	     test_bit(log_QUIESCE, &log->flag)))
 		/*
 		 * Call lmGCwrite with new group leader
 		 */
@@ -1039,6 +1048,16 @@
 			 log->syncpt));
 	}
 
+	/*
+	 * We may have to initiate group commit
+	 */
+	LOGGC_LOCK(log);
+	if (log->cqueue.head && !(log->cflag & logGC_PAGEOUT)) {
+		log->cflag |= logGC_PAGEOUT;
+		lmGCwrite(log, 0);
+	}
+	LOGGC_UNLOCK(log);
+
 	return lsn;
 }
 
@@ -1399,6 +1418,22 @@
 
 	jFYI(1, ("lmLogWait: log:0x%p\n", log));
 
+	/*
+	 * This ensures that we will keep writing to the journal as long
+	 * as there are unwritten commit records
+	 */
+	set_bit(log_QUIESCE, &log->flag);
+
+	/*
+	 * Initiate I/O on outstanding transactions
+	 */
+	LOGGC_LOCK(log);
+	if (log->cqueue.head && !(log->cflag & logGC_PAGEOUT)) {
+		log->cflag |= logGC_PAGEOUT;
+		lmGCwrite(log, 0);
+	}
+	LOGGC_UNLOCK(log);
+
 	if (log->cqueue.head || !list_empty(&log->synclist)) {
 		/*
 		 * If there was very recent activity, we may need to wait
@@ -1415,6 +1450,8 @@
 	}
 	assert(log->cqueue.head == NULL);
 	assert(list_empty(&log->synclist));
+
+	clear_bit(log_QUIESCE, &log->flag);	/* Probably not needed */
 }
 
 /*
@@ -2288,10 +2325,14 @@
 		       "================\n"
 		       "commits = %d\n"
 		       "writes submitted = %d\n"
-		       "writes completed = %d\n",
+		       "writes completed = %d\n"
+		       "full pages submitted = %d\n"
+		       "partial pages submitted = %d\n",
 		       lmStat.commit,
 		       lmStat.submitted,
-		       lmStat.pagedone);
+		       lmStat.pagedone,
+		       lmStat.full_page,
+		       lmStat.partial_page);
 
 	begin = offset;
 	*start = buffer + begin;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_metapage.c linux-2.4.21/fs/jfs/jfs_metapage.c
--- linux-2.4.20/fs/jfs/jfs_metapage.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/jfs/jfs_metapage.c	2002-12-18 18:58:10.000000000 +0000
@@ -352,8 +352,6 @@
 		mp->page = 0;
 		mp->logical_size = size;
 		add_to_hash(mp, hash_ptr);
-		if (!absolute)
-			list_add(&mp->inode_list, &JFS_IP(inode)->mp_list);
 		spin_unlock(&meta_lock);
 
 		if (new) {
@@ -363,8 +361,10 @@
 			if (!mp->page) {
 				jERROR(1, ("grab_cache_page failed!\n"));
 				goto freeit;
-			} else
+			} else {
 				INCREMENT(mpStat.pagealloc);
+				UnlockPage(mp->page);
+			}
 		} else {
 			jFYI(1,
 			     ("__get_metapage: Calling read_cache_page\n"));
@@ -375,7 +375,6 @@
 				goto freeit;
 			} else
 				INCREMENT(mpStat.pagealloc);
-			lock_page(mp->page);
 		}
 		mp->data = kmap(mp->page) + page_offset;
 	}
@@ -385,8 +384,6 @@
 freeit:
 	spin_lock(&meta_lock);
 	remove_from_hash(mp, hash_ptr);
-	if (!absolute)
-		list_del(&mp->inode_list);
 	__free_metapage(mp);
 	spin_unlock(&meta_lock);
 	return NULL;
@@ -430,12 +427,14 @@
 	page_offset =
 	    (mp->index - (page_index << l2BlocksPerPage)) << l2bsize;
 
+	lock_page(mp->page);
 	rc = mp->mapping->a_ops->prepare_write(NULL, mp->page, page_offset,
 					       page_offset +
 					       mp->logical_size);
 	if (rc) {
 		jERROR(1, ("prepare_write return %d!\n", rc));
 		ClearPageUptodate(mp->page);
+		UnlockPage(mp->page);
 		kunmap(mp->page);
 		clear_bit(META_dirty, &mp->flag);
 		return;
@@ -447,6 +446,7 @@
 		jERROR(1, ("commit_write returned %d\n", rc));
 	}
 
+	UnlockPage(mp->page);
 	clear_bit(META_dirty, &mp->flag);
 
 	jFYI(1, ("__write_metapage done\n"));
@@ -491,8 +491,6 @@
 		spin_unlock(&meta_lock);
 	} else {
 		remove_from_hash(mp, meta_hash(mp->mapping, mp->index));
-		if (!test_bit(META_absolute, &mp->flag))
-			list_del(&mp->inode_list);
 		spin_unlock(&meta_lock);
 
 		if (mp->page) {
@@ -500,7 +498,6 @@
 			mp->data = 0;
 			if (test_bit(META_dirty, &mp->flag))
 				__write_metapage(mp);
-			UnlockPage(mp->page);
 			if (test_bit(META_sync, &mp->flag)) {
 				sync_metapage(mp);
 				clear_bit(META_sync, &mp->flag);
@@ -509,7 +506,7 @@
 			if (test_bit(META_discard, &mp->flag)) {
 				lock_page(mp->page);
 				block_flushpage(mp->page, 0);
-				unlock_page(mp->page);
+				UnlockPage(mp->page);
 			}
 
 			page_cache_release(mp->page);
@@ -540,7 +537,8 @@
 	struct metapage **hash_ptr;
 	unsigned long lblock;
 	int l2BlocksPerPage = PAGE_CACHE_SHIFT - ip->i_blkbits;
-	struct address_space *mapping = ip->i_mapping;
+	/* All callers are interested in block device's mapping */
+	struct address_space *mapping = ip->i_sb->s_bdev->bd_inode->i_mapping;
 	struct metapage *mp;
 	struct page *page;
 
@@ -556,10 +554,9 @@
 		if (mp) {
 			set_bit(META_discard, &mp->flag);
 			spin_unlock(&meta_lock);
-			/*
-			 * If in the metapage cache, we've got the page locked
-			 */
+			lock_page(mp->page);
 			block_flushpage(mp->page, 0);
+			UnlockPage(mp->page);
 		} else {
 			spin_unlock(&meta_lock);
 			page = find_lock_page(mapping, lblock>>l2BlocksPerPage);
@@ -571,27 +568,6 @@
 	}
 }
 
-void invalidate_inode_metapages(struct inode *inode)
-{
-	struct list_head *ptr;
-	struct metapage *mp;
-
-	spin_lock(&meta_lock);
-	list_for_each(ptr, &JFS_IP(inode)->mp_list) {
-		mp = list_entry(ptr, struct metapage, inode_list);
-		clear_bit(META_dirty, &mp->flag);
-		set_bit(META_discard, &mp->flag);
-		kunmap(mp->page);
-		UnlockPage(mp->page);
-		page_cache_release(mp->page);
-		INCREMENT(mpStat.pagefree);
-		mp->data = 0;
-		mp->page = 0;
-	}
-	spin_unlock(&meta_lock);
-	truncate_inode_pages(inode->i_mapping, 0);
-}
-
 #ifdef CONFIG_JFS_STATISTICS
 int jfs_mpstat_read(char *buffer, char **start, off_t offset, int length,
 		    int *eof, void *data)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_metapage.h linux-2.4.21/fs/jfs/jfs_metapage.h
--- linux-2.4.20/fs/jfs/jfs_metapage.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/jfs/jfs_metapage.h	2002-12-18 18:58:06.000000000 +0000
@@ -38,7 +38,6 @@
 	struct metapage *hash_prev;
 	struct metapage *hash_next;	/* Also used for free list */
 
-	struct list_head inode_list;	/* per-inode metapage list */
 	/*
 	 * mapping & index become redundant, but we need these here to
 	 * add the metapage to the hash before we have the real page
@@ -109,9 +108,7 @@
 	__invalidate_metapages((ip), addressPXD(&(pxd)), lengthPXD(&(pxd)))
 #define invalidate_dxd_metapages(ip, dxd) \
 	__invalidate_metapages((ip), addressDXD(&(dxd)), lengthDXD(&(dxd)))
+#define invalidate_xad_metapages(ip, xad) \
+	__invalidate_metapages((ip), addressXAD(&(xad)), lengthXAD(&(xad)))
 
-/*
- * This one uses mp_list to invalidate all pages for an inode
- */
-extern void invalidate_inode_metapages(struct inode *inode);
 #endif				/* _H_JFS_METAPAGE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_txnmgr.c linux-2.4.21/fs/jfs/jfs_txnmgr.c
--- linux-2.4.20/fs/jfs/jfs_txnmgr.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/jfs/jfs_txnmgr.c	2002-12-18 18:58:05.000000000 +0000
@@ -69,6 +69,7 @@
 	wait_queue_head_t freelockwait;	/* eventlist of free tlock */
 	wait_queue_head_t lowlockwait;	/* eventlist of ample tlocks */
 	int tlocksInUse;	/* Number of tlocks in use */
+	int TlocksLow;		/* Indicates low number of available tlocks */
 	spinlock_t LazyLock;	/* synchronize sync_queue & unlock_queue */
 /*	struct tblock *sync_queue; * Transactions waiting for data sync */
 	struct tblock *unlock_queue;	/* Txns waiting to be released */
@@ -78,6 +79,20 @@
 					   that couldn't be sync'ed */
 } TxAnchor;
 
+#ifdef CONFIG_JFS_STATISTICS
+struct {
+	uint txBegin;
+	uint txBegin_barrier;
+	uint txBegin_lockslow;
+	uint txBegin_freetid;
+	uint txBeginAnon;
+	uint txBeginAnon_barrier;
+	uint txBeginAnon_lockslow;
+	uint txLockAlloc;
+	uint txLockAlloc_freelock;
+} TxStat;
+#endif
+
 static int nTxBlock = 512;	/* number of transaction blocks */
 struct tblock *TxBlock;	        /* transaction block table */
 
@@ -85,7 +100,6 @@
 static int TxLockLWM = 4096*.4;	/* Low water mark for number of txLocks used */
 static int TxLockHWM = 4096*.8;	/* High water mark for number of txLocks used */
 struct tlock *TxLock;           /* transaction lock table */
-static int TlocksLow = 0;	/* Indicates low number of available tlocks */
 
 
 /*
@@ -142,7 +156,8 @@
 /*
  * external references
  */
-extern int lmGroupCommit(struct jfs_log * log, struct tblock * tblk);
+extern int lmGroupCommit(struct jfs_log *, struct tblock *);
+extern int lmGCwrite(struct jfs_log *, int);
 extern void lmSync(struct jfs_log *);
 extern int jfs_commit_inode(struct inode *, int);
 extern int jfs_stop_threads;
@@ -189,13 +204,18 @@
 {
 	lid_t lid;
 
+	INCREMENT(TxStat.txLockAlloc);
+	if (!TxAnchor.freelock) {
+		INCREMENT(TxStat.txLockAlloc_freelock);
+	}
+
 	while (!(lid = TxAnchor.freelock))
 		TXN_SLEEP(&TxAnchor.freelockwait);
 	TxAnchor.freelock = TxLock[lid].next;
 	HIGHWATERMARK(stattx.maxlid, lid);
-	if ((++TxAnchor.tlocksInUse > TxLockHWM) && (TlocksLow == 0)) {
+	if ((++TxAnchor.tlocksInUse > TxLockHWM) && (TxAnchor.TlocksLow == 0)) {
 		jEVENT(0,("txLockAlloc TlocksLow\n"));
-		TlocksLow = 1;
+		TxAnchor.TlocksLow = 1;
 		wake_up(&jfs_sync_thread_wait);
 	}
 
@@ -207,9 +227,9 @@
 	TxLock[lid].next = TxAnchor.freelock;
 	TxAnchor.freelock = lid;
 	TxAnchor.tlocksInUse--;
-	if (TlocksLow && (TxAnchor.tlocksInUse < TxLockLWM)) {
+	if (TxAnchor.TlocksLow && (TxAnchor.tlocksInUse < TxLockLWM)) {
 		jEVENT(0,("txLockFree TlocksLow no more\n"));
-		TlocksLow = 0;
+		TxAnchor.TlocksLow = 0;
 		TXN_WAKEUP(&TxAnchor.lowlockwait);
 	}
 	TXN_WAKEUP(&TxAnchor.freelockwait);
@@ -321,6 +341,8 @@
 
 	TXN_LOCK();
 
+	INCREMENT(TxStat.txBegin);
+
       retry:
 	if (!(flag & COMMIT_FORCE)) {
 		/*
@@ -328,6 +350,7 @@
 		 */
 		if (test_bit(log_SYNCBARRIER, &log->flag) ||
 		    test_bit(log_QUIESCE, &log->flag)) {
+			INCREMENT(TxStat.txBegin_barrier);
 			TXN_SLEEP(&log->syncwait);
 			goto retry;
 		}
@@ -338,7 +361,8 @@
 		 * unless COMMIT_FORCE or COMMIT_INODE (which may ultimately
 		 * free tlocks)
 		 */
-		if (TlocksLow) {
+		if (TxAnchor.TlocksLow) {
+			INCREMENT(TxStat.txBegin_lockslow);
 			TXN_SLEEP(&TxAnchor.lowlockwait);
 			goto retry;
 		}
@@ -349,6 +373,7 @@
 	 */
 	if ((t = TxAnchor.freetid) == 0) {
 		jFYI(1, ("txBegin: waiting for free tid\n"));
+		INCREMENT(TxStat.txBegin_freetid);
 		TXN_SLEEP(&TxAnchor.freewait);
 		goto retry;
 	}
@@ -358,6 +383,7 @@
 	if ((tblk->next == 0) && (current != jfsCommitTask)) {
 		/* Save one tblk for jfsCommit thread */
 		jFYI(1, ("txBegin: waiting for free tid\n"));
+		INCREMENT(TxStat.txBegin_freetid);
 		TXN_SLEEP(&TxAnchor.freewait);
 		goto retry;
 	}
@@ -411,6 +437,7 @@
 	log = JFS_SBI(sb)->log;
 
 	TXN_LOCK();
+	INCREMENT(TxStat.txBeginAnon);
 
       retry:
 	/*
@@ -418,6 +445,7 @@
 	 */
 	if (test_bit(log_SYNCBARRIER, &log->flag) ||
 	    test_bit(log_QUIESCE, &log->flag)) {
+		INCREMENT(TxStat.txBeginAnon_barrier);
 		TXN_SLEEP(&log->syncwait);
 		goto retry;
 	}
@@ -425,7 +453,8 @@
 	/*
 	 * Don't begin transaction if we're getting starved for tlocks
 	 */
-	if (TlocksLow) {
+	if (TxAnchor.TlocksLow) {
+		INCREMENT(TxStat.txBeginAnon_lockslow);
 		TXN_SLEEP(&TxAnchor.lowlockwait);
 		goto retry;
 	}
@@ -1473,10 +1502,6 @@
 {
 	struct metapage *mp;
 	pxd_t *pxd;
-	int rc;
-	s64 xaddr;
-	int xflag;
-	s32 xlen;
 
 	mp = tlck->mp;
 
@@ -1501,13 +1526,7 @@
 		return 0;
 	}
 
-	rc = xtLookup(tlck->ip, mp->index, 1, &xflag, &xaddr, &xlen, 1);
-	if (rc || (xlen == 0)) {
-		jERROR(1, ("dataLog: can't find physical address\n"));
-		return 0;
-	}
-
-	PXDaddress(pxd, xaddr);
+	PXDaddress(pxd, mp->index);
 	PXDlength(pxd, mp->logical_size >> tblk->sb->s_blocksize_bits);
 
 	lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
@@ -2197,9 +2216,21 @@
 				tlck->flag &= ~tlckWRITEPAGE;
 
 				/* do not release page to freelist */
+
+				/*
+				 * The "right" thing to do here is to
+				 * synchronously write the metadata.
+				 * With the current implementation this
+				 * is hard since write_metapage requires
+				 * us to kunmap & remap the page.  If we
+				 * have tlocks pointing into the metadata
+				 * pages, we don't want to do this.  I think
+				 * we can get by with synchronously writing
+				 * the pages when they are released.
+				 */
 				assert(atomic_read(&mp->nohomeok));
-				hold_metapage(mp, 0);
-				write_metapage(mp);
+				set_bit(META_dirty, &mp->flag);
+				set_bit(META_sync, &mp->flag);
 			}
 		}
 	}
@@ -2727,7 +2758,7 @@
 
 	tblk->flag |= tblkGC_COMMITTED;
 
-	if ((tblk->flag & tblkGC_READY) || (tblk->flag & tblkGC_LAZY))
+	if (tblk->flag & tblkGC_READY)
 		log->gcrtc--;
 
 	if (tblk->flag & tblkGC_READY)
@@ -2929,6 +2960,16 @@
 		goto restart;
 	}
 	TXN_UNLOCK();
+
+	/*
+	 * We may need to kick off the group commit
+	 */
+	spin_lock_irq(&log->gclock);	// LOGGC_LOCK
+	if (log->cqueue.head && !(log->cflag & logGC_PAGEOUT)) {
+		log->cflag |= logGC_PAGEOUT;
+		lmGCwrite(log, 0);
+	}
+	spin_unlock_irq(&log->gclock);	// LOGGC_UNLOCK
 }
 
 /*
@@ -2979,7 +3020,7 @@
 		 * write each inode on the anonymous inode list
 		 */
 		TXN_LOCK();
-		while (TlocksLow && !list_empty(&TxAnchor.anon_list)) {
+		while (TxAnchor.TlocksLow && !list_empty(&TxAnchor.anon_list)) {
 			jfs_ip = list_entry(TxAnchor.anon_list.next,
 					    struct jfs_inode_info,
 					    anon_inode_list);
@@ -3065,6 +3106,7 @@
 		       "freelockwait = %s\n"
 		       "lowlockwait = %s\n"
 		       "tlocksInUse = %d\n"
+		       "TlocksLow = %d\n"
 		       "unlock_queue = 0x%p\n"
 		       "unlock_tail = 0x%p\n",
 		       TxAnchor.freetid,
@@ -3073,6 +3115,7 @@
 		       freelockwait,
 		       lowlockwait,
 		       TxAnchor.tlocksInUse,
+		       TxAnchor.TlocksLow,
 		       TxAnchor.unlock_queue,
 		       TxAnchor.unlock_tail);
 
@@ -3091,3 +3134,48 @@
 	return len;
 }
 #endif
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_JFS_STATISTICS)
+int jfs_txstats_read(char *buffer, char **start, off_t offset, int length,
+		     int *eof, void *data)
+{
+	int len = 0;
+	off_t begin;
+
+	len += sprintf(buffer,
+		       "JFS TxStats\n"
+		       "===========\n"
+		       "calls to txBegin = %d\n"
+		       "txBegin blocked by sync barrier = %d\n"
+		       "txBegin blocked by tlocks low = %d\n"
+		       "txBegin blocked by no free tid = %d\n"
+		       "calls to txBeginAnon = %d\n"
+		       "txBeginAnon blocked by sync barrier = %d\n"
+		       "txBeginAnon blocked by tlocks low = %d\n"
+		       "calls to txLockAlloc = %d\n"
+		       "tLockAlloc blocked by no free lock = %d\n",
+		       TxStat.txBegin,
+		       TxStat.txBegin_barrier,
+		       TxStat.txBegin_lockslow,
+		       TxStat.txBegin_freetid,
+		       TxStat.txBeginAnon,
+		       TxStat.txBeginAnon_barrier,
+		       TxStat.txBeginAnon_lockslow,
+		       TxStat.txLockAlloc,
+		       TxStat.txLockAlloc_freelock);
+
+	begin = offset;
+	*start = buffer + begin;
+	len -= begin;
+
+	if (len > length)
+		len = length;
+	else
+		*eof = 1;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_xtree.c linux-2.4.21/fs/jfs/jfs_xtree.c
--- linux-2.4.20/fs/jfs/jfs_xtree.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/jfs/jfs_xtree.c	2002-12-18 18:58:12.000000000 +0000
@@ -3518,6 +3518,13 @@
 		xaddr = addressXAD(xad);
 
 		/*
+		 * The "data" for a directory is indexed by the block
+		 * device's address space.  This metadata must be invalidated
+		 * here
+		 */
+		if (S_ISDIR(ip->i_mode) && (teof == 0))
+			invalidate_xad_metapages(ip, *xad);
+		/*
 		 * entry beyond eof: continue scan of current page
 		 *          xad
 		 * ---|---=======------->
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/namei.c linux-2.4.21/fs/jfs/namei.c
--- linux-2.4.20/fs/jfs/namei.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/jfs/namei.c	2002-12-18 18:58:03.000000000 +0000
@@ -589,7 +589,7 @@
 		break;
 	case S_IFLNK:
 		/* fast symbolic link */
-		if (ip->i_size <= 256) {
+		if (ip->i_size < IDATASIZE) {
 			ip->i_size = 0;
 			return 0;
 		}
@@ -661,7 +661,7 @@
 		break;
 	case S_IFLNK:
 		/* if its contained in inode nothing to do */
-		if (ip->i_size <= 256)
+		if (ip->i_size < IDATASIZE)
 			return 0;
 		break;
 	default:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/super.c linux-2.4.21/fs/jfs/super.c
--- linux-2.4.20/fs/jfs/super.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/jfs/super.c	2002-12-18 18:58:09.000000000 +0000
@@ -374,7 +374,6 @@
 	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
 	    SLAB_CTOR_CONSTRUCTOR) {
 		INIT_LIST_HEAD(&jfs_ip->anon_inode_list);
-		INIT_LIST_HEAD(&jfs_ip->mp_list);
 		init_rwsem(&jfs_ip->rdwrlock);
 		init_MUTEX(&jfs_ip->commit_sem);
 		jfs_ip->atlhead = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/lockd/svc.c linux-2.4.21/fs/lockd/svc.c
--- linux-2.4.20/fs/lockd/svc.c	2001-10-21 17:32:33.000000000 +0000
+++ linux-2.4.21/fs/lockd/svc.c	2002-12-18 18:58:10.000000000 +0000
@@ -72,11 +72,6 @@
 	return grace_period + jiffies;
 }
 
-static inline void clear_grace_period(void)
-{
-	nlmsvc_grace_period = 0;
-}
-
 /*
  * This is the lockd kernel thread
  */
@@ -142,10 +137,8 @@
 		 * (Theoretically, there shouldn't even be blocked locks
 		 * during grace period).
 		 */
-		if (!nlmsvc_grace_period) {
+		if (!nlmsvc_grace_period)
 			timeout = nlmsvc_retry_blocked();
-		} else if (time_before(grace_period_expire, jiffies))
-			clear_grace_period();
 
 		/*
 		 * Find a socket with data available and call its
@@ -175,6 +168,9 @@
 				nlmsvc_ops->exp_getclient(&rqstp->rq_addr);
 		}
 
+		if (nlmsvc_grace_period &&
+		    time_before(grace_period_expire, jiffies))
+			nlmsvc_grace_period = 0;
 		svc_process(serv, rqstp);
 
 		/* Unlock export hash tables */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/locks.c linux-2.4.21/fs/locks.c
--- linux-2.4.20/fs/locks.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/locks.c	2002-12-18 18:58:07.000000000 +0000
@@ -274,9 +274,18 @@
 		return -EINVAL;
 	}
 
-	if (((start += l->l_start) < 0) || (l->l_len < 0))
+	/* POSIX-1996 leaves the case l->l_len < 0 undefined;
+	   POSIX-2001 defines it. */
+	start += l->l_start;
+	if (l->l_len < 0) {
+		end = start - 1;
+		start += l->l_len;
+	} else {
+		end = start + l->l_len - 1;
+	}
+
+	if (start < 0)
 		return -EINVAL;
-	end = start + l->l_len - 1;
 	if (l->l_len > 0 && end < 0)
 		return -EOVERFLOW;
 	fl->fl_start = start;	/* we record the absolute position */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/nfs/file.c linux-2.4.21/fs/nfs/file.c
--- linux-2.4.20/fs/nfs/file.c	2002-02-25 19:38:09.000000000 +0000
+++ linux-2.4.21/fs/nfs/file.c	2002-12-18 18:58:10.000000000 +0000
@@ -187,6 +187,7 @@
 	if (!inode)
 		return 0;
 
+	NFS_SetPageSync(page);
 	rpages = NFS_SERVER(inode)->rpages;
 	result = nfs_pagein_inode(inode, index, rpages);
 	if (result < 0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/nfs/read.c linux-2.4.21/fs/nfs/read.c
--- linux-2.4.20/fs/nfs/read.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/nfs/read.c	2002-12-18 18:58:01.000000000 +0000
@@ -171,11 +171,16 @@
 	struct nfs_page	*new;
 
 	new = nfs_create_request(nfs_file_cred(file), inode, page, 0, PAGE_CACHE_SIZE);
-	if (IS_ERR(new))
+	if (IS_ERR(new)) {
+		SetPageError(page);
+		NFS_ClearPageSync(page);
+		UnlockPage(page);
 		return PTR_ERR(new);
+	}
 	nfs_mark_request_read(new);
 
-	if (inode->u.nfs_i.nread >= NFS_SERVER(inode)->rpages ||
+	if (NFS_TestClearPageSync(page) ||
+	    inode->u.nfs_i.nread >= NFS_SERVER(inode)->rpages ||
 	    page_index(page) == (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT)
 		nfs_pagein_inode(inode, 0, 0);
 	return 0;
@@ -222,6 +227,7 @@
 		req = nfs_list_entry(head->next);
 		page = req->wb_page;
 		nfs_list_remove_request(req);
+		NFS_ClearPageSync(page);
 		SetPageError(page);
 		UnlockPage(page);
 		nfs_clear_request(req);
@@ -429,6 +435,7 @@
 		} else
 			SetPageError(page);
 		flush_dcache_page(page);
+		NFS_ClearPageSync(page);
 		UnlockPage(page);
 
 		dprintk("NFS: read (%x/%Ld %d@%Ld)\n",
@@ -482,6 +489,7 @@
 	return error;
 
 out_error:
+	NFS_ClearPageSync(page);
 	UnlockPage(page);
 	goto out;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/nfsd/nfs3proc.c linux-2.4.21/fs/nfsd/nfs3proc.c
--- linux-2.4.20/fs/nfsd/nfs3proc.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/nfsd/nfs3proc.c	2002-12-18 18:58:07.000000000 +0000
@@ -672,7 +672,7 @@
   PROC(setattr,  sattr,		wccstat,	fhandle,  RC_REPLBUFF, ST+WC),
   PROC(lookup,	 dirop,		dirop,		fhandle2, RC_NOCACHE, ST+FH+pAT+pAT),
   PROC(access,	 access,	access,		fhandle,  RC_NOCACHE, ST+pAT+1),
-  PROC(readlink, fhandle,	readlink,	fhandle,  RC_NOCACHE, ST+pAT+1+256),
+  PROC(readlink, fhandle,	readlink,	fhandle,  RC_NOCACHE, ST+pAT+1+NFS3_MAXPATHLEN/4),
   PROC(read,	 read,		read,		fhandle, RC_NOCACHE, ST+pAT+4+NFSSVC_MAXBLKSIZE),
   PROC(write,	 write,		write,		fhandle,  RC_REPLBUFF, ST+WC+4),
   PROC(create,	 create,	create,		fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC),
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/nfsd/nfsfh.c linux-2.4.21/fs/nfsd/nfsfh.c
--- linux-2.4.20/fs/nfsd/nfsfh.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/nfsd/nfsfh.c	2002-12-18 18:58:06.000000000 +0000
@@ -620,6 +620,13 @@
 			switch (fh->fh_fileid_type) {
 			case 0:
 				dentry = dget(exp->ex_dentry);
+				/* need to revalidate the inode */
+				inode = dentry->d_inode;
+				if (inode->i_op && inode->i_op->revalidate)
+					if (inode->i_op->revalidate(dentry)) {
+						dput(dentry);
+						dentry = ERR_PTR(-ESTALE);
+					}
 				break;
 			default:
 				dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
@@ -671,11 +678,16 @@
 
 	/* Type can be negative to e.g. exclude directories from linking */
 	if (type > 0 && (inode->i_mode & S_IFMT) != type) {
-		error = (type == S_IFDIR)? nfserr_notdir : nfserr_isdir;
+		if (type == S_IFDIR)
+			error = nfserr_notdir;
+		else if ((inode->i_mode & S_IFMT) == S_IFDIR)
+			error = nfserr_isdir;
+		else
+			error = nfserr_inval;
 		goto out;
 	}
 	if (type < 0 && (inode->i_mode & S_IFMT) == -type) {
-		error = (type == -S_IFDIR)? nfserr_notdir : nfserr_isdir;
+		error = (type == -S_IFDIR)? nfserr_isdir : nfserr_notdir;
 		goto out;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/nfsd/nfsproc.c linux-2.4.21/fs/nfsd/nfsproc.c
--- linux-2.4.20/fs/nfsd/nfsproc.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/nfsd/nfsproc.c	2002-12-18 18:58:06.000000000 +0000
@@ -545,7 +545,7 @@
   PROC(setattr,  sattrargs,	attrstat,	fhandle,	RC_REPLBUFF, ST+AT),
   PROC(none,	 void,		void,		none,		RC_NOCACHE, ST),
   PROC(lookup,	 diropargs,	diropres,	fhandle,	RC_NOCACHE, ST+FH+AT),
-  PROC(readlink, fhandle,	readlinkres,	none,		RC_NOCACHE, ST+1+256),
+  PROC(readlink, fhandle,	readlinkres,	none,		RC_NOCACHE, ST+1+NFS_MAXPATHLEN/4),
   PROC(read,	 readargs,	readres,	fhandle,	RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE),
   PROC(none,	 void,		void,		none,		RC_NOCACHE, ST),
   PROC(write,	 writeargs,	attrstat,	fhandle,	RC_REPLBUFF, ST+AT),
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/nfsd/nfsxdr.c linux-2.4.21/fs/nfsd/nfsxdr.c
--- linux-2.4.20/fs/nfsd/nfsxdr.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/nfsd/nfsxdr.c	2002-12-18 18:58:02.000000000 +0000
@@ -385,7 +385,7 @@
 {
 	struct statfs	*stat = &resp->stats;
 
-	*p++ = htonl(8 * 1024);		/* max transfer size */
+	*p++ = htonl(NFSSVC_MAXBLKSIZE);	/* max transfer size */
 	*p++ = htonl(stat->f_bsize);
 	*p++ = htonl(stat->f_blocks);
 	*p++ = htonl(stat->f_bfree);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/nfsd/vfs.c linux-2.4.21/fs/nfsd/vfs.c
--- linux-2.4.20/fs/nfsd/vfs.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/nfsd/vfs.c	2002-12-18 18:58:07.000000000 +0000
@@ -168,11 +168,13 @@
 			mntput(mnt);
 		}
 	}
-	/*
-	 * Note: we compose the file handle now, but as the
-	 * dentry may be negative, it may need to be updated.
-	 */
-	err = fh_compose(resfh, exp, dentry, fhp);
+
+	if (dentry->d_inode && dentry->d_inode->i_op &&
+	    dentry->d_inode->i_op->revalidate &&
+	    dentry->d_inode->i_op->revalidate(dentry))
+		err = nfserr_noent;
+	else
+		err = fh_compose(resfh, exp, dentry, fhp);
 	if (!err && !dentry->d_inode)
 		err = nfserr_noent;
 out:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/proc/generic.c linux-2.4.21/fs/proc/generic.c
--- linux-2.4.20/fs/proc/generic.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/fs/proc/generic.c	2002-12-18 18:58:12.000000000 +0000
@@ -456,7 +456,11 @@
 		ent->data = kmalloc((ent->size=strlen(dest))+1, GFP_KERNEL);
 		if (ent->data) {
 			strcpy((char*)ent->data,dest);
-			proc_register(parent, ent);
+			if (proc_register(parent, ent) < 0) {
+				kfree(ent->data);
+				kfree(ent);
+				ent = NULL;
+			}
 		} else {
 			kfree(ent);
 			ent = NULL;
@@ -473,7 +477,10 @@
 	ent = proc_create(&parent,name,mode,1);
 	if (ent) {
 		ent->rdev = rdev;
-		proc_register(parent, ent);
+		if (proc_register(parent, ent) < 0) {
+			kfree(ent);
+			ent = NULL;
+		}
 	}
 	return ent;
 }
@@ -488,7 +495,10 @@
 		ent->proc_fops = &proc_dir_operations;
 		ent->proc_iops = &proc_dir_inode_operations;
 
-		proc_register(parent, ent);
+		if (proc_register(parent, ent) < 0) {
+			kfree(ent);
+			ent = NULL;
+		}
 	}
 	return ent;
 }
@@ -517,7 +527,10 @@
 			ent->proc_fops = &proc_dir_operations;
 			ent->proc_iops = &proc_dir_inode_operations;
 		}
-		proc_register(parent, ent);
+		if (proc_register(parent, ent) < 0) {
+			kfree(ent);
+			ent = NULL;
+		}
 	}
 	return ent;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/read_write.c linux-2.4.21/fs/read_write.c
--- linux-2.4.20/fs/read_write.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/fs/read_write.c	2002-12-18 18:58:10.000000000 +0000
@@ -218,7 +218,7 @@
 	typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
 	typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
 
-	ssize_t tot_len;
+	size_t tot_len;
 	struct iovec iovstack[UIO_FASTIOV];
 	struct iovec *iov=iovstack;
 	ssize_t ret, i;
@@ -259,12 +259,19 @@
 	tot_len = 0;
 	ret = -EINVAL;
 	for (i = 0 ; i < count ; i++) {
-		ssize_t tmp = tot_len;
 		ssize_t len = (ssize_t) iov[i].iov_len;
 		if (len < 0)	/* size_t not fitting an ssize_t .. */
 			goto out;
 		tot_len += len;
-		if (tot_len < tmp) /* maths overflow on the ssize_t */
+		/* We must do this work unsigned - signed overflow is
+		   undefined and gcc 3.2 now uses that fact sometimes... 
+		   
+		   FIXME: put in a proper limits.h for each platform */
+#if BITS_PER_LONG==64
+		if (tot_len > 0x7FFFFFFFFFFFFFFFUL)
+#else
+		if (tot_len > 0x7FFFFFFFUL)
+#endif		
 			goto out;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/reiserfs/fix_node.c linux-2.4.21/fs/reiserfs/fix_node.c
--- linux-2.4.20/fs/reiserfs/fix_node.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/reiserfs/fix_node.c	2002-12-18 18:58:05.000000000 +0000
@@ -2059,7 +2059,7 @@
 	    /* getting memory with GFP_KERNEL priority may involve
                balancing now (due to indirect_to_direct conversion on
                dcache shrinking). So, release path and collected
-               resourses here */
+               resources here */
 	    free_buffers_in_tb (tb);
 	    buf = reiserfs_kmalloc(size, GFP_NOFS, tb->tb_sb);
 	    if ( !buf ) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/reiserfs/inode.c linux-2.4.21/fs/reiserfs/inode.c
--- linux-2.4.20/fs/reiserfs/inode.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/reiserfs/inode.c	2002-12-18 18:58:06.000000000 +0000
@@ -102,9 +102,9 @@
 }
 
 static void add_to_flushlist(struct inode *inode, struct buffer_head *bh) {
-    struct inode *jinode = &(SB_JOURNAL(inode->i_sb)->j_dummy_inode) ;
+    struct reiserfs_journal *j = SB_JOURNAL(inode->i_sb) ;
 
-    buffer_insert_inode_queue(bh, jinode) ;
+    buffer_insert_list(bh, &j->j_dirty_buffers) ;
 }
 
 //
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/reiserfs/journal.c linux-2.4.21/fs/reiserfs/journal.c
--- linux-2.4.20/fs/reiserfs/journal.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/reiserfs/journal.c	2002-12-18 18:58:10.000000000 +0000
@@ -1937,7 +1937,7 @@
   memset(journal_writers, 0, sizeof(char *) * 512) ; /* debug code */
 
   INIT_LIST_HEAD(&SB_JOURNAL(p_s_sb)->j_bitmap_nodes) ;
-  INIT_LIST_HEAD(&(SB_JOURNAL(p_s_sb)->j_dummy_inode.i_dirty_buffers)) ;
+  INIT_LIST_HEAD(&SB_JOURNAL(p_s_sb)->j_dirty_buffers) ;
   reiserfs_allocate_list_bitmaps(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_bitmap, 
                                  SB_BMAP_NR(p_s_sb)) ;
   allocate_bitmap_nodes(p_s_sb) ;
@@ -2933,7 +2933,7 @@
   SB_JOURNAL_LIST_INDEX(p_s_sb) = jindex ;
 
   /* write any buffers that must hit disk before this commit is done */
-  fsync_inode_buffers(&(SB_JOURNAL(p_s_sb)->j_dummy_inode)) ;
+  fsync_buffers_list(&(SB_JOURNAL(p_s_sb)->j_dirty_buffers)) ;
 
   /* honor the flush and async wishes from the caller */
   if (flush) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/select.c linux-2.4.21/fs/select.c
--- linux-2.4.20/fs/select.c	2001-09-10 20:04:33.000000000 +0000
+++ linux-2.4.21/fs/select.c	2002-12-18 18:58:02.000000000 +0000
@@ -417,7 +417,7 @@
 	int nchunks, nleft;
 
 	/* Do a sanity check on nfds ... */
-	if (nfds > NR_OPEN)
+	if (nfds > current->files->max_fdset && nfds > OPEN_MAX)
 		return -EINVAL;
 
 	if (timeout) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/super.c linux-2.4.21/fs/super.c
--- linux-2.4.20/fs/super.c	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/fs/super.c	2002-12-18 18:58:08.000000000 +0000
@@ -262,6 +262,7 @@
  */
 static struct super_block *alloc_super(void)
 {
+	static struct super_operations empty_sops = {};
 	struct super_block *s = kmalloc(sizeof(struct super_block),  GFP_USER);
 	if (s) {
 		memset(s, 0, sizeof(struct super_block));
@@ -279,6 +280,7 @@
 		sema_init(&s->s_dquot.dqio_sem, 1);
 		sema_init(&s->s_dquot.dqoff_sem, 1);
 		s->s_maxbytes = MAX_NON_LFS;
+		s->s_op = &empty_sops;
 	}
 	return s;
 }
@@ -445,7 +447,7 @@
  * hold up the sync while mounting a device. (The newly
  * mounted device won't need syncing.)
  */
-void sync_supers(kdev_t dev)
+void sync_supers(kdev_t dev, int wait)
 {
 	struct super_block * sb;
 
@@ -454,6 +456,8 @@
 		if (sb) {
 			if (sb->s_dirt)
 				write_super(sb);
+			if (wait && sb->s_op && sb->s_op->sync_fs)
+				sb->s_op->sync_fs(sb);
 			drop_super(sb);
 		}
 		return;
@@ -467,6 +471,8 @@
 			spin_unlock(&sb_lock);
 			down_read(&sb->s_umount);
 			write_super(sb);
+			if (wait && sb->s_op && sb->s_op->sync_fs)
+				sb->s_op->sync_fs(sb);
 			drop_super(sb);
 			goto restart;
 		} else
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/core_cia.h linux-2.4.21/include/asm-alpha/core_cia.h
--- linux-2.4.20/include/asm-alpha/core_cia.h	2001-11-09 21:45:35.000000000 +0000
+++ linux-2.4.21/include/asm-alpha/core_cia.h	2002-12-18 18:58:01.000000000 +0000
@@ -202,6 +202,10 @@
 #define CIA_IOC_PCI_W3_MASK		(IDENT_ADDR + 0x8760000740UL)
 #define CIA_IOC_PCI_T3_BASE		(IDENT_ADDR + 0x8760000780UL)
 
+#define CIA_IOC_PCI_Wn_BASE(N)	  (IDENT_ADDR + 0x8760000400UL + (N)*0x100)
+#define CIA_IOC_PCI_Wn_MASK(N)	  (IDENT_ADDR + 0x8760000440UL + (N)*0x100)
+#define CIA_IOC_PCI_Tn_BASE(N)	  (IDENT_ADDR + 0x8760000480UL + (N)*0x100)
+
 #define CIA_IOC_PCI_W_DAC		(IDENT_ADDR + 0x87600007C0UL)
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/core_t2.h linux-2.4.21/include/asm-alpha/core_t2.h
--- linux-2.4.20/include/asm-alpha/core_t2.h	2001-11-09 21:45:35.000000000 +0000
+++ linux-2.4.21/include/asm-alpha/core_t2.h	2002-12-18 18:58:09.000000000 +0000
@@ -19,7 +19,7 @@
  *
  */
 
-#define T2_MEM_R1_MASK 0x03ffffff  /* Mem sparse region 1 mask is 26 bits */
+#define T2_MEM_R1_MASK 0x07ffffff  /* Mem sparse region 1 mask is 26 bits */
 
 /* GAMMA-SABLE is a SABLE with EV5-based CPUs */
 #define _GAMMA_BIAS		0x8000000000UL
@@ -402,13 +402,17 @@
  *
  */
 
+#define t2_set_hae { \
+	msb = addr  >> 27; \
+	addr &= T2_MEM_R1_MASK; \
+	set_hae(msb); \
+}
+
 __EXTERN_INLINE u8 t2_readb(unsigned long addr)
 {
 	unsigned long result, msb;
 
-	msb = addr & 0xE0000000;
-	addr &= T2_MEM_R1_MASK;
-	set_hae(msb);
+	t2_set_hae;
 
 	result = *(vip) ((addr << 5) + T2_SPARSE_MEM + 0x00);
 	return __kernel_extbl(result, addr & 3);
@@ -418,9 +422,7 @@
 {
 	unsigned long result, msb;
 
-	msb = addr & 0xE0000000;
-	addr &= T2_MEM_R1_MASK;
-	set_hae(msb);
+	t2_set_hae;
 
 	result = *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08);
 	return __kernel_extwl(result, addr & 3);
@@ -431,9 +433,7 @@
 {
 	unsigned long msb;
 
-	msb = addr & 0xE0000000;
-	addr &= T2_MEM_R1_MASK;
-	set_hae(msb);
+	t2_set_hae;
 
 	return *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18);
 }
@@ -442,9 +442,7 @@
 {
 	unsigned long r0, r1, work, msb;
 
-	msb = addr & 0xE0000000;
-	addr &= T2_MEM_R1_MASK;
-	set_hae(msb);
+	t2_set_hae;
 
 	work = (addr << 5) + T2_SPARSE_MEM + 0x18;
 	r0 = *(vuip)(work);
@@ -456,9 +454,7 @@
 {
 	unsigned long msb, w;
 
-	msb = addr & 0xE0000000;
-	addr &= T2_MEM_R1_MASK;
-	set_hae(msb);
+	t2_set_hae;
 
 	w = __kernel_insbl(b, addr & 3);
 	*(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x00) = w;
@@ -468,9 +464,7 @@
 {
 	unsigned long msb, w;
 
-	msb = addr & 0xE0000000;
-	addr &= T2_MEM_R1_MASK;
-	set_hae(msb);
+	t2_set_hae;
 
 	w = __kernel_inswl(b, addr & 3);
 	*(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08) = w;
@@ -481,9 +475,7 @@
 {
 	unsigned long msb;
 
-	msb = addr & 0xE0000000;
-	addr &= T2_MEM_R1_MASK;
-	set_hae(msb);
+	t2_set_hae;
 
 	*(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18) = b;
 }
@@ -492,9 +484,7 @@
 {
 	unsigned long msb, work;
 
-	msb = addr & 0xE0000000;
-	addr &= T2_MEM_R1_MASK;
-	set_hae(msb);
+	t2_set_hae;
 
 	work = (addr << 5) + T2_SPARSE_MEM + 0x18;
 	*(vuip)work = b;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/dma.h linux-2.4.21/include/asm-alpha/dma.h
--- linux-2.4.20/include/asm-alpha/dma.h	1999-11-27 23:27:49.000000000 +0000
+++ linux-2.4.21/include/asm-alpha/dma.h	2002-12-18 18:58:06.000000000 +0000
@@ -75,34 +75,49 @@
 
 #define MAX_DMA_CHANNELS	8
 
-/* The maximum address that we can perform a DMA transfer to on Alpha XL,
-   due to a hardware SIO (PCI<->ISA bus bridge) chip limitation, is 64MB.
-   See <asm/apecs.h> for more info.
+/*
+  ISA DMA limitations on Alpha platforms,
+
+  These may be due to SIO (PCI<->ISA bridge) chipset limitation, or
+  just a wiring limit.
+*/
+
+/* The maximum address for ISA DMA transfer on Alpha XL, due to an
+   hardware SIO limitation, is 64MB.
 */
-/* The maximum address that we can perform a DMA transfer to on RUFFIAN,
-   due to a hardware SIO (PCI<->ISA bus bridge) chip limitation, is 16MB.
-   See <asm/pyxis.h> for more info.
+#define ALPHA_XL_MAX_DMA_ADDRESS	(IDENT_ADDR+0x04000000UL)
+
+/* The maximum address for ISA DMA transfer on RUFFIAN and NAUTILUS,
+   due to an hardware SIO limitation, is 16MB.
 */
-/* NOTE: we must define the maximum as something less than 64Mb, to prevent 
-   virt_to_bus() from returning an address in the first window, for a
-   data area that goes beyond the 64Mb first DMA window. Sigh...
-   We MUST coordinate the maximum with <asm/apecs.h> for consistency.
-   For now, this limit is set to 48Mb...
+#define ALPHA_RUFFIAN_MAX_DMA_ADDRESS	(IDENT_ADDR+0x01000000UL)
+#define ALPHA_NAUTILUS_MAX_DMA_ADDRESS	(IDENT_ADDR+0x01000000UL)
+
+/* The maximum address for ISA DMA transfer on SABLE, and some ALCORs,
+   due to an hardware SIO chip limitation, is 2GB.
+*/
+#define ALPHA_SABLE_MAX_DMA_ADDRESS	(IDENT_ADDR+0x80000000UL)
+#define ALPHA_ALCOR_MAX_DMA_ADDRESS	(IDENT_ADDR+0x80000000UL)
+
+/*
+  Maximum address for all the others is the complete 32-bit bus
+  address space.
 */
-#define ALPHA_XL_MAX_DMA_ADDRESS	(IDENT_ADDR+0x3000000UL)
-#define ALPHA_RUFFIAN_MAX_DMA_ADDRESS	(IDENT_ADDR+0x1000000UL)
-#define ALPHA_NAUTILUS_MAX_DMA_ADDRESS	(IDENT_ADDR+0x1000000UL)
-#define ALPHA_MAX_DMA_ADDRESS		(~0UL)
+#define ALPHA_MAX_DMA_ADDRESS		(IDENT_ADDR+0x100000000UL)
 
 #ifdef CONFIG_ALPHA_GENERIC
 # define MAX_DMA_ADDRESS		(alpha_mv.max_dma_address)
 #else
-# ifdef CONFIG_ALPHA_XL
+# if defined(CONFIG_ALPHA_XL)
 #  define MAX_DMA_ADDRESS		ALPHA_XL_MAX_DMA_ADDRESS
 # elif defined(CONFIG_ALPHA_RUFFIAN)
 #  define MAX_DMA_ADDRESS		ALPHA_RUFFIAN_MAX_DMA_ADDRESS
 # elif defined(CONFIG_ALPHA_NAUTILUS)
 #  define MAX_DMA_ADDRESS		ALPHA_NAUTILUS_MAX_DMA_ADDRESS
+# elif defined(CONFIG_ALPHA_SABLE)
+#  define MAX_DMA_ADDRESS		ALPHA_SABLE_MAX_DMA_ADDRESS
+# elif defined(CONFIG_ALPHA_ALCOR)
+#  define MAX_DMA_ADDRESS		ALPHA_ALCOR_MAX_DMA_ADDRESS
 # else
 #  define MAX_DMA_ADDRESS		ALPHA_MAX_DMA_ADDRESS
 # endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/floppy.h linux-2.4.21/include/asm-alpha/floppy.h
--- linux-2.4.20/include/asm-alpha/floppy.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-alpha/floppy.h	2002-12-18 18:58:11.000000000 +0000
@@ -92,25 +92,22 @@
 
 /*
  * Most Alphas have no problems with floppy DMA crossing 64k borders,
- * except for XL and RUFFIAN.  They are also the only one with DMA
- * limits, so we use that to test in the generic kernel.
+ * except for certain ones, like XL and RUFFIAN.
+ *
+ * However, the test is simple and fast, and this *is* floppy, after all,
+ * so we do it for all platforms, just to make sure.
+ *
+ * This is advantageous in other circumstances as well, as in moving
+ * about the PCI DMA windows and forcing the floppy to start doing
+ * scatter-gather when it never had before, and there *is* a problem
+ * on that platform... ;-}
  */
 
-#define __CROSS_64KB(a,s)					\
+#define CROSS_64KB(a,s)						\
 ({ unsigned long __s64 = (unsigned long)(a);			\
    unsigned long __e64 = __s64 + (unsigned long)(s) - 1;	\
    (__s64 ^ __e64) & ~0xfffful; })
 
-#ifdef CONFIG_ALPHA_GENERIC
-# define CROSS_64KB(a,s)   (__CROSS_64KB(a,s) && ~alpha_mv.max_dma_address)
-#else
-# if defined(CONFIG_ALPHA_XL) || defined(CONFIG_ALPHA_RUFFIAN) || defined(CONFIG_ALPHA_NAUTILUS)
-#  define CROSS_64KB(a,s)  __CROSS_64KB(a,s)
-# else
-#  define CROSS_64KB(a,s)  (0)
-# endif
-#endif
-
 #define EXTRA_FLOPPY_PARAMS
 
 #endif /* __ASM_ALPHA_FLOPPY_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/hdreg.h linux-2.4.21/include/asm-alpha/hdreg.h
--- linux-2.4.20/include/asm-alpha/hdreg.h	1999-05-13 18:00:08.000000000 +0000
+++ linux-2.4.21/include/asm-alpha/hdreg.h	2002-12-18 18:58:08.000000000 +0000
@@ -7,6 +7,7 @@
 #ifndef __ASMalpha_HDREG_H
 #define __ASMalpha_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+//typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASMalpha_HDREG_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/ide.h linux-2.4.21/include/asm-alpha/ide.h
--- linux-2.4.20/include/asm-alpha/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-alpha/ide.h	2002-12-18 18:58:06.000000000 +0000
@@ -19,8 +19,6 @@
 #define MAX_HWIFS	4
 #endif
 
-#define ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	switch (base) {
@@ -82,42 +80,7 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#define ide_check_region(from,extent)		check_region((from), (extent))
-#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
-#define ide_release_region(from,extent)		release_region((from), (extent))
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+#include <asm-generic/ide_iops.h>
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/mmu_context.h linux-2.4.21/include/asm-alpha/mmu_context.h
--- linux-2.4.20/include/asm-alpha/mmu_context.h	2000-12-29 22:07:23.000000000 +0000
+++ linux-2.4.21/include/asm-alpha/mmu_context.h	2002-12-18 18:58:09.000000000 +0000
@@ -32,7 +32,7 @@
 		"call_pal %2 #__reload_thread"
 		: "=r"(v0), "=r"(a0)
 		: "i"(PAL_swpctx), "r"(a0)
-		: "$1", "$16", "$22", "$23", "$24", "$25");
+		: "$1", "$22", "$23", "$24", "$25");
 
 	return v0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/mmzone.h linux-2.4.21/include/asm-alpha/mmzone.h
--- linux-2.4.20/include/asm-alpha/mmzone.h	2001-05-24 22:20:18.000000000 +0000
+++ linux-2.4.21/include/asm-alpha/mmzone.h	2002-12-18 18:58:06.000000000 +0000
@@ -86,7 +86,7 @@
 
 /*
  * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory
- * and returns the the mem_map of that node.
+ * and returns the mem_map of that node.
  */
 #define ADDR_TO_MAPBASE(kaddr) \
 			NODE_MEM_MAP(KVADDR_TO_NID((unsigned long)(kaddr)))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/regdef.h linux-2.4.21/include/asm-alpha/regdef.h
--- linux-2.4.20/include/asm-alpha/regdef.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/include/asm-alpha/regdef.h	2002-12-18 18:58:05.000000000 +0000
@@ -0,0 +1,44 @@
+#ifndef __alpha_regdef_h__
+#define __alpha_regdef_h__
+
+#define v0	$0	/* function return value */
+
+#define t0	$1	/* temporary registers (caller-saved) */
+#define t1	$2
+#define t2	$3
+#define t3	$4
+#define t4	$5
+#define t5	$6
+#define t6	$7
+#define t7	$8
+
+#define	s0	$9	/* saved-registers (callee-saved registers) */
+#define	s1	$10
+#define	s2	$11
+#define	s3	$12
+#define	s4	$13
+#define	s5	$14
+#define	s6	$15
+#define	fp	s6	/* frame-pointer (s6 in frame-less procedures) */
+
+#define a0	$16	/* argument registers (caller-saved) */
+#define a1	$17
+#define a2	$18
+#define a3	$19
+#define a4	$20
+#define a5	$21
+
+#define t8	$22	/* more temps (caller-saved) */
+#define t9	$23
+#define t10	$24
+#define t11	$25
+#define ra	$26	/* return address register */
+#define t12	$27
+
+#define pv	t12	/* procedure-variable register */
+#define AT	$at	/* assembler temporary */
+#define gp	$29	/* global pointer */
+#define sp	$30	/* stack pointer */
+#define zero	$31	/* reads as zero, writes are noops */
+
+#endif /* __alpha_regdef_h__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/system.h linux-2.4.21/include/asm-alpha/system.h
--- linux-2.4.20/include/asm-alpha/system.h	2001-10-05 01:47:08.000000000 +0000
+++ linux-2.4.21/include/asm-alpha/system.h	2002-12-18 18:58:02.000000000 +0000
@@ -309,9 +309,11 @@
 #define __sti()			do { barrier(); setipl(IPL_MIN); } while(0)
 #define __save_flags(flags)	((flags) = rdps())
 #define __save_and_cli(flags)	do { (flags) = swpipl(IPL_MAX); barrier(); } while(0)
+#define __save_and_sti(flags)	do { barrier(); (flags) = swpipl(IPL_MIN); } while(0)
 #define __restore_flags(flags)	do { barrier(); setipl(flags); barrier(); } while(0)
 
 #define local_irq_save(flags)		__save_and_cli(flags)
+#define local_irq_set(flags)            __save_and_sti(flags)
 #define local_irq_restore(flags)	__restore_flags(flags)
 #define local_irq_disable()		__cli()
 #define local_irq_enable()		__sti()
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/timex.h linux-2.4.21/include/asm-alpha/timex.h
--- linux-2.4.20/include/asm-alpha/timex.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-alpha/timex.h	2002-12-18 18:58:09.000000000 +0000
@@ -18,7 +18,6 @@
  */
 
 typedef unsigned int cycles_t;
-extern cycles_t cacheflush_time;
 
 static inline cycles_t get_cycles (void)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-arm/hdreg.h linux-2.4.21/include/asm-arm/hdreg.h
--- linux-2.4.20/include/asm-arm/hdreg.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-arm/hdreg.h	2002-12-18 18:58:08.000000000 +0000
@@ -7,7 +7,8 @@
 #ifndef __ASMARM_HDREG_H
 #define __ASMARM_HDREG_H
 
-typedef unsigned int ide_ioreg_t;
+//typedef unsigned int ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASMARM_HDREG_H */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-arm/ide.h linux-2.4.21/include/asm-arm/ide.h
--- linux-2.4.20/include/asm-arm/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-arm/ide.h	2002-12-18 18:58:07.000000000 +0000
@@ -17,47 +17,8 @@
 #define MAX_HWIFS	4
 #endif
 
-#define ide__sti()	__sti()
-
 #include <asm/arch/ide.h>
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#define ide_check_region(from,extent)		check_region((from), (extent))
-#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
-#define ide_release_region(from,extent)		release_region((from), (extent))
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
 /*
  * We always use the new IDE port registering,
  * so these are fixed here.
@@ -65,6 +26,8 @@
 #define ide_default_io_base(i)		((ide_ioreg_t)0)
 #define ide_default_irq(b)		(0)
 
+#include <asm-generic/ide_iops.h>
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASMARM_IDE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-arm/proc-armo/system.h linux-2.4.21/include/asm-arm/proc-armo/system.h
--- linux-2.4.20/include/asm-arm/proc-armo/system.h	2001-08-12 18:14:00.000000000 +0000
+++ linux-2.4.21/include/asm-arm/proc-armo/system.h	2002-12-18 18:58:06.000000000 +0000
@@ -127,4 +127,6 @@
 	  : "memory");					\
 	} while (0)
 
+#define __save_and_sti(x)	({__save_flags(x);__sti();})
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-arm/proc-armv/system.h linux-2.4.21/include/asm-arm/proc-armv/system.h
--- linux-2.4.20/include/asm-arm/proc-armv/system.h	2001-08-12 18:14:00.000000000 +0000
+++ linux-2.4.21/include/asm-arm/proc-armv/system.h	2002-12-18 18:58:02.000000000 +0000
@@ -141,6 +141,8 @@
 	: "r" (x)						\
 	: "memory")
 
+#define __save_and_sti(x)	({__save_flags(x);__sti();})
+
 #if defined(CONFIG_CPU_SA1100) || defined(CONFIG_CPU_SA110)
 /*
  * On the StrongARM, "swp" is terminally broken since it bypasses the
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-arm/system.h linux-2.4.21/include/asm-arm/system.h
--- linux-2.4.20/include/asm-arm/system.h	2000-11-28 01:07:59.000000000 +0000
+++ linux-2.4.21/include/asm-arm/system.h	2002-12-18 18:58:03.000000000 +0000
@@ -58,6 +58,7 @@
 
 /* For spinlocks etc */
 #define local_irq_save(x)	__save_flags_cli(x)
+#define local_irq_set(x)	__save_and_sti(x)
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
@@ -82,6 +83,8 @@
 #define save_flags(x)		__save_flags(x)
 #define restore_flags(x)	__restore_flags(x)
 #define save_flags_cli(x)	__save_flags_cli(x)
+#define save_and_cli(x)		__save_flags_cli(x)
+#define save_and_sti(x)		__save_flags_sti(x)
 
 #endif /* CONFIG_SMP */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/atomic.h linux-2.4.21/include/asm-cris/atomic.h
--- linux-2.4.20/include/asm-cris/atomic.h	2001-07-26 22:10:06.000000000 +0000
+++ linux-2.4.21/include/asm-cris/atomic.h	2002-12-18 18:58:01.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: atomic.h,v 1.3 2001/07/25 16:15:19 bjornw Exp $ */
+/* $Id: atomic.h,v 1.4 2002/11/20 18:20:17 hp Exp $ */
 
 #ifndef __ASM_CRIS_ATOMIC__
 #define __ASM_CRIS_ATOMIC__
@@ -27,7 +27,7 @@
 
 /* These should be written in asm but we do it in C for now. */
 
-static __inline__ void atomic_add(int i, volatile atomic_t *v)
+extern __inline__ void atomic_add(int i, volatile atomic_t *v)
 {
 	unsigned long flags;
 	save_flags(flags);
@@ -36,7 +36,7 @@
 	restore_flags(flags);
 }
 
-static __inline__ void atomic_sub(int i, volatile atomic_t *v)
+extern __inline__ void atomic_sub(int i, volatile atomic_t *v)
 {
 	unsigned long flags;
 	save_flags(flags);
@@ -45,7 +45,7 @@
 	restore_flags(flags);
 }
 
-static __inline__ int atomic_add_return(int i, volatile atomic_t *v)
+extern __inline__ int atomic_add_return(int i, volatile atomic_t *v)
 {
 	unsigned long flags;
 	int retval;
@@ -56,7 +56,7 @@
 	return retval;
 }
 
-static __inline__ int atomic_sub_return(int i, volatile atomic_t *v)
+extern __inline__ int atomic_sub_return(int i, volatile atomic_t *v)
 {
 	unsigned long flags;
 	int retval;
@@ -67,7 +67,7 @@
 	return retval;
 }
 
-static __inline__ int atomic_sub_and_test(int i, volatile atomic_t *v)
+extern __inline__ int atomic_sub_and_test(int i, volatile atomic_t *v)
 {
 	int retval;
 	unsigned long flags;
@@ -78,7 +78,7 @@
 	return retval;
 }
 
-static __inline__ void atomic_inc(volatile atomic_t *v)
+extern __inline__ void atomic_inc(volatile atomic_t *v)
 {
 	unsigned long flags;
 	save_flags(flags);
@@ -87,7 +87,7 @@
 	restore_flags(flags);
 }
 
-static __inline__ void atomic_dec(volatile atomic_t *v)
+extern __inline__ void atomic_dec(volatile atomic_t *v)
 {
 	unsigned long flags;
 	save_flags(flags);
@@ -96,7 +96,7 @@
 	restore_flags(flags);
 }
 
-static __inline__ int atomic_inc_return(volatile atomic_t *v)
+extern __inline__ int atomic_inc_return(volatile atomic_t *v)
 {
 	unsigned long flags;
 	int retval;
@@ -107,7 +107,7 @@
 	return retval;
 }
 
-static __inline__ int atomic_dec_return(volatile atomic_t *v)
+extern __inline__ int atomic_dec_return(volatile atomic_t *v)
 {
 	unsigned long flags;
 	int retval;
@@ -117,7 +117,7 @@
 	restore_flags(flags);
 	return retval;
 }
-static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
+extern __inline__ int atomic_dec_and_test(volatile atomic_t *v)
 {
 	int retval;
 	unsigned long flags;
@@ -128,7 +128,7 @@
 	return retval;
 }
 
-static __inline__ int atomic_inc_and_test(volatile atomic_t *v)
+extern __inline__ int atomic_inc_and_test(volatile atomic_t *v)
 {
 	int retval;
 	unsigned long flags;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/bitops.h linux-2.4.21/include/asm-cris/bitops.h
--- linux-2.4.20/include/asm-cris/bitops.h	2002-02-25 19:38:10.000000000 +0000
+++ linux-2.4.21/include/asm-cris/bitops.h	2002-12-18 18:58:07.000000000 +0000
@@ -89,7 +89,7 @@
  * It also implies a memory barrier.
  */
 
-static __inline__ int test_and_set_bit(int nr, void *addr)
+extern __inline__ int test_and_set_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned long flags;
@@ -120,7 +120,7 @@
  * It also implies a memory barrier.
  */
 
-static __inline__ int test_and_clear_bit(int nr, void *addr)
+extern __inline__ int test_and_clear_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned long flags;
@@ -146,7 +146,7 @@
  * but actually fail.  You must protect multiple accesses with a lock.
  */
 
-static __inline__ int __test_and_clear_bit(int nr, void *addr)
+extern __inline__ int __test_and_clear_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned int *adr = (unsigned int *)addr;
@@ -166,7 +166,7 @@
  * It also implies a memory barrier.
  */
 
-static __inline__ int test_and_change_bit(int nr, void *addr)
+extern __inline__ int test_and_change_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned long flags;
@@ -183,7 +183,7 @@
 
 /* WARNING: non atomic and it can be reordered! */
 
-static __inline__ int __test_and_change_bit(int nr, void *addr)
+extern __inline__ int __test_and_change_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned int *adr = (unsigned int *)addr;
@@ -204,7 +204,7 @@
  * This routine doesn't need to be atomic.
  */
 
-static __inline__ int test_bit(int nr, const void *addr)
+extern __inline__ int test_bit(int nr, const void *addr)
 {
 	unsigned int mask;
 	unsigned int *adr = (unsigned int *)addr;
@@ -225,7 +225,7 @@
  * number.  They differ in that the first function also inverts all bits
  * in the input.
  */
-static __inline__ unsigned long cris_swapnwbrlz(unsigned long w)
+extern __inline__ unsigned long cris_swapnwbrlz(unsigned long w)
 {
 	/* Let's just say we return the result in the same register as the
 	   input.  Saying we clobber the input but can return the result
@@ -241,7 +241,7 @@
 	return res;
 }
 
-static __inline__ unsigned long cris_swapwbrlz(unsigned long w)
+extern __inline__ unsigned long cris_swapwbrlz(unsigned long w)
 {
 	unsigned res;
 	__asm__ ("swapwbr %0 \n\t"
@@ -255,7 +255,7 @@
  * ffz = Find First Zero in word. Undefined if no zero exists,
  * so code should check against ~0UL first..
  */
-static __inline__ unsigned long ffz(unsigned long w)
+extern __inline__ unsigned long ffz(unsigned long w)
 {
 	/* The generic_ffs function is used to avoid the asm when the
 	   argument is a constant.  */
@@ -268,7 +268,7 @@
  * Somewhat like ffz but the equivalent of generic_ffs: in contrast to
  * ffz we return the first one-bit *plus one*.
  */
-static __inline__ unsigned long ffs(unsigned long w)
+extern __inline__ unsigned long kernel_ffs(unsigned long w)
 {
 	/* The generic_ffs function is used to avoid the asm when the
 	   argument is a constant.  */
@@ -277,13 +277,20 @@
 		: w ? cris_swapwbrlz (w) + 1 : 0;
 }
 
+/*
+ * Since we define it "external", it collides with the built-in
+ * definition, which doesn't have the same semantics.  We don't want to
+ * use -fno-builtin, so just hide the name ffs.
+ */
+#define ffs kernel_ffs
+
 /**
  * find_next_zero_bit - find the first zero bit in a memory region
  * @addr: The address to base the search on
  * @offset: The bitnumber to start searching at
  * @size: The maximum size to search
  */
-static __inline__ int find_next_zero_bit (void * addr, int size, int offset)
+extern __inline__ int find_next_zero_bit (void * addr, int size, int offset)
 {
 	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
 	unsigned long result = offset & ~31UL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/byteorder.h linux-2.4.21/include/asm-cris/byteorder.h
--- linux-2.4.20/include/asm-cris/byteorder.h	2001-02-09 00:32:44.000000000 +0000
+++ linux-2.4.21/include/asm-cris/byteorder.h	2002-12-18 18:58:01.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: byteorder.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ */
+/* $Id: byteorder.h,v 1.2 2002/11/20 18:20:17 hp Exp $ */
 
 #ifndef _CRIS_BYTEORDER_H
 #define _CRIS_BYTEORDER_H
@@ -12,14 +12,14 @@
  * them together into ntohl etc.
  */
 
-static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
+extern __inline__ __const__ __u32 ___arch__swab32(__u32 x)
 {
 	__asm__ ("swapwb %0" : "=r" (x) : "0" (x));
   
 	return(x);
 }
 
-static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
+extern __inline__ __const__ __u16 ___arch__swab16(__u16 x)
 {
 	__asm__ ("swapb %0" : "=r" (x) : "0" (x));
 	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/checksum.h linux-2.4.21/include/asm-cris/checksum.h
--- linux-2.4.20/include/asm-cris/checksum.h	2001-10-08 18:43:54.000000000 +0000
+++ linux-2.4.21/include/asm-cris/checksum.h	2002-12-18 18:58:10.000000000 +0000
@@ -32,7 +32,7 @@
  *	Fold a partial checksum into a word
  */
 
-static inline unsigned int csum_fold(unsigned int sum)
+extern inline unsigned int csum_fold(unsigned int sum)
 {
 	/* the while loop is unnecessary really, it's always enough with two
 	   iterations */
@@ -50,7 +50,7 @@
  * to split all of those into 16-bit components, then add.
  */
 
-static inline unsigned int
+extern inline unsigned int
 csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned short len,
 		   unsigned short proto, unsigned int sum)
 {
@@ -78,7 +78,7 @@
  *
  */
 
-static inline unsigned short ip_fast_csum(unsigned char * iph,
+extern inline unsigned short ip_fast_csum(unsigned char * iph,
 					  unsigned int ihl)
 {
 	return csum_fold(csum_partial(iph, ihl * 4, 0));
@@ -89,7 +89,7 @@
  * returns a 16-bit checksum, already complemented
  */
 
-static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
+extern inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
 						   unsigned long daddr,
 						   unsigned short len,
 						   unsigned short proto,
@@ -103,7 +103,7 @@
  * in icmp.c
  */
 
-static inline unsigned short ip_compute_csum(unsigned char * buff, int len) {
+extern inline unsigned short ip_compute_csum(unsigned char * buff, int len) {
 	return csum_fold (csum_partial(buff, len, 0));
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/current.h linux-2.4.21/include/asm-cris/current.h
--- linux-2.4.20/include/asm-cris/current.h	2001-10-08 18:43:54.000000000 +0000
+++ linux-2.4.21/include/asm-cris/current.h	2002-12-18 18:58:08.000000000 +0000
@@ -3,7 +3,7 @@
 
 struct task_struct;
 
-static inline struct task_struct * get_current(void)
+extern inline struct task_struct * get_current(void)
 {
         struct task_struct *current;
         __asm__("and.d $sp,%0; ":"=r" (current) : "0" (~8191UL));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/ide.h linux-2.4.21/include/asm-cris/ide.h
--- linux-2.4.20/include/asm-cris/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-cris/ide.h	2002-12-18 18:58:04.000000000 +0000
@@ -22,9 +22,7 @@
 
 #define MAX_HWIFS	4
 
-#define ide__sti()	__sti()
-
-static __inline__ int ide_default_irq(ide_ioreg_t base)
+extern __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	/* all IDE busses share the same IRQ, number 4.
 	 * this has the side-effect that ide-probe.c will cluster our 4 interfaces
@@ -34,7 +32,7 @@
 	return 4; 
 }
 
-static __inline__ ide_ioreg_t ide_default_io_base(int index)
+extern __inline__ ide_ioreg_t ide_default_io_base(int index)
 {
 	/* we have no real I/O base address per interface, since all go through the
 	 * same register. but in a bitfield in that register, we have the i/f number.
@@ -53,7 +51,7 @@
  * of the ide_default_io_base call above. ctrl_port will be 0, but that is don't care for us.
  */
 
-static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+extern __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
 	int i;
 
@@ -76,7 +74,7 @@
 	hw->io_ports[IDE_IRQ_OFFSET] = 0;
 }
 
-static __inline__ void ide_init_default_hwifs(void)
+extern __inline__ void ide_init_default_hwifs(void)
 {
 	hw_regs_t hw;
 	int index;
@@ -88,67 +86,11 @@
 	}
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all                    : 8;    /* all of the bits together */
-	struct {
-		unsigned bit0           : 1;
-		unsigned nIEN           : 1;    /* device INTRQ to host */
-		unsigned SRST           : 1;    /* host soft reset bit */
-		unsigned bit3           : 1;    /* ATA-2 thingy */
-		unsigned reserved456    : 3;
-		unsigned HOB            : 1;    /* 48-bit address ordering */
-	} b;
-} control_t;
-
 /* some configuration options we don't need */
 
 #undef SUPPORT_VLB_SYNC
 #define SUPPORT_VLB_SYNC 0
 
-#undef SUPPORT_SLOW_DATA_PORTS
-#define SUPPORT_SLOW_DATA_PORTS	0
-
-/* request and free a normal interrupt */
-
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-
-/* ide-probe.c calls ide_request_region and stuff on the io_ports defined,
- * but since they are not actually memory-mapped in the ETRAX driver, we don't
- * do anything.
- */
-
-#define ide_check_region(from,extent)		(0)
-#define ide_request_region(from,extent,name)	do {} while(0)
-#define ide_release_region(from,extent)		do {} while(0)
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
-/* the drive addressing is done through a controller register on the Etrax CPU */
-void OUT_BYTE(unsigned char data, ide_ioreg_t reg);
-unsigned char IN_BYTE(ide_ioreg_t reg);
-
-/* this tells ide.h not to define the standard macros */
-#define HAVE_ARCH_OUT_BYTE
-#define HAVE_ARCH_IN_BYTE
-
 #endif /* __KERNEL__ */
 
 #endif /* __ASMCRIS_IDE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/io.h linux-2.4.21/include/asm-cris/io.h
--- linux-2.4.20/include/asm-cris/io.h	2001-10-08 18:43:54.000000000 +0000
+++ linux-2.4.21/include/asm-cris/io.h	2002-12-18 18:58:10.000000000 +0000
@@ -3,6 +3,8 @@
 
 #include <asm/page.h>   /* for __va, __pa */
 #include <asm/svinto.h>
+#include <linux/sched.h>
+#include <asm/pgtable.h>
 #include <linux/config.h>
 
 /* Console I/O for simulated etrax100.  Use #ifdef so erroneous
@@ -199,16 +201,18 @@
  * Change virtual addresses to physical addresses and vv.
  */
 
-static inline unsigned long virt_to_phys(volatile void * address)
+extern inline unsigned long virt_to_phys(volatile void * address)
 {
 	return __pa(address);
 }
 
-static inline void * phys_to_virt(unsigned long address)
+extern inline void * phys_to_virt(unsigned long address)
 {
 	return __va(address);
 }
 
+#define page_to_phys(page)	__pa(__page_address(page))
+
 extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
 extern inline void * ioremap (unsigned long offset, unsigned long size)
@@ -216,6 +220,8 @@
 	return __ioremap(offset, size, 0);
 }
 
+extern void iounmap(void *addr);
+
 /*
  * IO bus memory addresses are also 1:1 with the physical address
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/mmu_context.h linux-2.4.21/include/asm-cris/mmu_context.h
--- linux-2.4.20/include/asm-cris/mmu_context.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21/include/asm-cris/mmu_context.h	2002-12-18 18:58:06.000000000 +0000
@@ -15,7 +15,7 @@
 
 extern volatile pgd_t *current_pgd;   /* defined in arch/cris/mm/fault.c */
 
-static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
+extern inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
 {
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/pgalloc.h linux-2.4.21/include/asm-cris/pgalloc.h
--- linux-2.4.20/include/asm-cris/pgalloc.h	2001-05-01 23:05:00.000000000 +0000
+++ linux-2.4.21/include/asm-cris/pgalloc.h	2002-12-18 18:58:06.000000000 +0000
@@ -58,7 +58,7 @@
         pgtable_cache_size++;
 }
 
-static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+extern inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
 {
         pte_t *pte;
 
@@ -68,7 +68,7 @@
         return pte;
 }
 
-static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
+extern inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
 {
         unsigned long *ret;
 
@@ -80,14 +80,14 @@
         return (pte_t *)ret;
 }
 
-static __inline__ void pte_free_fast(pte_t *pte)
+extern __inline__ void pte_free_fast(pte_t *pte)
 {
         *(unsigned long *)pte = (unsigned long) pte_quicklist;
         pte_quicklist = (unsigned long *) pte;
         pgtable_cache_size++;
 }
 
-static __inline__ void pte_free_slow(pte_t *pte)
+extern __inline__ void pte_free_slow(pte_t *pte)
 {
         free_page((unsigned long)pte);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/pgtable.h linux-2.4.21/include/asm-cris/pgtable.h
--- linux-2.4.20/include/asm-cris/pgtable.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-cris/pgtable.h	2002-12-18 18:58:01.000000000 +0000
@@ -3,6 +3,12 @@
  * HISTORY:
  *
  * $Log: pgtable.h,v $
+ * Revision 1.17  2002/12/02 08:14:08  starvik
+ * Merge of Linux 2.4.20
+ *
+ * Revision 1.16  2002/11/20 18:20:17  hp
+ * Make all static inline functions extern inline.
+ *
  * Revision 1.15  2002/04/23 15:37:52  bjornw
  * Removed page_address and added flush_icache_user_range
  *
@@ -149,14 +155,14 @@
 			    unsigned long start,
 			    unsigned long end);
 
-static inline void flush_tlb_pgtables(struct mm_struct *mm,
+extern inline void flush_tlb_pgtables(struct mm_struct *mm,
                                       unsigned long start, unsigned long end)
 {
         /* CRIS does not keep any page table caches in TLB */
 }
 
 
-static inline void flush_tlb(void) 
+extern inline void flush_tlb(void) 
 {
 	flush_tlb_mm(current->mm);
 }
@@ -166,6 +172,8 @@
  * hook is made available.
  */
 #define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
+#define set_pte_atomic(pteptr, pteval) ((*(pteptr)) = (pteval))
+
 /*
  * (pmds are folded into pgds so this doesn't get actually called,
  * but the define is needed for a generic inline function.)
@@ -303,53 +311,53 @@
  * setup: the pgd is never bad, and a pmd always exists (as it's folded
  * into the pgd entry)
  */
-static inline int pgd_none(pgd_t pgd)		{ return 0; }
-static inline int pgd_bad(pgd_t pgd)		{ return 0; }
-static inline int pgd_present(pgd_t pgd)	{ return 1; }
-static inline void pgd_clear(pgd_t * pgdp)	{ }
+extern inline int pgd_none(pgd_t pgd)		{ return 0; }
+extern inline int pgd_bad(pgd_t pgd)		{ return 0; }
+extern inline int pgd_present(pgd_t pgd)	{ return 1; }
+extern inline void pgd_clear(pgd_t * pgdp)	{ }
 
 /*
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
 
-static inline int pte_read(pte_t pte)           { return pte_val(pte) & _PAGE_READ; }
-static inline int pte_write(pte_t pte)          { return pte_val(pte) & _PAGE_WRITE; }
-static inline int pte_exec(pte_t pte)           { return pte_val(pte) & _PAGE_READ; }
-static inline int pte_dirty(pte_t pte)          { return pte_val(pte) & _PAGE_MODIFIED; }
-static inline int pte_young(pte_t pte)          { return pte_val(pte) & _PAGE_ACCESSED; }
+extern inline int pte_read(pte_t pte)           { return pte_val(pte) & _PAGE_READ; }
+extern inline int pte_write(pte_t pte)          { return pte_val(pte) & _PAGE_WRITE; }
+extern inline int pte_exec(pte_t pte)           { return pte_val(pte) & _PAGE_READ; }
+extern inline int pte_dirty(pte_t pte)          { return pte_val(pte) & _PAGE_MODIFIED; }
+extern inline int pte_young(pte_t pte)          { return pte_val(pte) & _PAGE_ACCESSED; }
 
-static inline pte_t pte_wrprotect(pte_t pte)
+extern inline pte_t pte_wrprotect(pte_t pte)
 {
         pte_val(pte) &= ~(_PAGE_WRITE | _PAGE_SILENT_WRITE);
         return pte;
 }
 
-static inline pte_t pte_rdprotect(pte_t pte)
+extern inline pte_t pte_rdprotect(pte_t pte)
 {
         pte_val(pte) &= ~(_PAGE_READ | _PAGE_SILENT_READ);
 	return pte;
 }
 
-static inline pte_t pte_exprotect(pte_t pte)
+extern inline pte_t pte_exprotect(pte_t pte)
 {
         pte_val(pte) &= ~(_PAGE_READ | _PAGE_SILENT_READ);
 	return pte;
 }
 
-static inline pte_t pte_mkclean(pte_t pte)
+extern inline pte_t pte_mkclean(pte_t pte)
 {
 	pte_val(pte) &= ~(_PAGE_MODIFIED | _PAGE_SILENT_WRITE); 
 	return pte; 
 }
 
-static inline pte_t pte_mkold(pte_t pte)
+extern inline pte_t pte_mkold(pte_t pte)
 {
 	pte_val(pte) &= ~(_PAGE_ACCESSED | _PAGE_SILENT_READ);
 	return pte;
 }
 
-static inline pte_t pte_mkwrite(pte_t pte)
+extern inline pte_t pte_mkwrite(pte_t pte)
 {
         pte_val(pte) |= _PAGE_WRITE;
         if (pte_val(pte) & _PAGE_MODIFIED)
@@ -357,7 +365,7 @@
         return pte;
 }
 
-static inline pte_t pte_mkread(pte_t pte)
+extern inline pte_t pte_mkread(pte_t pte)
 {
         pte_val(pte) |= _PAGE_READ;
         if (pte_val(pte) & _PAGE_ACCESSED)
@@ -365,7 +373,7 @@
         return pte;
 }
 
-static inline pte_t pte_mkexec(pte_t pte)
+extern inline pte_t pte_mkexec(pte_t pte)
 {
         pte_val(pte) |= _PAGE_READ;
         if (pte_val(pte) & _PAGE_ACCESSED)
@@ -373,7 +381,7 @@
         return pte;
 }
 
-static inline pte_t pte_mkdirty(pte_t pte)
+extern inline pte_t pte_mkdirty(pte_t pte)
 {
         pte_val(pte) |= _PAGE_MODIFIED;
         if (pte_val(pte) & _PAGE_WRITE)
@@ -381,7 +389,7 @@
         return pte;
 }
 
-static inline pte_t pte_mkyoung(pte_t pte)
+extern inline pte_t pte_mkyoung(pte_t pte)
 {
         pte_val(pte) |= _PAGE_ACCESSED;
         if (pte_val(pte) & _PAGE_READ)
@@ -405,7 +413,7 @@
  * addresses (the 0xc0xxxxxx's) goes as void *'s.
  */
 
-static inline pte_t __mk_pte(void * page, pgprot_t pgprot)
+extern inline pte_t __mk_pte(void * page, pgprot_t pgprot)
 {
 	pte_t pte;
 	/* the PTE needs a physical address */
@@ -423,7 +431,7 @@
         __pte;                                                          \
 })
 
-static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
 
 
@@ -432,7 +440,7 @@
  * pte_pagenr refers to the page-number counted starting from the virtual DRAM start
  */
 
-static inline unsigned long __pte_page(pte_t pte)
+extern inline unsigned long __pte_page(pte_t pte)
 {
 	/* the PTE contains a physical address */
 	return (unsigned long)__va(pte_val(pte) & PAGE_MASK);
@@ -450,17 +458,17 @@
  * don't need the __pa and __va transformations.
  */
 
-static inline unsigned long pmd_page(pmd_t pmd)
+extern inline unsigned long pmd_page(pmd_t pmd)
 { return pmd_val(pmd) & PAGE_MASK; }
 
-static inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
+extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
 { pmd_val(*pmdp) = _PAGE_TABLE | (unsigned long) ptep; }
 
 /* to find an entry in a page-table-directory. */
 #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
 
 /* to find an entry in a page-table-directory */
-static inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
+extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
 {
 	return mm->pgd + pgd_index(address);
 }
@@ -469,13 +477,13 @@
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
 /* Find an entry in the second-level page table.. */
-static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
 {
 	return (pmd_t *) dir;
 }
 
 /* Find an entry in the third-level page table.. */ 
-static inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
+extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
 {
 	return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
 }
@@ -495,7 +503,7 @@
  * 
  * Actually I am not sure on what this could be used for.
  */
-static inline void update_mmu_cache(struct vm_area_struct * vma,
+extern inline void update_mmu_cache(struct vm_area_struct * vma,
 	unsigned long address, pte_t pte)
 {
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/posix_types.h linux-2.4.21/include/asm-cris/posix_types.h
--- linux-2.4.20/include/asm-cris/posix_types.h	2001-02-09 00:32:44.000000000 +0000
+++ linux-2.4.21/include/asm-cris/posix_types.h	2002-12-18 18:58:04.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: posix_types.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ */
+/* $Id: posix_types.h,v 1.2 2002/09/26 14:44:59 hp Exp $ */
 
 /* We cheat a bit and use our C-coded bitops functions from asm/bitops.h */
 /* I guess we should write these in assembler because they are used often. */
@@ -23,7 +23,7 @@
 typedef unsigned short  __kernel_ipc_pid_t;
 typedef unsigned short	__kernel_uid_t;
 typedef unsigned short	__kernel_gid_t;
-typedef unsigned long	__kernel_size_t;
+typedef __SIZE_TYPE__	__kernel_size_t;
 typedef long		__kernel_ssize_t;
 typedef int		__kernel_ptrdiff_t;
 typedef long		__kernel_time_t;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/processor.h linux-2.4.21/include/asm-cris/processor.h
--- linux-2.4.20/include/asm-cris/processor.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-cris/processor.h	2002-12-18 18:58:08.000000000 +0000
@@ -116,13 +116,13 @@
  * Free current thread data structures etc..
  */
 
-static inline void exit_thread(void)
+extern inline void exit_thread(void)
 {
         /* Nothing needs to be done.  */
 }
 
 /* Free all resources held by a thread. */
-static inline void release_thread(struct task_struct *dead_task)
+extern inline void release_thread(struct task_struct *dead_task)
 {
         /* Nothing needs to be done.  */
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/rtc.h linux-2.4.21/include/asm-cris/rtc.h
--- linux-2.4.20/include/asm-cris/rtc.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-cris/rtc.h	2002-12-18 18:58:02.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: rtc.h,v 1.5 2002/08/14 11:04:10 sebsjo Exp $ */
+/* $Id: rtc.h,v 1.8 2002/11/20 14:27:25 oskarp Exp $ */
 
 #ifndef __RTC_H__
 #define __RTC_H__
@@ -53,17 +53,23 @@
 #  define RTC_MINUTE_ALARM	0x09
 #  define RTC_HOUR_ALARM	0x0a
 #  define RTC_DAY_ALARM		0x0b
-#  define RTC_WEEKDAY_ALARM 0x0c
+#  define RTC_WEEKDAY_ALARM 0x0c	/* Not coded in BCD! */
 
 #endif
 
 #ifdef CONFIG_ETRAX_DS1302
+extern unsigned char ds1302_readreg(int reg);
+extern void ds1302_writereg(int reg, unsigned char val);
+extern int ds1302_init(void);
 #  define CMOS_READ(x) ds1302_readreg(x)
 #  define CMOS_WRITE(val,reg) ds1302_writereg(reg,val)
 #  define RTC_INIT() ds1302_init()
 #elif defined(CONFIG_ETRAX_PCF8563)
-#  define CMOS_READ(x) i2c_readreg(RTC_I2C_READ, x)
-#  define CMOS_WRITE(val,reg) i2c_writereg(RTC_I2C_WRITE,reg,val)
+extern unsigned char pcf8563_readreg(int reg);
+extern void pcf8563_writereg(int reg, unsigned char val);
+extern int pcf8563_init(void);
+#  define CMOS_READ(x) pcf8563_readreg(x)
+#  define CMOS_WRITE(val,reg) pcf8563_writereg(reg,val)
 #  define RTC_INIT() pcf8563_init()
 #else
   /* No RTC configured so we shouldn't try to access any. */
@@ -94,17 +100,10 @@
 };
 
 /* ioctl() calls that are permitted to the /dev/rtc interface. */
-#ifdef CONFIG_ETRAX_DS1302
-#  define DS1302_MAGIC 'p'
-#  define RTC_RD_TIME		_IOR(DS1302_MAGIC, 0x09, struct rtc_time) 	/* Read RTC time. */
-#  define RTC_SET_TIME		_IOW(DS1302_MAGIC, 0x0a, struct rtc_time) 	/* Set RTC time. */
-#  define RTC_SET_CHARGE  	_IOW(DS1302_MAGIC, 0x0b, int) 				/* Set CHARGE mode. */
-#elif defined(CONFIG_ETRAX_PCF8563)
-#  define PCF8563_MAGIC 'T'
-#  define RTC_RD_TIME		_IOR(PCF8563_MAGIC, 0x01, struct rtc_time)	/* Read RTC time. */
-#  define RTC_SET_TIME		_IOW(PCF8563_MAGIC, 0x02, struct rtc_time)	/* Set RTC time. */
-#  define RTC_SET_CHARGE  	_IOW(PCF8563_MAGIC, 0x03, int) 		
-#  define RTC_MAX_IOCTL 3
-#endif
+#define RTC_MAGIC 'p'
+#define RTC_RD_TIME		_IOR(RTC_MAGIC, 0x09, struct rtc_time)	/* Read RTC time. */
+#define RTC_SET_TIME		_IOW(RTC_MAGIC, 0x0a, struct rtc_time)	/* Set RTC time. */
+#define RTC_SET_CHARGE  	_IOW(RTC_MAGIC, 0x0b, int) 		
+#define RTC_MAX_IOCTL 0x0b
 
 #endif /* __RTC_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/scatterlist.h linux-2.4.21/include/asm-cris/scatterlist.h
--- linux-2.4.20/include/asm-cris/scatterlist.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/include/asm-cris/scatterlist.h	2002-12-18 18:58:01.000000000 +0000
@@ -0,0 +1,18 @@
+#ifndef __ASM_CRIS_SCATTERLIST_H
+#define __ASM_CRIS_SCATTERLIST_H
+
+struct scatterlist {
+	char *  address;    /* Location data is to be transferred to */
+	unsigned int length;
+
+	/* The following is i386 highmem junk - not used by us */
+	struct page * page; /* Location for highmem page, if any */
+	unsigned int offset;/* for highmem, page offset */
+
+};
+
+/* i386 junk */
+
+#define ISA_DMA_THRESHOLD (0x1fffffff)
+
+#endif /* !(__ASM_CRIS_SCATTERLIST_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/semaphore-helper.h linux-2.4.21/include/asm-cris/semaphore-helper.h
--- linux-2.4.20/include/asm-cris/semaphore-helper.h	2001-05-01 23:05:00.000000000 +0000
+++ linux-2.4.21/include/asm-cris/semaphore-helper.h	2002-12-18 18:58:08.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: semaphore-helper.h,v 1.3 2001/03/26 15:00:33 orjanf Exp $
+/* $Id: semaphore-helper.h,v 1.4 2002/11/20 18:20:17 hp Exp $
  *
  * SMP- and interrupt-safe semaphores helper functions. Generic versions, no
  * optimizations whatsoever... 
@@ -19,12 +19,12 @@
 /*
  * These two _must_ execute atomically wrt each other.
  */
-static inline void wake_one_more(struct semaphore * sem)
+extern inline void wake_one_more(struct semaphore * sem)
 {
 	atomic_inc(&sem->waking);
 }
 
-static inline int waking_non_zero(struct semaphore *sem)
+extern inline int waking_non_zero(struct semaphore *sem)
 {
 	unsigned long flags;
 	int ret = 0;
@@ -38,7 +38,7 @@
 	return ret;
 }
 
-static inline int waking_non_zero_interruptible(struct semaphore *sem,
+extern inline int waking_non_zero_interruptible(struct semaphore *sem,
 						struct task_struct *tsk)
 {
 	int ret = 0;
@@ -56,7 +56,7 @@
 	return ret;
 }
 
-static inline int waking_non_zero_trylock(struct semaphore *sem)
+extern inline int waking_non_zero_trylock(struct semaphore *sem)
 {
         int ret = 1;
 	unsigned long flags;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/semaphore.h linux-2.4.21/include/asm-cris/semaphore.h
--- linux-2.4.20/include/asm-cris/semaphore.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-cris/semaphore.h	2002-12-18 18:58:06.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: semaphore.h,v 1.3 2001/05/08 13:54:09 bjornw Exp $ */
+/* $Id: semaphore.h,v 1.5 2002/12/02 08:14:08 starvik Exp $ */
 
 /* On the i386 these are coded in asm, perhaps we should as well. Later.. */
 
@@ -54,12 +54,12 @@
 	*sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
 }
 
-static inline void init_MUTEX (struct semaphore *sem)
+extern inline void init_MUTEX (struct semaphore *sem)
 {
         sema_init(sem, 1);
 }
 
-static inline void init_MUTEX_LOCKED (struct semaphore *sem)
+extern inline void init_MUTEX_LOCKED (struct semaphore *sem)
 {
         sema_init(sem, 0);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/sv_addr_ag.h linux-2.4.21/include/asm-cris/sv_addr_ag.h
--- linux-2.4.20/include/asm-cris/sv_addr_ag.h	2001-02-09 00:32:44.000000000 +0000
+++ linux-2.4.21/include/asm-cris/sv_addr_ag.h	2002-12-18 18:58:11.000000000 +0000
@@ -25,33 +25,41 @@
 
 /* IO_MASK returns a mask for a specified bitfield in a register.
    Note that this macro doesn't work when field width is 32 bits. */
-#define IO_MASK(reg,field) \
-    ( ( ( 1 << reg##__##field##__WIDTH ) - 1 ) << reg##__##field##__BITNR )
+#define IO_MASK(reg, field) IO_MASK_ (reg##_, field##_)
+#define IO_MASK_(reg_, field_) \
+    ( ( ( 1 << reg_##_##field_##_WIDTH ) - 1 ) << reg_##_##field_##_BITNR )
 
 /* IO_STATE returns a constant corresponding to a one of the symbolic
    states that the bitfield can have. (Shifted to correct position)  */
-#define IO_STATE(reg,field,state) \
-    ( reg##__##field##__##state << reg##__##field##__BITNR )
+#define IO_STATE(reg, field, state) IO_STATE_ (reg##_, field##_, _##state)
+#define IO_STATE_(reg_, field_, _state) \
+    ( reg_##_##field_##_state << reg_##_##field_##_BITNR )
 
 /* IO_EXTRACT returns the masked and shifted value corresponding to the
    bitfield can have. */
-#define IO_EXTRACT(reg,field,val) ( (( ( ( 1 << reg##__##field##__WIDTH ) \
-     - 1 ) << reg##__##field##__BITNR ) & (val)) >> reg##__##field##__BITNR )
+#define IO_EXTRACT(reg, field, val) IO_EXTRACT_ (reg##_, field##_, val)
+#define IO_EXTRACT_(reg_, field_, val) ( (( ( ( 1 << reg_##_##field_##_WIDTH ) \
+     - 1 ) << reg_##_##field_##_BITNR ) & (val)) >> reg_##_##field_##_BITNR )
 
 /* IO_STATE_VALUE returns a constant corresponding to a one of the symbolic
    states that the bitfield can have. (Not shifted)  */
-#define IO_STATE_VALUE(reg,field,state) ( reg##__##field##__##state )
+#define IO_STATE_VALUE(reg, field, state) \
+    IO_STATE_VALUE_ (reg##_, field##_, _##state)
+#define IO_STATE_VALUE_(reg_, field_, _state) ( reg_##_##field_##_state )
 
 /* IO_FIELD shifts the val parameter to be aligned with the bitfield
    specified. */
-#define IO_FIELD(reg,field,val) ((val) << reg##__##field##__BITNR)
+#define IO_FIELD(reg, field, val) IO_FIELD_ (reg##_, field##_, val)
+#define IO_FIELD_(reg_, field_, val) ((val) << reg_##_##field_##_BITNR)
 
 /* IO_BITNR returns the starting bitnumber of a bitfield. Bit 0 is
    LSB and the returned bitnumber is LSB of the field. */
-#define IO_BITNR(reg,field) (reg##__##field##__BITNR)
+#define IO_BITNR(reg, field) IO_BITNR_ (reg##_, field##_)
+#define IO_BITNR_(reg_, field_) (reg_##_##field_##_BITNR)
 
 /* IO_WIDTH returns the width, in bits, of a bitfield. */
-#define IO_WIDTH(reg,field) (reg##__##field##__WIDTH)
+#define IO_WIDTH(reg, field) IO_WIDTH_ (reg##_, field##_)
+#define IO_WIDTH_(reg_, field_) (reg_##_##field_##_WIDTH)
 
 /*--- Obsolete. Kept for backw compatibility. ---*/
 /* Reads (or writes) a byte/uword/udword from the specified mode
@@ -66,7 +74,9 @@
 !*-----------------------------------------------------------*/
 
 #define MEM_CSE0_START (0x00000000)
+#define MEM_CSE0_SIZE (0x04000000)
 #define MEM_CSE1_START (0x04000000)
+#define MEM_CSE1_SIZE (0x04000000)
 #define MEM_CSR0_START (0x08000000)
 #define MEM_CSR1_START (0x0c000000)
 #define MEM_CSP0_START (0x10000000)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/system.h linux-2.4.21/include/asm-cris/system.h
--- linux-2.4.20/include/asm-cris/system.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-cris/system.h	2002-12-18 18:58:01.000000000 +0000
@@ -16,7 +16,7 @@
 
 /* read the CPU version register */
 
-static inline unsigned long rdvr(void) { 
+extern inline unsigned long rdvr(void) { 
 	unsigned char vr;
 	__asm__ volatile ("move $vr,%0" : "=rm" (vr));
 	return vr;
@@ -24,7 +24,7 @@
 
 /* read/write the user-mode stackpointer */
 
-static inline unsigned long rdusp(void) {
+extern inline unsigned long rdusp(void) {
 	unsigned long usp;
 	__asm__ __volatile__("move $usp,%0" : "=rm" (usp));
 	return usp;
@@ -35,13 +35,13 @@
 
 /* read the current stackpointer */
 
-static inline unsigned long rdsp(void) {
+extern inline unsigned long rdsp(void) {
 	unsigned long sp;
 	__asm__ __volatile__("move.d $sp,%0" : "=rm" (sp));
 	return sp;
 }
 
-static inline unsigned long _get_base(char * addr)
+extern inline unsigned long _get_base(char * addr)
 {
   return 0;
 }
@@ -69,6 +69,7 @@
 
 /* For spinlocks etc */
 #define local_irq_save(x) __asm__ __volatile__ ("move $ccr,%0\n\tdi" : "=rm" (x) : : "memory"); 
+#define local_irq_set(x) __asm__ __volatile__ ("move $ccr,%0\n\tei" : "=rm" (x) : : "memory");
 #define local_irq_restore(x) restore_flags(x)
 
 #define local_irq_disable()  cli()
@@ -80,9 +81,10 @@
 #define sti() __sti()
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
-#define save_and_cli(x) do { __save_flags(x); cli(); } while(0)
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0)
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0)
 
-static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
+extern inline unsigned long __xchg(unsigned long x, void * ptr, int size)
 {
   /* since Etrax doesn't have any atomic xchg instructions, we need to disable
      irq's (if enabled) and do it with move.d's */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/timex.h linux-2.4.21/include/asm-cris/timex.h
--- linux-2.4.20/include/asm-cris/timex.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-cris/timex.h	2002-12-18 18:58:06.000000000 +0000
@@ -26,7 +26,7 @@
 
 unsigned long get_ns_in_jiffie(void);
 
-static inline unsigned long get_us_in_jiffie_highres(void)
+extern inline unsigned long get_us_in_jiffie_highres(void)
 {
 	return get_ns_in_jiffie()/1000;
 }
@@ -37,7 +37,7 @@
 
 typedef unsigned int cycles_t;
 
-static inline cycles_t get_cycles(void)
+extern inline cycles_t get_cycles(void)
 {
         return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/uaccess.h linux-2.4.21/include/asm-cris/uaccess.h
--- linux-2.4.20/include/asm-cris/uaccess.h	2001-11-09 22:11:15.000000000 +0000
+++ linux-2.4.21/include/asm-cris/uaccess.h	2002-12-18 18:58:03.000000000 +0000
@@ -3,6 +3,9 @@
  *	       Hans-Peter Nilsson (hp@axis.com)
  *
  * $Log: uaccess.h,v $
+ * Revision 1.9  2002/11/20 18:20:17  hp
+ * Make all static inline functions extern inline.
+ *
  * Revision 1.8  2001/10/29 13:01:48  bjornw
  * Removed unused variable tmp2 in strnlen_user
  *
@@ -321,7 +324,7 @@
  * (without the null byte)
  */
 
-static inline long         
+extern inline long         
 __do_strncpy_from_user(char *dst, const char *src, long count)
 {
 	long res;
@@ -381,7 +384,7 @@
 	return res;
 }
 
-static inline unsigned long
+extern inline unsigned long
 __generic_copy_to_user(void *to, const void *from, unsigned long n)
 {
 	if (access_ok(VERIFY_WRITE, to, n))
@@ -389,7 +392,7 @@
 	return n;
 }
 
-static inline unsigned long
+extern inline unsigned long
 __generic_copy_from_user(void *to, const void *from, unsigned long n)
 {
 	if (access_ok(VERIFY_READ, from, n))
@@ -397,7 +400,7 @@
 	return n;
 }
 
-static inline unsigned long
+extern inline unsigned long
 __generic_clear_user(void *to, unsigned long n)
 {
 	if (access_ok(VERIFY_WRITE, to, n))
@@ -405,13 +408,13 @@
 	return n;
 }
 
-static inline long
+extern inline long
 __strncpy_from_user(char *dst, const char *src, long count)
 {
 	return __do_strncpy_from_user(dst, src, count);
 }
 
-static inline long
+extern inline long
 strncpy_from_user(char *dst, const char *src, long count)
 {
 	long res = -EFAULT;
@@ -871,7 +874,7 @@
 /* Note that if these expand awfully if made into switch constructs, so
    don't do that.  */
 
-static inline unsigned long
+extern inline unsigned long
 __constant_copy_from_user(void *to, const void *from, unsigned long n)
 {
 	unsigned long ret = 0;
@@ -921,7 +924,7 @@
 
 /* Ditto, don't make a switch out of this.  */
 
-static inline unsigned long
+extern inline unsigned long
 __constant_copy_to_user(void *to, const void *from, unsigned long n)
 {
 	unsigned long ret = 0;
@@ -971,7 +974,7 @@
 
 /* No switch, please.  */
 
-static inline unsigned long
+extern inline unsigned long
 __constant_clear_user(void *to, unsigned long n)
 {
 	unsigned long ret = 0;
@@ -1026,19 +1029,19 @@
  * used in fast paths and have only a small space overhead.
  */
 
-static inline unsigned long
+extern inline unsigned long
 __generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n)
 {
 	return __copy_user_zeroing(to,from,n);
 }
 
-static inline unsigned long
+extern inline unsigned long
 __generic_copy_to_user_nocheck(void *to, const void *from, unsigned long n)
 {
 	return __copy_user(to,from,n);
 }
 
-static inline unsigned long
+extern inline unsigned long
 __generic_clear_user_nocheck(void *to, unsigned long n)
 {
 	return __do_clear_user(to,n);
@@ -1057,7 +1060,7 @@
  * or 0 for error.  Return a value greater than N if too long.
  */
 
-static inline long
+extern inline long
 strnlen_user(const char *s, long n)
 {
 	long res, tmp1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/unistd.h linux-2.4.21/include/asm-cris/unistd.h
--- linux-2.4.20/include/asm-cris/unistd.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-cris/unistd.h	2002-12-18 18:58:06.000000000 +0000
@@ -230,18 +230,51 @@
 #define __NR_security           223     /* syscall for security modules */
 #define __NR_gettid             224
 #define __NR_readahead          225
-#define __NR_tkill              226
+#define __NR_setxattr		226
+#define __NR_lsetxattr		227
+#define __NR_fsetxattr		228
+#define __NR_getxattr		229
+#define __NR_lgetxattr		230
+#define __NR_fgetxattr		231
+#define __NR_listxattr		232
+#define __NR_llistxattr		233
+#define __NR_flistxattr		234
+#define __NR_removexattr	235
+#define __NR_lremovexattr	236
+#define __NR_fremovexattr	237
+#define __NR_tkill		238
+#define __NR_sendfile64		239
+#define __NR_futex		240
+#define __NR_sched_setaffinity	241
+#define __NR_sched_getaffinity	242
+#define __NR_set_thread_area	243
+#define __NR_get_thread_area	244
+#define __NR_io_setup		245
+#define __NR_io_destroy		246
+#define __NR_io_getevents	247
+#define __NR_io_submit		248
+#define __NR_io_cancel		249
+#define __NR_alloc_hugepages	250
+#define __NR_free_hugepages	251
+#define __NR_exit_group		252
 
 /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
+/*
+ * Don't remove the .ifnc tests; they are an insurance against
+ * any hard-to-spot gcc register allocation bugs.
+ */
 #define _syscall0(type,name) \
 type name(void) \
 { \
   register long __a __asm__ ("r10"); \
-  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1,$r10$r9\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"break 13" \
 			: "=r" (__a) \
-			: "g" (__NR_##name) \
-			: "r10", "r9"); \
-  if(__a >= 0) \
+			: "r" (__n_)); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -251,11 +284,14 @@
 type name(type1 arg1) \
 { \
   register long __a __asm__ ("r10") = (long) arg1; \
-  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1,$r10$r9\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"break 13" \
 			: "=r" (__a) \
-			: "g" (__NR_##name), "0" (__a) \
-			: "r10", "r9"); \
-  if(__a >= 0) \
+			: "r" (__n_), "0" (__a)); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -266,11 +302,14 @@
 { \
   register long __a __asm__ ("r10") = (long) arg1; \
   register long __b __asm__ ("r11") = (long) arg2; \
-  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1%3,$r10$r9$r11\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"break 13" \
 			: "=r" (__a) \
-			: "g" (__NR_##name), "0" (__a), "r" (__b) \
-			: "r10", "r9"); \
-  if(__a >= 0) \
+			: "r" (__n_), "0" (__a), "r" (__b)); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -282,11 +321,14 @@
   register long __a __asm__ ("r10") = (long) arg1; \
   register long __b __asm__ ("r11") = (long) arg2; \
   register long __c __asm__ ("r12") = (long) arg3; \
-  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1%3%4,$r10$r9$r11$r12\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"break 13" \
 			: "=r" (__a) \
-			: "g" (__NR_##name), "0" (__a), "r" (__b), "r" (__c) \
-			: "r10", "r9"); \
-  if(__a >= 0) \
+			: "r" (__n_), "0" (__a), "r" (__b), "r" (__c)); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -299,12 +341,15 @@
   register long __b __asm__ ("r11") = (long) arg2; \
   register long __c __asm__ ("r12") = (long) arg3; \
   register long __d __asm__ ("r13") = (long) arg4; \
-  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
-			: "=r" (__a) \
-			: "g" (__NR_##name), "0" (__a), "r" (__b), \
-			  "r" (__c), "r" (__d) \
-			: "r10", "r9"); \
-  if(__a >= 0) \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1%3%4%5,$r10$r9$r11$r12$r13\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"break 13" \
+			: "=r" (__a) \
+			: "r" (__n_), "0" (__a), "r" (__b), \
+			  "r" (__c), "r" (__d)); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -318,13 +363,16 @@
   register long __b __asm__ ("r11") = (long) arg2; \
   register long __c __asm__ ("r12") = (long) arg3; \
   register long __d __asm__ ("r13") = (long) arg4; \
-  __asm__ __volatile__ ("move %6,$mof\n\t" \
-			"movu.w %1,$r9\n\tbreak 13" \
-			: "=r" (__a) \
-			: "g" (__NR_##name), "0" (__a), "r" (__b), \
-			  "r" (__c), "r" (__d), "g" (arg5) \
-			: "r10", "r9"); \
-  if(__a >= 0) \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1%3%4%5,$r10$r9$r11$r12$r13\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"move %6,$mof\n\t" \
+			"break 13" \
+			: "=r" (__a) \
+			: "r" (__n_), "0" (__a), "r" (__b), \
+			  "r" (__c), "r" (__d), "g" (arg5)); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -338,13 +386,17 @@
   register long __b __asm__ ("r11") = (long) arg2; \
   register long __c __asm__ ("r12") = (long) arg3; \
   register long __d __asm__ ("r13") = (long) arg4; \
-  __asm__ __volatile__ ("move %6,$mof\n\tmove %7,$srp\n\t" \
-			"movu.w %1,$r9\n\tbreak 13" \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1%3%4%5,$r10$r9$r11$r12$r13\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"move %6,$mof\n\tmove %7,$srp\n\t" \
+			"break 13" \
 			: "=r" (__a) \
-			: "g" (__NR_##name), "0" (__a), "r" (__b), \
+			: "r" (__n_), "0" (__a), "r" (__b), \
 			  "r" (__c), "r" (__d), "g" (arg5), "g" (arg6)\
-			: "r10", "r9", "srp"); \
-  if(__a >= 0) \
+			: "srp"); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -365,30 +417,40 @@
  * some others too.
  */
 #define __NR__exit __NR_exit
-static inline _syscall0(int,idle)
-static inline _syscall0(int,fork)
-static inline _syscall2(int,clone,unsigned long,flags,char *,esp)
-static inline _syscall0(int,pause)
-static inline _syscall0(int,setup)
-static inline _syscall0(int,sync)
-static inline _syscall0(pid_t,setsid)
-static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
-static inline _syscall1(int,dup,int,fd)
-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
-static inline _syscall1(int,close,int,fd)
-static inline _syscall1(int,_exit,int,exitcode)
-static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
+extern inline _syscall0(int,idle)
+extern inline _syscall0(int,fork)
+extern inline _syscall2(int,clone,unsigned long,flags,char *,esp)
+extern inline _syscall0(int,pause)
+extern inline _syscall0(int,setup)
+extern inline _syscall0(int,sync)
+extern inline _syscall0(pid_t,setsid)
+extern inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
+extern inline _syscall1(int,dup,int,fd)
+extern inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+extern inline _syscall3(int,open,const char *,file,int,flag,int,mode)
+extern inline _syscall1(int,close,int,fd)
+
+/*
+ * Since we define it "external", it collides with the built-in
+ * definition, which has the "noreturn" attribute and will cause
+ * complaints.  We don't want to use -fno-builtin, so just use a
+ * different name when in the kernel.
+ */
+#ifdef __KERNEL__
+#define _exit kernel_syscall_exit
+#endif
+extern inline _syscall1(int,_exit,int,exitcode)
+extern inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
+extern inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
 
   /* the following are just while developing the elinux port! */
 
-static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
-static inline _syscall2(int,socketcall,int,call,unsigned long *,args)
-static inline _syscall3(int,ioctl,unsigned int,fd,unsigned int,cmd,unsigned long,arg)
-static inline _syscall5(int,mount,const char *,a,const char *,b,const char *,c,unsigned long,rwflag,const void *,data)
+extern inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
+extern inline _syscall2(int,socketcall,int,call,unsigned long *,args)
+extern inline _syscall3(int,ioctl,unsigned int,fd,unsigned int,cmd,unsigned long,arg)
+extern inline _syscall5(int,mount,const char *,a,const char *,b,const char *,c,unsigned long,rwflag,const void *,data)
 
-static inline pid_t wait(int * wait_stat)
+extern inline pid_t wait(int * wait_stat)
 {
 	return waitpid(-1,wait_stat,0);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-generic/ide_iops.h linux-2.4.21/include/asm-generic/ide_iops.h
--- linux-2.4.20/include/asm-generic/ide_iops.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/include/asm-generic/ide_iops.h	2002-12-18 18:58:04.000000000 +0000
@@ -0,0 +1,38 @@
+/* Generic I/O and MEMIO string operations.  */
+
+#define __ide_insw	insw
+#define __ide_insl	insl
+#define __ide_outsw	outsw
+#define __ide_outsl	outsl
+
+static __inline__ void __ide_mm_insw(unsigned long port, void *addr, u32 count)
+{
+	while (count--) {
+		*(u16 *)addr = readw(port);
+		addr += 2;
+	}
+}
+
+static __inline__ void __ide_mm_insl(unsigned long port, void *addr, u32 count)
+{
+	while (count--) {
+		*(u32 *)addr = readl(port);
+		addr += 4;
+	}
+}
+
+static __inline__ void __ide_mm_outsw(unsigned long port, void *addr, u32 count)
+{
+	while (count--) {
+		writew(*(u16 *)addr, port);
+		addr += 2;
+	}
+}
+
+static __inline__ void __ide_mm_outsl(unsigned long port, void *addr, u32 count)
+{
+	while (count--) {
+		writel(*(u32 *)addr, port);
+		addr += 4;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/apicdef.h linux-2.4.21/include/asm-i386/apicdef.h
--- linux-2.4.20/include/asm-i386/apicdef.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-i386/apicdef.h	2002-12-18 18:58:09.000000000 +0000
@@ -32,6 +32,7 @@
 #define			SET_APIC_LOGICAL_ID(x)	(((x)<<24))
 #define			APIC_ALL_CPUS		0xFF
 #define		APIC_DFR	0xE0
+#define			APIC_DFR_CLUSTER	0x0FFFFFFFul	/* Clustered */
 #define			APIC_DFR_FLAT		0xFFFFFFFFul	/* Flat mode */
 #define		APIC_SPIV	0xF0
 #define			APIC_SPIV_FOCUS_DISABLED	(1<<9)
@@ -58,6 +59,7 @@
 #define			APIC_INT_LEVELTRIG	0x08000
 #define			APIC_INT_ASSERT		0x04000
 #define			APIC_ICR_BUSY		0x01000
+#define			APIC_DEST_PHYSICAL	0x00000
 #define			APIC_DEST_LOGICAL	0x00800
 #define			APIC_DM_FIXED		0x00000
 #define			APIC_DM_LOWEST		0x00100
@@ -108,11 +110,18 @@
 
 #define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
 
+#ifdef CONFIG_X86_CLUSTERED_APIC
+#define MAX_IO_APICS 32
+#else
 #define MAX_IO_APICS 8
+#endif
+
 
 /*
- * The broadcast ID is 0xF for old APICs.
+ * The broadcast ID is 0xF for old APICs and 0xFF for xAPICs.  SAPICs
+ * don't broadcast (yet?), but if they did, they might use 0xFFFF.
  */
+#define APIC_BROADCAST_ID_XAPIC (0xFF)
 #define APIC_BROADCAST_ID_APIC  (0x0F)
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/fixmap.h linux-2.4.21/include/asm-i386/fixmap.h
--- linux-2.4.20/include/asm-i386/fixmap.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-i386/fixmap.h	2002-12-18 18:58:02.000000000 +0000
@@ -64,6 +64,9 @@
 #ifndef CONFIG_X86_F00F_WORKS_OK
 	FIX_F00F,
 #endif
+#ifdef CONFIG_X86_SUMMIT
+	FIX_CYCLONE_TIMER, /*cyclone timer register*/
+#endif 
 #ifdef CONFIG_HIGHMEM
 	FIX_KMAP_BEGIN,	/* reserved pte's for temporary kernel mappings */
 	FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/hdreg.h linux-2.4.21/include/asm-i386/hdreg.h
--- linux-2.4.20/include/asm-i386/hdreg.h	1999-05-13 18:00:08.000000000 +0000
+++ linux-2.4.21/include/asm-i386/hdreg.h	2002-12-18 18:58:02.000000000 +0000
@@ -7,6 +7,7 @@
 #ifndef __ASMi386_HDREG_H
 #define __ASMi386_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+//typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASMi386_HDREG_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/ide.h linux-2.4.21/include/asm-i386/ide.h
--- linux-2.4.20/include/asm-i386/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-i386/ide.h	2002-12-18 18:58:03.000000000 +0000
@@ -23,8 +23,6 @@
 # endif
 #endif
 
-#define ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	switch (base) {
@@ -79,6 +77,7 @@
 	int index;
 
 	for(index = 0; index < MAX_HWIFS; index++) {
+		memset(&hw, 0, sizeof hw);
 		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
 		hw.irq = ide_default_irq(ide_default_io_base(index));
 		ide_register_hw(&hw, NULL);
@@ -86,42 +85,7 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#define ide_check_region(from,extent)		check_region((from), (extent))
-#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
-#define ide_release_region(from,extent)		release_region((from), (extent))
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+#include <asm-generic/ide_iops.h>
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/io.h linux-2.4.21/include/asm-i386/io.h
--- linux-2.4.20/include/asm-i386/io.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-i386/io.h	2002-12-18 18:58:08.000000000 +0000
@@ -187,9 +187,9 @@
 #define __raw_writew writew
 #define __raw_writel writel
 
-#define memset_io(a,b,c)	memset(__io_virt(a),(b),(c))
-#define memcpy_fromio(a,b,c)	memcpy((a),__io_virt(b),(c))
-#define memcpy_toio(a,b,c)	memcpy(__io_virt(a),(b),(c))
+#define memset_io(a,b,c)	__memset(__io_virt(a),(b),(c))
+#define memcpy_fromio(a,b,c)	__memcpy((a),__io_virt(b),(c))
+#define memcpy_toio(a,b,c)	__memcpy(__io_virt(a),(b),(c))
 
 /*
  * ISA space is 'always mapped' on a typical x86 system, no need to
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/io_apic.h linux-2.4.21/include/asm-i386/io_apic.h
--- linux-2.4.20/include/asm-i386/io_apic.h	2002-02-25 19:38:12.000000000 +0000
+++ linux-2.4.21/include/asm-i386/io_apic.h	2002-12-18 18:58:10.000000000 +0000
@@ -97,7 +97,7 @@
 extern int mp_irq_entries;
 
 /* MP IRQ source entries */
-extern struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
+extern struct mpc_config_intsrc *mp_irqs;
 
 /* non-0 if default (table-less) MP configuration */
 extern int mpc_default_type;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/mpspec.h linux-2.4.21/include/asm-i386/mpspec.h
--- linux-2.4.20/include/asm-i386/mpspec.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-i386/mpspec.h	2002-12-18 18:58:01.000000000 +0000
@@ -15,12 +15,13 @@
 
 /*
  * a maximum of 16 APICs with the current APIC ID architecture.
+ * xAPICs can have up to 256.  SAPICs have 16 ID bits.
  */
-#ifdef CONFIG_MULTIQUAD
+#ifdef CONFIG_X86_CLUSTERED_APIC
 #define MAX_APICS 256
-#else /* !CONFIG_MULTIQUAD */
+#else
 #define MAX_APICS 16
-#endif /* CONFIG_MULTIQUAD */
+#endif
 
 #define MAX_MPC_ENTRY 1024
 
@@ -197,11 +198,11 @@
 	MP_BUS_PCI,
 	MP_BUS_MCA
 };
-extern int mp_bus_id_to_type [MAX_MP_BUSSES];
-extern int mp_bus_id_to_node [MAX_MP_BUSSES];
-extern int mp_bus_id_to_local [MAX_MP_BUSSES];
+extern int *mp_bus_id_to_type;
+extern int *mp_bus_id_to_node;
+extern int *mp_bus_id_to_local;
+extern int *mp_bus_id_to_pci_bus;
 extern int quad_local_to_mp_bus_id [NR_CPUS/4][4];
-extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
 
 extern unsigned int boot_cpu_physical_apicid;
 extern unsigned long phys_cpu_present_map;
@@ -210,11 +211,9 @@
 extern void get_smp_config (void);
 extern int nr_ioapics;
 extern int apic_version [MAX_APICS];
-extern int mp_bus_id_to_type [MAX_MP_BUSSES];
 extern int mp_irq_entries;
-extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES];
+extern struct mpc_config_intsrc *mp_irqs;
 extern int mpc_default_type;
-extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
 extern int mp_current_pci_id;
 extern unsigned long mp_lapic_addr;
 extern int pic_mode;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/smpboot.h linux-2.4.21/include/asm-i386/smpboot.h
--- linux-2.4.20/include/asm-i386/smpboot.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-i386/smpboot.h	2002-12-18 18:58:07.000000000 +0000
@@ -8,54 +8,74 @@
 	CLUSTERED_APIC_NUMAQ
 };
 
-#ifdef CONFIG_MULTIQUAD
- #define clustered_apic_mode (CLUSTERED_APIC_NUMAQ)
-#else /* !CONFIG_MULTIQUAD */
- #define clustered_apic_mode (CLUSTERED_APIC_NONE)
-#endif /* CONFIG_MULTIQUAD */
-
-#ifdef CONFIG_X86_LOCAL_APIC
+#ifdef CONFIG_X86_CLUSTERED_APIC
+extern unsigned int apic_broadcast_id;
+extern unsigned char clustered_apic_mode;
 extern unsigned char esr_disable;
-static inline int target_cpus(void)
+extern unsigned char int_delivery_mode;
+extern unsigned int int_dest_addr_mode;
+extern int cyclone_setup(char*);
+
+static inline void detect_clustered_apic(char* oem, char* prod)
 {
-	switch(clustered_apic_mode){
-		case CLUSTERED_APIC_NUMAQ:
-			/* Broadcast intrs to local quad only. */
-			return APIC_BROADCAST_ID_APIC;
-		default:
+	/*
+	 * Can't recognize Summit xAPICs at present, so use the OEM ID.
+	 */
+	if (!strncmp(oem, "IBM ENSW", 8) && !strncmp(prod, "VIGIL SMP", 9)){
+		clustered_apic_mode = CLUSTERED_APIC_XAPIC;
+		apic_broadcast_id = APIC_BROADCAST_ID_XAPIC;
+		int_dest_addr_mode = APIC_DEST_PHYSICAL;
+		int_delivery_mode = dest_Fixed;
+		esr_disable = 1;
+		/*Start cyclone clock*/
+		cyclone_setup(0);
+	}
+	else if (!strncmp(oem, "IBM NUMA", 8)){
+		clustered_apic_mode = CLUSTERED_APIC_NUMAQ;
+		apic_broadcast_id = APIC_BROADCAST_ID_APIC;
+		int_dest_addr_mode = APIC_DEST_LOGICAL;
+		int_delivery_mode = dest_LowestPrio;
+		esr_disable = 1;
 	}
-	return cpu_online_map;
 }
-#ifdef CONFIG_X86_IO_APIC
-extern unsigned char int_delivery_mode;
-extern unsigned int int_dest_addr_mode;
 #define	INT_DEST_ADDR_MODE (int_dest_addr_mode)
 #define	INT_DELIVERY_MODE (int_delivery_mode)
-#endif /* CONFIG_X86_IO_APIC */
-#else /* CONFIG_X86_LOCAL_APIC */
+#else /* CONFIG_X86_CLUSTERED_APIC */
+#define apic_broadcast_id (APIC_BROADCAST_ID_APIC)
+#define clustered_apic_mode (CLUSTERED_APIC_NONE)
 #define esr_disable (0)
-#define target_cpus() (0x01)
-#ifdef CONFIG_X86_IO_APIC
+#define detect_clustered_apic(x,y)
 #define INT_DEST_ADDR_MODE (APIC_DEST_LOGICAL)	/* logical delivery */
 #define INT_DELIVERY_MODE (dest_LowestPrio)
-#endif /* CONFIG_X86_IO_APIC */
-#endif /* CONFIG_X86_LOCAL_APIC */
+#endif /* CONFIG_X86_CLUSTERED_APIC */
+#define BAD_APICID 0xFFu
 
 #define TRAMPOLINE_LOW phys_to_virt((clustered_apic_mode == CLUSTERED_APIC_NUMAQ)?0x8:0x467)
 #define TRAMPOLINE_HIGH phys_to_virt((clustered_apic_mode == CLUSTERED_APIC_NUMAQ)?0xa:0x469)
 
 #define boot_cpu_apicid ((clustered_apic_mode == CLUSTERED_APIC_NUMAQ)?boot_cpu_logical_apicid:boot_cpu_physical_apicid)
 
+extern unsigned char raw_phys_apicid[NR_CPUS];
+
 /*
  * How to map from the cpu_present_map
  */
 static inline int cpu_present_to_apicid(int mps_cpu)
 {
+	if (clustered_apic_mode == CLUSTERED_APIC_XAPIC)
+		return raw_phys_apicid[mps_cpu];
 	if(clustered_apic_mode == CLUSTERED_APIC_NUMAQ)
 		return (mps_cpu/4)*16 + (1<<(mps_cpu%4));
 	return mps_cpu;
 }
 
+static inline unsigned long apicid_to_phys_cpu_present(int apicid)
+{
+	if(clustered_apic_mode)
+		return 1UL << (((apicid >> 4) << 2) + (apicid & 0x3));
+	return 1UL << apicid;
+}
+
 #define physical_to_logical_apicid(phys_apic) ( (1ul << (phys_apic & 0x3)) | (phys_apic & 0xF0u) )
 
 /*
@@ -79,4 +99,23 @@
 #define cpu_to_boot_apicid(cpu) cpu_2_physical_apicid[cpu]
 #endif /* CONFIG_MULTIQUAD */
 
+#ifdef CONFIG_X86_CLUSTERED_APIC
+static inline int target_cpus(void)
+{
+	static int cpu;
+	switch(clustered_apic_mode){
+		case CLUSTERED_APIC_NUMAQ:
+			/* Broadcast intrs to local quad only. */
+			return APIC_BROADCAST_ID_APIC;
+		case CLUSTERED_APIC_XAPIC:
+			/*round robin the interrupts*/
+			cpu = (cpu+1)%smp_num_cpus;
+			return cpu_to_physical_apicid(cpu);
+		default:
+	}
+	return cpu_online_map;
+}
+#else
+#define target_cpus() (0x01)
+#endif
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/system.h linux-2.4.21/include/asm-i386/system.h
--- linux-2.4.20/include/asm-i386/system.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-i386/system.h	2002-12-18 18:58:01.000000000 +0000
@@ -322,8 +322,18 @@
 /* used in the idle loop; sti takes one instruction cycle to complete */
 #define safe_halt()		__asm__ __volatile__("sti; hlt": : :"memory")
 
+#define __save_and_cli(x)	do { __save_flags(x); __cli(); } while(0);
+#define __save_and_sti(x)	do { __save_flags(x); __sti(); } while(0);
+
 /* For spinlocks etc */
+#if 0
 #define local_irq_save(x)	__asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
+#define local_irq_set(x)	__asm__ __volatile__("pushfl ; popl %0 ; sti":"=g" (x): /* no input */ :"memory")
+#else
+#define local_irq_save(x)	__save_and_cli(x)
+#define local_irq_set(x)	__save_and_sti(x)
+#endif
+
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
@@ -338,6 +348,8 @@
 #define sti() __global_sti()
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0);
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
 
 #else
 
@@ -345,6 +357,8 @@
 #define sti() __sti()
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
+#define save_and_cli(x) __save_and_cli(x)
+#define save_and_sti(x) __save_and_sti(x)
 
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/acpi.h linux-2.4.21/include/asm-ia64/acpi.h
--- linux-2.4.20/include/asm-ia64/acpi.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/acpi.h	2002-12-18 18:58:07.000000000 +0000
@@ -56,7 +56,7 @@
 
 #define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
 	do { \
-	__asm__ volatile ("1:  ld4      r29=%1\n"  \
+	__asm__ volatile ("1:  ld4      r29=[%1]\n"  \
 		";;\n"                  \
 		"mov    ar.ccv=r29\n"   \
 		"mov    r2=r29\n"       \
@@ -68,7 +68,7 @@
 		";;\n"                  \
 		"add    r29=r29,r30\n"  \
 		";;\n"                  \
-		"cmpxchg4.acq   r30=%1,r29,ar.ccv\n" \
+		"cmpxchg4.acq   r30=[%1],r29,ar.ccv\n" \
 		";;\n"                  \
 		"cmp.eq p6,p7=r2,r30\n" \
 		"(p7) br.dpnt.few 1b\n" \
@@ -76,24 +76,24 @@
 		";;\n"                  \
 		"(p8) mov %0=-1\n"      \
 		"(p9) mov %0=r0\n"      \
-		:"=r"(Acq):"m"(GLptr):"r2","r29","r30","memory"); \
+		:"=r"(Acq):"r"(GLptr):"r2","r29","r30","memory"); \
 	} while (0)
 
 #define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \
 	do { \
-	__asm__ volatile ("1:  ld4      r29=%1\n" \
+	__asm__ volatile ("1:  ld4      r29=[%1]\n" \
 		";;\n"                  \
 		"mov    ar.ccv=r29\n"   \
 		"mov    r2=r29\n"       \
 		"and    r29=-4,r29\n"   \
 		";;\n"                  \
-		"cmpxchg4.acq   r30=%1,r29,ar.ccv\n" \
+		"cmpxchg4.acq   r30=[%1],r29,ar.ccv\n" \
 		";;\n"                  \
 		"cmp.eq p6,p7=r2,r30\n" \
 		"(p7) br.dpnt.few 1b\n" \
 		"and    %0=1,r2\n"      \
 		";;\n"                  \
-		:"=r"(Acq):"m"(GLptr):"r2","r29","r30","memory"); \
+		:"=r"(Acq):"r"(GLptr):"r2","r29","r30","memory"); \
 	} while (0)
 
 const char *acpi_get_sysname (void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/hdreg.h linux-2.4.21/include/asm-ia64/hdreg.h
--- linux-2.4.20/include/asm-ia64/hdreg.h	2000-02-07 02:42:40.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/hdreg.h	2002-12-18 18:58:07.000000000 +0000
@@ -7,6 +7,7 @@
 #ifndef __ASM_IA64_HDREG_H
 #define __ASM_IA64_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+//typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASM_IA64_HDREG_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/ia32.h linux-2.4.21/include/asm-ia64/ia32.h
--- linux-2.4.20/include/asm-ia64/ia32.h	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/ia32.h	2002-12-18 18:58:12.000000000 +0000
@@ -73,6 +73,17 @@
        unsigned short exponent;
 };
 
+struct _fpxreg_ia32 {
+        unsigned short significand[4];
+        unsigned short exponent;
+        unsigned short padding[3];
+};
+
+struct _xmmreg_ia32 {
+        unsigned int element[4];
+};
+
+
 struct _fpstate_ia32 {
        unsigned int    cw,
 		       sw,
@@ -82,7 +93,16 @@
 		       dataoff,
 		       datasel;
        struct _fpreg_ia32      _st[8];
-       unsigned int    status;
+       unsigned short  status;
+       unsigned short  magic;          /* 0xffff = regular FPU data only */
+
+       /* FXSR FPU environment */
+       unsigned int         _fxsr_env[6];   /* FXSR FPU env is ignored */
+       unsigned int         mxcsr;
+       unsigned int         reserved;
+       struct _fpxreg_ia32  _fxsr_st[8];    /* FXSR FPU reg data is ignored */
+       struct _xmmreg_ia32  _xmm[8];
+       unsigned int         padding[56];
 };
 
 struct sigcontext_ia32 {
@@ -110,6 +130,44 @@
        unsigned int cr2;
 };
 
+/* user.h */
+/*
+ * IA32 (Pentium III/4) FXSR, SSE support
+ *
+ * Provide support for the GDB 5.0+ PTRACE_{GET|SET}FPXREGS requests for
+ * interacting with the FXSR-format floating point environment.  Floating
+ * point data can be accessed in the regular format in the usual manner,
+ * and both the standard and SIMD floating point data can be accessed via
+ * the new ptrace requests.  In either case, changes to the FPU environment
+ * will be reflected in the task's state as expected.
+ */
+struct ia32_user_i387_struct {
+	int	cwd;
+	int	swd;
+	int	twd;
+	int	fip;
+	int	fcs;
+	int	foo;
+	int	fos;
+	int	st_space[20];	/* 8*10 bytes for each FP-reg = 80 bytes */
+};
+
+struct ia32_user_fxsr_struct {
+	unsigned short	cwd;
+	unsigned short	swd;
+	unsigned short	twd;
+	unsigned short	fop;
+	int	fip;
+	int	fcs;
+	int	foo;
+	int	fos;
+	int	mxcsr;
+	int	reserved;
+	int	st_space[32];	/* 8*16 bytes for each FP-reg = 128 bytes */
+	int	xmm_space[32];	/* 8*16 bytes for each XMM-reg = 128 bytes */
+	int	padding[56];
+};
+
 /* signal.h */
 #define _IA32_NSIG	       64
 #define _IA32_NSIG_BPW	       32
@@ -443,6 +501,8 @@
 #define IA32_PTRACE_SETREGS	13
 #define IA32_PTRACE_GETFPREGS	14
 #define IA32_PTRACE_SETFPREGS	15
+#define IA32_PTRACE_GETFPXREGS	18
+#define IA32_PTRACE_SETFPXREGS	19
 
 #define ia32_start_thread(regs,new_ip,new_sp) do {				\
 	set_fs(USER_DS);							\
@@ -485,6 +545,18 @@
 extern unsigned long ia32_do_mmap (struct file *, unsigned long, unsigned long, int, int, loff_t);
 extern void ia32_load_segment_descriptors (struct task_struct *task);
 
+#define ia32f2ia64f(dst,src) \
+	do { \
+	register double f6 asm ("f6"); \
+	asm volatile ("ldfe f6=[%2];; stf.spill [%1]=f6" : "=f"(f6): "r"(dst), "r"(src) : "memory"); \
+	} while(0)
+
+#define ia64f2ia32f(dst,src) \
+	do { \
+	register double f6 asm ("f6"); \
+	asm volatile ("ldf.fill f6=[%2];; stfe [%1]=f6" : "=f"(f6): "r"(dst),  "r"(src) : "memory"); \
+	} while(0)
+
 #endif /* !CONFIG_IA32_SUPPORT */
 
 #endif /* _ASM_IA64_IA32_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/ide.h linux-2.4.21/include/asm-ia64/ide.h
--- linux-2.4.20/include/asm-ia64/ide.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/ide.h	2002-12-18 18:58:01.000000000 +0000
@@ -25,8 +25,6 @@
 # endif
 #endif
 
-#define ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	switch (base) {
@@ -88,42 +86,7 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#define ide_check_region(from,extent)		check_region((from), (extent))
-#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
-#define ide_release_region(from,extent)		release_region((from), (extent))
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+#include <asm-generic/ide_iops.h>
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/io.h linux-2.4.21/include/asm-ia64/io.h
--- linux-2.4.20/include/asm-ia64/io.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/io.h	2002-12-18 18:58:02.000000000 +0000
@@ -13,7 +13,7 @@
  * over and over again with slight variations and possibly making a
  * mistake somewhere.
  *
- * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2002 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
  * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
@@ -261,9 +261,9 @@
 }
 
 /*
- * Unfortunately, some platforms are broken and do not follow the
- * IA-64 architecture specification regarding legacy I/O support.
- * Thus, we have to make these operations platform dependent...
+ * Unfortunately, some platforms are broken and do not follow the IA-64 architecture
+ * specification regarding legacy I/O support.  Thus, we have to make these operations
+ * platform dependent...
  */
 #define __inb		platform_inb
 #define __inw		platform_inw
@@ -272,18 +272,18 @@
 #define __outw		platform_outw
 #define __outl		platform_outl
 
-#define inb		__inb
-#define inw		__inw
-#define inl		__inl
-#define insb		__insb
-#define insw		__insw
-#define insl		__insl
-#define outb		__outb
-#define outw		__outw
-#define outl		__outl
-#define outsb		__outsb
-#define outsw		__outsw
-#define outsl		__outsl
+#define inb(p)		__inb(p)
+#define inw(p)		__inw(p)
+#define inl(p)		__inl(p)
+#define insb(p,d,c)	__insb(p,d,c)
+#define insw(p,d,c)	__insw(p,d,c)
+#define insl(p,d,c)	__insl(p,d,c)
+#define outb(v,p)	__outb(v,p)
+#define outw(v,p)	__outw(v,p)
+#define outl(v,p)	__outl(v,p)
+#define outsb(p,s,c)	__outsb(p,s,c)
+#define outsw(p,s,c)	__outsw(p,s,c)
+#define outsl(p,s,c)	__outsl(p,s,c)
 
 /*
  * The address passed to these functions are ioremap()ped already.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/machvec.h linux-2.4.21/include/asm-ia64/machvec.h
--- linux-2.4.20/include/asm-ia64/machvec.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/machvec.h	2002-12-18 18:58:01.000000000 +0000
@@ -25,7 +25,7 @@
 typedef void ia64_mv_irq_init_t (void);
 typedef void ia64_mv_pci_fixup_t (int);
 typedef void ia64_mv_pci_enable_device_t (struct pci_dev *);
-typedef unsigned long ia64_mv_map_nr_t (unsigned long);
+typedef unsigned long ia64_mv_map_nr_t (void *);
 typedef void ia64_mv_mca_init_t (void);
 typedef void ia64_mv_mca_handler_t (void);
 typedef void ia64_mv_cmci_handler_t (int, void *, struct pt_regs *);
@@ -46,7 +46,6 @@
 typedef void ia64_mv_pci_unmap_sg (struct pci_dev *, struct scatterlist *, int, int);
 typedef void ia64_mv_pci_dma_sync_single (struct pci_dev *, dma_addr_t, size_t, int);
 typedef void ia64_mv_pci_dma_sync_sg (struct pci_dev *, struct scatterlist *, int, int);
-typedef unsigned long ia64_mv_pci_dma_address (struct scatterlist *);
 typedef int ia64_mv_pci_dma_supported (struct pci_dev *, u64);
 
 /*
@@ -104,7 +103,6 @@
 #  define platform_pci_unmap_sg		ia64_mv.unmap_sg
 #  define platform_pci_dma_sync_single	ia64_mv.sync_single
 #  define platform_pci_dma_sync_sg	ia64_mv.sync_sg
-#  define platform_pci_dma_address	ia64_mv.dma_address
 #  define platform_pci_dma_supported	ia64_mv.dma_supported
 #  define platform_irq_desc		ia64_mv.irq_desc
 #  define platform_irq_to_vector	ia64_mv.irq_to_vector
@@ -140,7 +138,6 @@
 	ia64_mv_pci_unmap_sg *unmap_sg;
 	ia64_mv_pci_dma_sync_single *sync_single;
 	ia64_mv_pci_dma_sync_sg *sync_sg;
-	ia64_mv_pci_dma_address *dma_address;
 	ia64_mv_pci_dma_supported *dma_supported;
 	ia64_mv_irq_desc *irq_desc;
 	ia64_mv_irq_to_vector *irq_to_vector;
@@ -177,7 +174,6 @@
 	platform_pci_unmap_sg,			\
 	platform_pci_dma_sync_single,		\
 	platform_pci_dma_sync_sg,		\
-	platform_pci_dma_address,		\
 	platform_pci_dma_supported,		\
 	platform_irq_desc,			\
 	platform_irq_to_vector,			\
@@ -209,7 +205,6 @@
 extern ia64_mv_pci_unmap_sg swiotlb_unmap_sg;
 extern ia64_mv_pci_dma_sync_single swiotlb_sync_single;
 extern ia64_mv_pci_dma_sync_sg swiotlb_sync_sg;
-extern ia64_mv_pci_dma_address swiotlb_dma_address;
 extern ia64_mv_pci_dma_supported swiotlb_pci_dma_supported;
 
 /*
@@ -276,9 +271,6 @@
 #ifndef platform_pci_dma_sync_sg
 # define platform_pci_dma_sync_sg	swiotlb_sync_sg
 #endif
-#ifndef platform_pci_dma_address
-# define  platform_pci_dma_address	swiotlb_dma_address
-#endif
 #ifndef platform_pci_dma_supported
 # define  platform_pci_dma_supported	swiotlb_pci_dma_supported
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/machvec_hpzx1.h linux-2.4.21/include/asm-ia64/machvec_hpzx1.h
--- linux-2.4.20/include/asm-ia64/machvec_hpzx1.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/machvec_hpzx1.h	2002-12-18 18:58:01.000000000 +0000
@@ -11,7 +11,6 @@
 extern ia64_mv_pci_unmap_single sba_unmap_single;
 extern ia64_mv_pci_map_sg sba_map_sg;
 extern ia64_mv_pci_unmap_sg sba_unmap_sg;
-extern ia64_mv_pci_dma_address sba_dma_address;
 extern ia64_mv_pci_dma_supported sba_dma_supported;
 
 /*
@@ -35,7 +34,6 @@
 #define platform_pci_unmap_sg		sba_unmap_sg
 #define platform_pci_dma_sync_single	((ia64_mv_pci_dma_sync_single *) machvec_noop)
 #define platform_pci_dma_sync_sg	((ia64_mv_pci_dma_sync_sg *) machvec_noop)
-#define platform_pci_dma_address	sba_dma_address
 #define platform_pci_dma_supported	sba_dma_supported
 
 #endif /* _ASM_IA64_MACHVEC_HPZX1_h */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/machvec_sn1.h linux-2.4.21/include/asm-ia64/machvec_sn1.h
--- linux-2.4.20/include/asm-ia64/machvec_sn1.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/machvec_sn1.h	2002-12-18 18:58:10.000000000 +0000
@@ -58,7 +58,6 @@
 extern ia64_mv_pci_unmap_sg		sn_pci_unmap_sg;
 extern ia64_mv_pci_dma_sync_single	sn_pci_dma_sync_single;
 extern ia64_mv_pci_dma_sync_sg		sn_pci_dma_sync_sg;
-extern ia64_mv_pci_dma_address		sn_dma_address;
 extern ia64_mv_pci_dma_supported	sn_pci_dma_supported;
 
 /*
@@ -95,7 +94,6 @@
 #define platform_pci_unmap_sg		sn_pci_unmap_sg
 #define platform_pci_dma_sync_single	sn_pci_dma_sync_single
 #define platform_pci_dma_sync_sg	sn_pci_dma_sync_sg
-#define platform_pci_dma_address	sn_dma_address
 #define platform_pci_dma_supported	sn_pci_dma_supported
 
 #endif /* _ASM_IA64_MACHVEC_SN1_h */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/machvec_sn2.h linux-2.4.21/include/asm-ia64/machvec_sn2.h
--- linux-2.4.20/include/asm-ia64/machvec_sn2.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/machvec_sn2.h	2002-12-18 18:58:01.000000000 +0000
@@ -58,7 +58,6 @@
 extern ia64_mv_pci_unmap_sg		sn_pci_unmap_sg;
 extern ia64_mv_pci_dma_sync_single	sn_pci_dma_sync_single;
 extern ia64_mv_pci_dma_sync_sg		sn_pci_dma_sync_sg;
-extern ia64_mv_pci_dma_address		sn_dma_address;
 extern ia64_mv_pci_dma_supported	sn_pci_dma_supported;
 
 /*
@@ -95,7 +94,6 @@
 #define platform_pci_unmap_sg		sn_pci_unmap_sg
 #define platform_pci_dma_sync_single	sn_pci_dma_sync_single
 #define platform_pci_dma_sync_sg	sn_pci_dma_sync_sg
-#define platform_pci_dma_address	sn_dma_address
 #define platform_pci_dma_supported	sn_pci_dma_supported
 
 #endif /* _ASM_IA64_MACHVEC_SN2_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/mc146818rtc.h linux-2.4.21/include/asm-ia64/mc146818rtc.h
--- linux-2.4.20/include/asm-ia64/mc146818rtc.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/mc146818rtc.h	2002-12-18 18:58:05.000000000 +0000
@@ -0,0 +1,10 @@
+#ifndef _ASM_IA64_MC146818RTC_H
+#define _ASM_IA64_MC146818RTC_H
+
+/*
+ * Machine dependent access functions for RTC registers.
+ */
+
+/* empty include file to satisfy the include in genrtc.c */
+
+#endif /* _ASM_IA64_MC146818RTC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/mca.h linux-2.4.21/include/asm-ia64/mca.h
--- linux-2.4.20/include/asm-ia64/mca.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/mca.h	2002-12-18 18:58:04.000000000 +0000
@@ -103,6 +103,8 @@
 	IA64_MCA_NEW_CONTEXT	=	-1	/* SAL to return to new context */
 };
 
+#define MIN_STATE_AREA_SIZE     57
+
 typedef struct ia64_mca_os_to_sal_state_s {
 	u64		imots_os_status;	/*   OS status to SAL as to what happened
 						 *   with the MCA handling.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/mca_asm.h linux-2.4.21/include/asm-ia64/mca_asm.h
--- linux-2.4.20/include/asm-ia64/mca_asm.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/mca_asm.h	2002-12-18 18:58:11.000000000 +0000
@@ -16,6 +16,7 @@
 #define PSR_I		14
 #define	PSR_DT		17
 #define PSR_RT		27
+#define PSR_MC		35
 #define PSR_IT		36
 #define PSR_BN		44
 
@@ -107,6 +108,8 @@
 	;;										\
 	dep	temp1 = 0, temp1, PSR_IC, 1;						\
 	;;										\
+	dep	temp1 = -1, temp1, PSR_MC, 1;						\
+	;;										\
 	movl	temp2 = start_addr;							\
 	mov	cr.ipsr = temp1;							\
 	;;										\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/mmu.h linux-2.4.21/include/asm-ia64/mmu.h
--- linux-2.4.20/include/asm-ia64/mmu.h	2000-12-29 22:07:23.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/mmu.h	2002-12-18 18:58:02.000000000 +0000
@@ -1,7 +1,11 @@
 #ifndef __MMU_H
 #define __MMU_H
 
-/* Default "unsigned long" context */
-typedef unsigned long mm_context_t;
+/*
+ * Type for a context number.  We declare it volatile to ensure proper ordering when it's
+ * accessed outside of spinlock'd critical sections (e.g., as done in activate_mm() and
+ * init_new_context()).
+ */
+typedef volatile unsigned long mm_context_t;
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/mmu_context.h linux-2.4.21/include/asm-ia64/mmu_context.h
--- linux-2.4.20/include/asm-ia64/mmu_context.h	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/mmu_context.h	2002-12-18 18:58:03.000000000 +0000
@@ -44,26 +44,32 @@
 {
 }
 
-static inline void
-get_new_mmu_context (struct mm_struct *mm)
+static inline mm_context_t
+get_mmu_context (struct mm_struct *mm)
 {
+	mm_context_t context = mm->context;
+
+	if (context)
+		return context;
+
 	spin_lock(&ia64_ctx.lock);
 	{
-		if (ia64_ctx.next >= ia64_ctx.limit)
-			wrap_mmu_context(mm);
-		mm->context = ia64_ctx.next++;
+		/* re-check, now that we've got the lock: */
+		context = mm->context;
+		if (context == 0) {
+			if (ia64_ctx.next >= ia64_ctx.limit)
+				wrap_mmu_context(mm);
+			mm->context = context = ia64_ctx.next++;
+		}
 	}
 	spin_unlock(&ia64_ctx.lock);
-
-}
-
-static inline void
-get_mmu_context (struct mm_struct *mm)
-{
-	if (mm->context == 0)
-		get_new_mmu_context(mm);
+	return context;
 }
 
+/*
+ * Initialize context number to some sane value.  MM is guaranteed to be a brand-new
+ * address-space, so no TLB flushing is needed, ever.
+ */
 static inline int
 init_new_context (struct task_struct *p, struct mm_struct *mm)
 {
@@ -78,13 +84,13 @@
 }
 
 static inline void
-reload_context (struct mm_struct *mm)
+reload_context (mm_context_t context)
 {
 	unsigned long rid;
 	unsigned long rid_incr = 0;
 	unsigned long rr0, rr1, rr2, rr3, rr4;
 
-	rid = mm->context << 3;	/* make space for encoding the region number */
+	rid = context << 3;	/* make space for encoding the region number */
 	rid_incr = 1 << 8;
 
 	/* encode the region id, preferred page size, and VHPT enable bit: */
@@ -103,6 +109,18 @@
 	ia64_insn_group_barrier();
 }
 
+static inline void
+activate_context (struct mm_struct *mm)
+{
+	mm_context_t context;
+
+	do {
+		context = get_mmu_context(mm);
+		reload_context(context);
+		/* in the unlikely event of a TLB-flush by another thread, redo the load: */
+	} while (unlikely(context != mm->context));
+}
+
 /*
  * Switch from address space PREV to address space NEXT.
  */
@@ -110,12 +128,11 @@
 activate_mm (struct mm_struct *prev, struct mm_struct *next)
 {
 	/*
-	 * We may get interrupts here, but that's OK because interrupt
-	 * handlers cannot touch user-space.
+	 * We may get interrupts here, but that's OK because interrupt handlers cannot
+	 * touch user-space.
 	 */
 	ia64_set_kr(IA64_KR_PT_BASE, __pa(next->pgd));
-	get_mmu_context(next);
-	reload_context(next);
+	activate_context(next);
 }
 
 #define switch_mm(prev_mm,next_mm,next_task,cpu)	activate_mm(prev_mm, next_mm)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/offsets.h linux-2.4.21/include/asm-ia64/offsets.h
--- linux-2.4.20/include/asm-ia64/offsets.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/offsets.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,142 +0,0 @@
-#ifndef _ASM_IA64_OFFSETS_H
-#define _ASM_IA64_OFFSETS_H
-/*
- * DO NOT MODIFY
- *
- * This file was generated by arch/ia64/tools/print_offsets.awk.
- *
- */
-#define PT_PTRACED_BIT		0
-#define PT_TRACESYS_BIT		1
-#define IA64_TASK_SIZE			3424	/* 0xd60 */
-#define IA64_PT_REGS_SIZE		400	/* 0x190 */
-#define IA64_SWITCH_STACK_SIZE		560	/* 0x230 */
-#define IA64_SIGINFO_SIZE		128	/* 0x80 */
-#define IA64_CPU_SIZE			16384	/* 0x4000 */
-#define SIGFRAME_SIZE			2816	/* 0xb00 */
-#define UNW_FRAME_INFO_SIZE		448	/* 0x1c0 */
-
-#define IA64_TASK_PTRACE_OFFSET		48	/* 0x30 */
-#define IA64_TASK_SIGPENDING_OFFSET	16	/* 0x10 */
-#define IA64_TASK_NEED_RESCHED_OFFSET	40	/* 0x28 */
-#define IA64_TASK_PROCESSOR_OFFSET	96	/* 0x60 */
-#define IA64_TASK_THREAD_OFFSET		992	/* 0x3e0 */
-#define IA64_TASK_THREAD_KSP_OFFSET	992	/* 0x3e0 */
-#define IA64_TASK_PFM_OVFL_BLOCK_RESET_OFFSET 1616	/* 0x650 */
-#define IA64_TASK_PID_OFFSET		228	/* 0xe4 */
-#define IA64_TASK_MM_OFFSET		88	/* 0x58 */
-#define IA64_PT_REGS_CR_IPSR_OFFSET	0	/* 0x0 */
-#define IA64_PT_REGS_CR_IIP_OFFSET	8	/* 0x8 */
-#define IA64_PT_REGS_CR_IFS_OFFSET	16	/* 0x10 */
-#define IA64_PT_REGS_AR_UNAT_OFFSET	24	/* 0x18 */
-#define IA64_PT_REGS_AR_PFS_OFFSET	32	/* 0x20 */
-#define IA64_PT_REGS_AR_RSC_OFFSET	40	/* 0x28 */
-#define IA64_PT_REGS_AR_RNAT_OFFSET	48	/* 0x30 */
-#define IA64_PT_REGS_AR_BSPSTORE_OFFSET	56	/* 0x38 */
-#define IA64_PT_REGS_PR_OFFSET		64	/* 0x40 */
-#define IA64_PT_REGS_B6_OFFSET		72	/* 0x48 */
-#define IA64_PT_REGS_LOADRS_OFFSET	80	/* 0x50 */
-#define IA64_PT_REGS_R1_OFFSET		88	/* 0x58 */
-#define IA64_PT_REGS_R2_OFFSET		96	/* 0x60 */
-#define IA64_PT_REGS_R3_OFFSET		104	/* 0x68 */
-#define IA64_PT_REGS_R12_OFFSET		112	/* 0x70 */
-#define IA64_PT_REGS_R13_OFFSET		120	/* 0x78 */
-#define IA64_PT_REGS_R14_OFFSET		128	/* 0x80 */
-#define IA64_PT_REGS_R15_OFFSET		136	/* 0x88 */
-#define IA64_PT_REGS_R8_OFFSET		144	/* 0x90 */
-#define IA64_PT_REGS_R9_OFFSET		152	/* 0x98 */
-#define IA64_PT_REGS_R10_OFFSET		160	/* 0xa0 */
-#define IA64_PT_REGS_R11_OFFSET		168	/* 0xa8 */
-#define IA64_PT_REGS_R16_OFFSET		176	/* 0xb0 */
-#define IA64_PT_REGS_R17_OFFSET		184	/* 0xb8 */
-#define IA64_PT_REGS_R18_OFFSET		192	/* 0xc0 */
-#define IA64_PT_REGS_R19_OFFSET		200	/* 0xc8 */
-#define IA64_PT_REGS_R20_OFFSET		208	/* 0xd0 */
-#define IA64_PT_REGS_R21_OFFSET		216	/* 0xd8 */
-#define IA64_PT_REGS_R22_OFFSET		224	/* 0xe0 */
-#define IA64_PT_REGS_R23_OFFSET		232	/* 0xe8 */
-#define IA64_PT_REGS_R24_OFFSET		240	/* 0xf0 */
-#define IA64_PT_REGS_R25_OFFSET		248	/* 0xf8 */
-#define IA64_PT_REGS_R26_OFFSET		256	/* 0x100 */
-#define IA64_PT_REGS_R27_OFFSET		264	/* 0x108 */
-#define IA64_PT_REGS_R28_OFFSET		272	/* 0x110 */
-#define IA64_PT_REGS_R29_OFFSET		280	/* 0x118 */
-#define IA64_PT_REGS_R30_OFFSET		288	/* 0x120 */
-#define IA64_PT_REGS_R31_OFFSET		296	/* 0x128 */
-#define IA64_PT_REGS_AR_CCV_OFFSET	304	/* 0x130 */
-#define IA64_PT_REGS_AR_FPSR_OFFSET	312	/* 0x138 */
-#define IA64_PT_REGS_B0_OFFSET		320	/* 0x140 */
-#define IA64_PT_REGS_B7_OFFSET		328	/* 0x148 */
-#define IA64_PT_REGS_F6_OFFSET		336	/* 0x150 */
-#define IA64_PT_REGS_F7_OFFSET		352	/* 0x160 */
-#define IA64_PT_REGS_F8_OFFSET		368	/* 0x170 */
-#define IA64_PT_REGS_F9_OFFSET		384	/* 0x180 */
-#define IA64_SWITCH_STACK_CALLER_UNAT_OFFSET 0	/* 0x0 */
-#define IA64_SWITCH_STACK_AR_FPSR_OFFSET 8	/* 0x8 */
-#define IA64_SWITCH_STACK_F2_OFFSET	16	/* 0x10 */
-#define IA64_SWITCH_STACK_F3_OFFSET	32	/* 0x20 */
-#define IA64_SWITCH_STACK_F4_OFFSET	48	/* 0x30 */
-#define IA64_SWITCH_STACK_F5_OFFSET	64	/* 0x40 */
-#define IA64_SWITCH_STACK_F10_OFFSET	80	/* 0x50 */
-#define IA64_SWITCH_STACK_F11_OFFSET	96	/* 0x60 */
-#define IA64_SWITCH_STACK_F12_OFFSET	112	/* 0x70 */
-#define IA64_SWITCH_STACK_F13_OFFSET	128	/* 0x80 */
-#define IA64_SWITCH_STACK_F14_OFFSET	144	/* 0x90 */
-#define IA64_SWITCH_STACK_F15_OFFSET	160	/* 0xa0 */
-#define IA64_SWITCH_STACK_F16_OFFSET	176	/* 0xb0 */
-#define IA64_SWITCH_STACK_F17_OFFSET	192	/* 0xc0 */
-#define IA64_SWITCH_STACK_F18_OFFSET	208	/* 0xd0 */
-#define IA64_SWITCH_STACK_F19_OFFSET	224	/* 0xe0 */
-#define IA64_SWITCH_STACK_F20_OFFSET	240	/* 0xf0 */
-#define IA64_SWITCH_STACK_F21_OFFSET	256	/* 0x100 */
-#define IA64_SWITCH_STACK_F22_OFFSET	272	/* 0x110 */
-#define IA64_SWITCH_STACK_F23_OFFSET	288	/* 0x120 */
-#define IA64_SWITCH_STACK_F24_OFFSET	304	/* 0x130 */
-#define IA64_SWITCH_STACK_F25_OFFSET	320	/* 0x140 */
-#define IA64_SWITCH_STACK_F26_OFFSET	336	/* 0x150 */
-#define IA64_SWITCH_STACK_F27_OFFSET	352	/* 0x160 */
-#define IA64_SWITCH_STACK_F28_OFFSET	368	/* 0x170 */
-#define IA64_SWITCH_STACK_F29_OFFSET	384	/* 0x180 */
-#define IA64_SWITCH_STACK_F30_OFFSET	400	/* 0x190 */
-#define IA64_SWITCH_STACK_F31_OFFSET	416	/* 0x1a0 */
-#define IA64_SWITCH_STACK_R4_OFFSET	432	/* 0x1b0 */
-#define IA64_SWITCH_STACK_R5_OFFSET	440	/* 0x1b8 */
-#define IA64_SWITCH_STACK_R6_OFFSET	448	/* 0x1c0 */
-#define IA64_SWITCH_STACK_R7_OFFSET	456	/* 0x1c8 */
-#define IA64_SWITCH_STACK_B0_OFFSET	464	/* 0x1d0 */
-#define IA64_SWITCH_STACK_B1_OFFSET	472	/* 0x1d8 */
-#define IA64_SWITCH_STACK_B2_OFFSET	480	/* 0x1e0 */
-#define IA64_SWITCH_STACK_B3_OFFSET	488	/* 0x1e8 */
-#define IA64_SWITCH_STACK_B4_OFFSET	496	/* 0x1f0 */
-#define IA64_SWITCH_STACK_B5_OFFSET	504	/* 0x1f8 */
-#define IA64_SWITCH_STACK_AR_PFS_OFFSET	512	/* 0x200 */
-#define IA64_SWITCH_STACK_AR_LC_OFFSET	520	/* 0x208 */
-#define IA64_SWITCH_STACK_AR_UNAT_OFFSET 528	/* 0x210 */
-#define IA64_SWITCH_STACK_AR_RNAT_OFFSET 536	/* 0x218 */
-#define IA64_SWITCH_STACK_AR_BSPSTORE_OFFSET 544	/* 0x220 */
-#define IA64_SWITCH_STACK_PR_OFFSET	552	/* 0x228 */
-#define IA64_SIGCONTEXT_IP_OFFSET	40	/* 0x28 */
-#define IA64_SIGCONTEXT_AR_BSP_OFFSET	72	/* 0x48 */
-#define IA64_SIGCONTEXT_AR_FPSR_OFFSET	104	/* 0x68 */
-#define IA64_SIGCONTEXT_AR_RNAT_OFFSET	80	/* 0x50 */
-#define IA64_SIGCONTEXT_AR_UNAT_OFFSET	96	/* 0x60 */
-#define IA64_SIGCONTEXT_B0_OFFSET	136	/* 0x88 */
-#define IA64_SIGCONTEXT_CFM_OFFSET	48	/* 0x30 */
-#define IA64_SIGCONTEXT_FLAGS_OFFSET	0	/* 0x0 */
-#define IA64_SIGCONTEXT_FR6_OFFSET	560	/* 0x230 */
-#define IA64_SIGCONTEXT_PR_OFFSET	128	/* 0x80 */
-#define IA64_SIGCONTEXT_R12_OFFSET	296	/* 0x128 */
-#define IA64_SIGCONTEXT_RBS_BASE_OFFSET	2512	/* 0x9d0 */
-#define IA64_SIGCONTEXT_LOADRS_OFFSET	2520	/* 0x9d8 */
-#define IA64_SIGFRAME_ARG0_OFFSET	0	/* 0x0 */
-#define IA64_SIGFRAME_ARG1_OFFSET	8	/* 0x8 */
-#define IA64_SIGFRAME_ARG2_OFFSET	16	/* 0x10 */
-#define IA64_SIGFRAME_HANDLER_OFFSET	24	/* 0x18 */
-#define IA64_SIGFRAME_SIGCONTEXT_OFFSET	160	/* 0xa0 */
-#define IA64_CLONE_VFORK		16384	/* 0x4000 */
-#define IA64_CLONE_VM			256	/* 0x100 */
-#define IA64_CPU_IRQ_COUNT_OFFSET	0	/* 0x0 */
-#define IA64_CPU_BH_COUNT_OFFSET	4	/* 0x4 */
-#define IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET 12	/* 0xc */
-
-#endif /* _ASM_IA64_OFFSETS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/page.h linux-2.4.21/include/asm-ia64/page.h
--- linux-2.4.20/include/asm-ia64/page.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/page.h	2002-12-18 18:58:03.000000000 +0000
@@ -65,13 +65,10 @@
 # define virt_to_page(kaddr)	(mem_map + MAP_NR_DENSE(kaddr))
 # define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
 #endif
-#ifdef CONFIG_VIRTUAL_MEM_MAP
-  struct page;
-  extern int ia64_page_valid (struct page *);
-# define VALID_PAGE(page)	(((page - mem_map) < max_mapnr) && ia64_page_valid(page))
-#else
-# define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
-#endif
+
+struct page;
+extern int ia64_page_valid (struct page *);
+#define VALID_PAGE(page)	(((page - mem_map) < max_mapnr) && ia64_page_valid(page))
 
 typedef union ia64_va {
 	struct {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/pal.h linux-2.4.21/include/asm-ia64/pal.h
--- linux-2.4.20/include/asm-ia64/pal.h	2001-12-21 17:42:03.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/pal.h	2002-12-18 18:58:03.000000000 +0000
@@ -78,6 +78,7 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
+#include <asm/fpu.h>
 
 /*
  * Data types needed to pass information into PAL procedures and
@@ -650,11 +651,43 @@
 extern struct ia64_pal_retval ia64_pal_call_phys_static (u64, u64, u64, u64);
 extern struct ia64_pal_retval ia64_pal_call_phys_stacked (u64, u64, u64, u64);
 
-#define PAL_CALL(iprv,a0,a1,a2,a3)		iprv = ia64_pal_call_static(a0, a1, a2, a3, 0)
-#define PAL_CALL_IC_OFF(iprv,a0,a1,a2,a3)	iprv = ia64_pal_call_static(a0, a1, a2, a3, 1)
-#define PAL_CALL_STK(iprv,a0,a1,a2,a3)		iprv = ia64_pal_call_stacked(a0, a1, a2, a3)
-#define PAL_CALL_PHYS(iprv,a0,a1,a2,a3)		iprv = ia64_pal_call_phys_static(a0, a1, a2, a3)
-#define PAL_CALL_PHYS_STK(iprv,a0,a1,a2,a3)	iprv = ia64_pal_call_phys_stacked(a0, a1, a2, a3)
+extern void ia64_save_scratch_fpregs(struct ia64_fpreg *);
+extern void ia64_load_scratch_fpregs(struct ia64_fpreg *);
+
+#define PAL_CALL(iprv,a0,a1,a2,a3) do {                 \
+	struct ia64_fpreg fr[6];                        \
+	ia64_save_scratch_fpregs(fr);                     \
+	iprv = ia64_pal_call_static(a0, a1, a2, a3, 0); \
+	ia64_load_scratch_fpregs(fr);                  \
+} while (0)
+
+#define PAL_CALL_IC_OFF(iprv,a0,a1,a2,a3) do {          \
+	struct ia64_fpreg fr[6];                        \
+	ia64_save_scratch_fpregs(fr);                     \
+	iprv = ia64_pal_call_static(a0, a1, a2, a3, 1); \
+	ia64_load_scratch_fpregs(fr);                  \
+} while (0)
+
+#define PAL_CALL_STK(iprv,a0,a1,a2,a3) do {             \
+	struct ia64_fpreg fr[6];                        \
+	ia64_save_scratch_fpregs(fr);                     \
+	iprv = ia64_pal_call_stacked(a0, a1, a2, a3);   \
+	ia64_load_scratch_fpregs(fr);                  \
+} while (0)
+
+#define PAL_CALL_PHYS(iprv,a0,a1,a2,a3) do {            \
+	struct ia64_fpreg fr[6];                        \
+	ia64_save_scratch_fpregs(fr);                     \
+	iprv = ia64_pal_call_phys_static(a0, a1, a2, a3);\
+	ia64_load_scratch_fpregs(fr);                  \
+} while (0)
+
+#define PAL_CALL_PHYS_STK(iprv,a0,a1,a2,a3) do {        \
+	struct ia64_fpreg fr[6];                        \
+	ia64_save_scratch_fpregs(fr);                     \
+	iprv = ia64_pal_call_phys_stacked(a0, a1, a2, a3); \
+	ia64_load_scratch_fpregs(fr);                  \
+} while (0)
 
 typedef int (*ia64_pal_handler) (u64, ...);
 extern ia64_pal_handler ia64_pal;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/pci.h linux-2.4.21/include/asm-ia64/pci.h
--- linux-2.4.20/include/asm-ia64/pci.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/pci.h	2002-12-18 18:58:11.000000000 +0000
@@ -26,6 +26,13 @@
 
 struct pci_dev;
 
+/*
+ * The PCI address space does equal the physical memory address space.
+ * The networking and block device layers use this boolean for bounce
+ * buffer decisions.
+ */
+#define PCI_DMA_BUS_IS_PHYS	(1)
+
 static inline void
 pcibios_set_master (struct pci_dev *dev)
 {
@@ -49,7 +56,6 @@
 #define pci_unmap_sg			platform_pci_unmap_sg
 #define pci_dma_sync_single		platform_pci_dma_sync_single
 #define pci_dma_sync_sg			platform_pci_dma_sync_sg
-#define sg_dma_address			platform_pci_dma_address
 #define pci_dma_supported		platform_pci_dma_supported
 
 /* pci_unmap_{single,page} is not a nop, thus... */
@@ -76,7 +82,8 @@
 /* Return the index of the PCI controller for device PDEV. */
 #define pci_controller_num(PDEV)	(0)
 
-#define sg_dma_len(sg)		((sg)->length)
+#define sg_dma_address(sg)	((sg)->dma_address)
+#define sg_dma_len(sg)		((sg)->dma_length)
 
 #define HAVE_PCI_MMAP
 extern int pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/perfmon.h linux-2.4.21/include/asm-ia64/perfmon.h
--- linux-2.4.20/include/asm-ia64/perfmon.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/perfmon.h	2002-12-18 18:58:09.000000000 +0000
@@ -45,6 +45,7 @@
  * PMC flags
  */
 #define PFM_REGFL_OVFL_NOTIFY	0x1	/* send notification on overflow */
+#define PFM_REGFL_RANDOM	0x2	/* randomize sampling interval */
 
 /*
  * PMD/PMC/IBR/DBR return flags (ignored on input)
@@ -85,9 +86,12 @@
 	unsigned long	reg_long_reset;	/* reset after sampling buffer overflow (large) */
 	unsigned long	reg_short_reset;/* reset after counter overflow (small) */
 
-	unsigned long	reg_reset_pmds[4]; /* which other counters to reset on overflow */
+	unsigned long	reg_reset_pmds[4];   /* which other counters to reset on overflow */
+	unsigned long	reg_random_seed;     /* seed value when randomization is used */
+	unsigned long	reg_random_mask;     /* bitmask used to limit random value */
+	unsigned long	reg_last_reset_value;/* last value used to reset the PMD (PFM_READ_PMDS) */
 
-	unsigned long   reserved[16];	/* for future use */
+	unsigned long   reserved[13];	/* for future use */
 } pfarg_reg_t;
 
 typedef struct {
@@ -120,7 +124,7 @@
  * Define the version numbers for both perfmon as a whole and the sampling buffer format.
  */
 #define PFM_VERSION_MAJ		1U
-#define PFM_VERSION_MIN		0U
+#define PFM_VERSION_MIN		2U
 #define PFM_VERSION		(((PFM_VERSION_MAJ&0xffff)<<16)|(PFM_VERSION_MIN & 0xffff))
 
 #define PFM_SMPL_VERSION_MAJ	1U
@@ -141,25 +145,29 @@
  * This should be enough for quite some time. Always check sampling format
  * before parsing entries!
  *
- * Inn the case where multiple counters have overflowed at the same time, the 
- * rate field indicate the initial value of the first PMD, based on the index.
- * For instance, if PMD2 and PMD5 have ovewrflowed for this entry, the rate field
- * will show the initial value of PMD2.
+ * In the case where multiple counters overflow at the same time, the
+ * last_reset_value member indicates the initial value of the PMD with
+ * the smallest index.  For instance, if PMD2 and PMD5 have overflowed,
+ * the last_reset_value member contains the initial value of PMD2.
  */
 typedef struct {
-	int		pid;		/* identification of process */
-	int		cpu;		/* which cpu was used */
-	unsigned long	rate;		/* initial value of overflowed counter */
-	unsigned long	stamp;		/* timestamp */
-	unsigned long	ip;		/* where did the overflow interrupt happened */
-	unsigned long	regs;		/* bitmask of which registers overflowed */
-	unsigned long   period;		/* sampling period used by overflowed counter (smallest pmd index) */
+	int		pid;		 /* identification of process */
+	int		cpu;		 /* which cpu was used */
+	unsigned long	last_reset_value;/* initial value of overflowed counter */
+	unsigned long	stamp;		 /* timestamp (unique per CPU) */
+	unsigned long	ip;		 /* where did the overflow interrupt happened */
+	unsigned long	regs;		 /* bitmask of which registers overflowed */
+	unsigned long   period;		 /* sampling period used by overflowed counter (smallest pmd index) */
 } perfmon_smpl_entry_t;
 
 extern int perfmonctl(pid_t pid, int cmd, void *arg, int narg);
 
 #ifdef __KERNEL__
 
+typedef struct {
+	void (*handler)(int irq, void *arg, struct pt_regs *regs);
+} pfm_intr_handler_desc_t;
+
 extern void pfm_save_regs (struct task_struct *);
 extern void pfm_load_regs (struct task_struct *);
 
@@ -172,7 +180,14 @@
 extern int  pfm_release_debug_registers(struct task_struct *);
 extern int  pfm_cleanup_smpl_buf(struct task_struct *);
 extern void pfm_syst_wide_update_task(struct task_struct *, int);
-extern void perfmon_init_percpu(void);
+extern void pfm_init_percpu(void);
+
+/* 
+ * hooks to allow VTune/Prospect to cooperate with perfmon.
+ * (reserved for system wide monitoring modules only)
+ */
+extern int pfm_install_alternate_syswide_subsystem(pfm_intr_handler_desc_t *h);
+extern int pfm_remove_alternate_syswide_subsystem(pfm_intr_handler_desc_t *h);
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/pgalloc.h linux-2.4.21/include/asm-ia64/pgalloc.h
--- linux-2.4.20/include/asm-ia64/pgalloc.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/pgalloc.h	2002-12-18 18:58:02.000000000 +0000
@@ -157,29 +157,44 @@
  * Flush everything (kernel mapping may also have changed due to
  * vmalloc/vfree).
  */
-extern void __flush_tlb_all (void);
+extern void local_flush_tlb_all (void);
 
 #ifdef CONFIG_SMP
   extern void smp_flush_tlb_all (void);
+  extern void smp_flush_tlb_mm (struct mm_struct *mm);
 # define flush_tlb_all()	smp_flush_tlb_all()
 #else
-# define flush_tlb_all()	__flush_tlb_all()
+# define flush_tlb_all()	local_flush_tlb_all()
 #endif
 
+static inline void
+local_flush_tlb_mm (struct mm_struct *mm)
+{
+	if (mm == current->active_mm)
+		activate_context(mm);
+}
+
 /*
- * Flush a specified user mapping
+ * Flush a specified user mapping.  This is called, e.g., as a result of fork() and
+ * exit().  fork() ends up here because the copy-on-write mechanism needs to write-protect
+ * the PTEs of the parent task.
  */
 static inline void
 flush_tlb_mm (struct mm_struct *mm)
 {
-	if (mm) {
-		mm->context = 0;
-		if (mm == current->active_mm) {
-			/* This is called, e.g., as a result of exec().  */
-			get_new_mmu_context(mm);
-			reload_context(mm);
-		}
-	}
+	if (!mm)
+		return;
+
+	mm->context = 0;
+
+	if (atomic_read(&mm->mm_users) == 0)
+		return;		/* happens as a result of exit_mmap() */
+
+#ifdef CONFIG_SMP
+	smp_flush_tlb_mm(mm);
+#else
+	local_flush_tlb_mm(mm);
+#endif
 }
 
 extern void flush_tlb_range (struct mm_struct *mm, unsigned long start, unsigned long end);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/pgtable.h linux-2.4.21/include/asm-ia64/pgtable.h
--- linux-2.4.20/include/asm-ia64/pgtable.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/pgtable.h	2002-12-18 18:58:06.000000000 +0000
@@ -198,13 +198,9 @@
 
 #define VMALLOC_START		(0xa000000000000000 + 3*PAGE_SIZE)
 #define VMALLOC_VMADDR(x)	((unsigned long)(x))
-#ifdef CONFIG_VIRTUAL_MEM_MAP
-# define VMALLOC_END_INIT        (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) 
-# define VMALLOC_END             vmalloc_end
-  extern unsigned long vmalloc_end;
-#else
-# define VMALLOC_END		(0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9)))
-#endif
+#define VMALLOC_END_INIT        (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) 
+#define VMALLOC_END             vmalloc_end
+extern unsigned long vmalloc_end;
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
@@ -284,11 +280,7 @@
  * works bypasses the caches, but does allow for consecutive writes to
  * be combined into single (but larger) write transactions.
  */
-#ifdef CONFIG_MCKINLEY_A0_SPECIFIC
-# define pgprot_writecombine(prot)	prot
-#else
-# define pgprot_writecombine(prot)	__pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WC)
-#endif
+#define pgprot_writecombine(prot)	__pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WC)
 
 /*
  * Return the region index for virtual address ADDRESS.
@@ -448,8 +440,6 @@
  */
 #define pgtable_cache_init()	do { } while (0)
 
-#ifdef CONFIG_VIRTUAL_MEM_MAP
-
 /* arch mem_map init routines are needed due to holes in a virtual mem_map */
 #define HAVE_ARCH_MEMMAP_INIT
 
@@ -460,8 +450,6 @@
 	struct page *start, struct page *end, int zone,
 	unsigned long start_paddr, int highmem);
 
-#endif /* CONFIG_VIRTUAL_MEM_MAP */
-
 # endif /* !__ASSEMBLY__ */
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/processor.h linux-2.4.21/include/asm-ia64/processor.h
--- linux-2.4.20/include/asm-ia64/processor.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/processor.h	2002-12-18 18:58:06.000000000 +0000
@@ -167,16 +167,16 @@
 	__u32 ptce_count[2];
 	__u32 ptce_stride[2];
 	struct task_struct *ksoftirqd;	/* kernel softirq daemon for this CPU */
+# ifdef CONFIG_PERFMON
+	__u32 pfm_syst_wide;
+	__u32 pfm_dcr_pp;
+# endif
 #ifdef CONFIG_SMP
 	int processor;
 	__u64 loops_per_jiffy;
 	__u64 ipi_count;
 	__u64 prof_counter;
 	__u64 prof_multiplier;
-# ifdef CONFIG_PERFMON
-	__u32 pfm_syst_wide;
-	__u32 pfm_dcr_pp;
-# endif
 	union {
 		/*
 		 *  This is written to by *other* CPUs,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sal.h linux-2.4.21/include/asm-ia64/sal.h
--- linux-2.4.20/include/asm-ia64/sal.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/sal.h	2002-12-18 18:58:07.000000000 +0000
@@ -38,9 +38,12 @@
 
 # define SAL_CALL(result,args...) do {			\
 	unsigned long flags;				\
+	struct ia64_fpreg fr[6];                        \
+	ia64_save_scratch_fpregs(fr);                   \
 	spin_lock_irqsave(&sal_lock, flags);		\
 	__SAL_CALL(result,args);			\
 	spin_unlock_irqrestore(&sal_lock, flags);	\
+	ia64_load_scratch_fpregs(fr);                   \
 } while (0)
 
 #define SAL_SET_VECTORS			0x01000000
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/scatterlist.h linux-2.4.21/include/asm-ia64/scatterlist.h
--- linux-2.4.20/include/asm-ia64/scatterlist.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/scatterlist.h	2002-12-18 18:58:01.000000000 +0000
@@ -9,12 +9,13 @@
 struct scatterlist {
 	/* This will disappear in 2.5.x: */
 	char *address;		/* location data is to be transferred to, NULL for highmem page */
-	char *orig_address;	/* for use by swiotlb */
 
 	/* These two are only valid if ADDRESS member of this struct is NULL.  */
 	struct page *page;
 	unsigned int offset;
 	unsigned int length;	/* buffer length */
+	dma_addr_t dma_address;
+	unsigned int dma_length;
 };
 
 #define ISA_DMA_THRESHOLD	(~0UL)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/siginfo.h linux-2.4.21/include/asm-ia64/siginfo.h
--- linux-2.4.20/include/asm-ia64/siginfo.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/siginfo.h	2002-12-18 18:58:06.000000000 +0000
@@ -266,8 +266,8 @@
 	if (from->si_code < 0)
 		memcpy(to, from, sizeof(siginfo_t));
 	else
-		/* _sigchld is currently the largest know union member */
-		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
+		/* _sigprof is currently the largest know union member */
+		memcpy(to, from, 4*sizeof(int) + sizeof(from->_sifields._sigprof));
 }
 
 extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/alenlist.h linux-2.4.21/include/asm-ia64/sn/alenlist.h
--- linux-2.4.20/include/asm-ia64/sn/alenlist.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/sn/alenlist.h	2002-12-18 18:58:01.000000000 +0000
@@ -15,7 +15,7 @@
 
 /*
  * An Address/Length List is used when setting up for an I/O DMA operation.
- * A driver creates an Address/Length List that describes to the the DMA 
+ * A driver creates an Address/Length List that describes to the DMA 
  * interface where in memory the DMA should go.  The bus interface sets up 
  * mapping registers, if required, and returns a suitable list of "physical 
  * addresses" or "I/O address" to the driver.  The driver then uses these 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/system.h linux-2.4.21/include/asm-ia64/system.h
--- linux-2.4.20/include/asm-ia64/system.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/system.h	2002-12-18 18:58:07.000000000 +0000
@@ -171,6 +171,15 @@
 						      : "p6", "p7", "memory")
 #endif /* !CONFIG_IA64_DEBUG_IRQ */
 
+#error andre hedrick screwed this up please help unscrew in order to clean up
+/*
+ * __save_and_sti(x) == __save_flags(x); ide__sti();
+ *                      __save_flags(x); __sti();
+ *
+ * local_irq_set(x) == __save_and_sti(x)
+ */
+
+
 #define local_irq_enable()	__asm__ __volatile__ (";; ssm psr.i;; srlz.d" ::: "memory")
 
 #define __cli()			local_irq_disable ()
@@ -384,7 +393,7 @@
 extern void ia64_save_extra (struct task_struct *task);
 extern void ia64_load_extra (struct task_struct *task);
 
-#if defined(CONFIG_SMP) && defined(CONFIG_PERFMON)
+#ifdef CONFIG_PERFMON
 # define PERFMON_IS_SYSWIDE() (local_cpu_data->pfm_syst_wide != 0)
 #else
 # define PERFMON_IS_SYSWIDE() (0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/unistd.h linux-2.4.21/include/asm-ia64/unistd.h
--- linux-2.4.20/include/asm-ia64/unistd.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-ia64/unistd.h	2002-12-18 18:58:03.000000000 +0000
@@ -206,12 +206,23 @@
 #define __NR_getdents64			1214
 #define __NR_getunwind			1215
 #define __NR_readahead			1216
-/*
- * 1217-1228: reserved for xattr
- * 1230-1232: reserved for futex and sched_[sg]etaffinity.
- */
+#define __NR_setxattr			1217
+#define __NR_lsetxattr			1218
+#define __NR_fsetxattr			1219
+#define __NR_getxattr			1220
+#define __NR_lgetxattr			1221
+#define __NR_fgetxattr			1222
+#define __NR_listxattr			1223
+#define __NR_llistxattr			1224
+#define __NR_flistxattr			1225
+#define __NR_removexattr		1226
+#define __NR_lremovexattr		1227
+#define __NR_fremovexattr		1228
 #define __NR_tkill			1229
-#define __NR_security			1233 /* syscall for security modules */
+/* 1230-1232: reserved for futex and sched_[sg]etaffinity */
+#define __NR_security			1233
+/* 1234-1235: reserved for {alloc,free}_hugepages */
+/* 1238-1242: reserved for io_{setup,destroy,getevents,submit,cancel} */
 
 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/hdreg.h linux-2.4.21/include/asm-m68k/hdreg.h
--- linux-2.4.20/include/asm-m68k/hdreg.h	1999-05-13 18:00:09.000000000 +0000
+++ linux-2.4.21/include/asm-m68k/hdreg.h	2002-12-18 18:58:05.000000000 +0000
@@ -9,5 +9,6 @@
 
 typedef unsigned int   q40ide_ioreg_t;
 typedef unsigned char * ide_ioreg_t;
+//typedef unsigned long ide_ioreg_t;
 
 #endif /* _M68K_HDREG_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/ide.h linux-2.4.21/include/asm-m68k/ide.h
--- linux-2.4.20/include/asm-m68k/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-m68k/ide.h	2002-12-18 18:58:01.000000000 +0000
@@ -50,6 +50,9 @@
 #define MAX_HWIFS	4	/* same as the other archs */
 #endif
 
+/*
+ * FIXME: IOPS struct calls needed for taskfile.
+ */
 
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
@@ -80,29 +83,6 @@
 {
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit7		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned head		: 4;	/* always zeros here */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-		unsigned reserved456	: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned bit0		: 1;
-	} b;
-} control_t;
-
 static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
 			unsigned long flags, const char *device, void *dev_id)
 {
@@ -190,22 +170,26 @@
 
 #define ADDR_TRANS_B(_addr_) (_addr_)
 #define ADDR_TRANS_W(_addr_) (_addr_)
+#define ADDR_TRANS_L(_addr_) (_addr_)
 
 #else
 
 #define ADDR_TRANS_B(_addr_) (MACH_IS_Q40 ? ((unsigned char *)Q40_ISA_IO_B(_addr_)) : (_addr_))
 #define ADDR_TRANS_W(_addr_) (MACH_IS_Q40 ? ((unsigned char *)Q40_ISA_IO_W(_addr_)) : (_addr_))
+#define ADDR_TRANS_L(_addr_) (MACH_IS_Q40 ? ((unsigned char *)Q40_ISA_IO_L(_addr_)) : (_addr_))
 #endif
 
-#define HAVE_ARCH_OUT_BYTE
+#define HAVE_ARCH_OUT_BYTE 1
 
 #define OUT_BYTE(v,p)	out_8(ADDR_TRANS_B((p)), (v))
 #define OUT_WORD(v,p)	out_be16(ADDR_TRANS_W((p)), (v))
+#define OUT_LONG(v,p)	out_be32(ADDR_TRANS_L((p)), (v))
 
-#define HAVE_ARCH_IN_BYTE
+#define HAVE_ARCH_IN_BYTE 1
 
 #define IN_BYTE(p)	in_8(ADDR_TRANS_B((p)))
 #define IN_WORD(p)	in_be16(ADDR_TRANS_W((p)))
+#define IN_LONG(p)	in_be32(ADDR_TRANS_L((p)))
 
 #define insw(port, buf, nr) raw_insw(ADDR_TRANS_W(port), buf, nr)
 #define outsw(port, buf, nr) raw_outsw(ADDR_TRANS_W(port), buf, nr)
@@ -227,19 +211,6 @@
 #endif /* CONFIG_ATARI || CONFIG_Q40 */
 
 
-#define T_CHAR          (0x0000)        /* char:  don't touch  */
-#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
-#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
-#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
-
-#define T_MASK_TYPE     (0xc000)
-#define T_MASK_COUNT    (0x3fff)
-
-#define D_CHAR(cnt)     (T_CHAR  | (cnt))
-#define D_SHORT(cnt)    (T_SHORT | (cnt))
-#define D_INT(cnt)      (T_INT   | (cnt))
-#define D_TEXT(cnt)     (T_TEXT  | (cnt))
-
 /* Q40 and Atari have byteswapped IDE bus and since many interesting
  * values in the identification string are text, chars and words they
  * happened to be almost correct without swapping.. However *_capacity 
@@ -248,83 +219,11 @@
 #define M68K_IDE_SWAPW  (MACH_IS_Q40 || MACH_IS_ATARI)
 #endif
 
-#if defined(CONFIG_AMIGA) || defined (CONFIG_MAC) || defined(M68K_IDE_SWAPW)
-static u_short driveid_types[] = {
-	D_SHORT(10),	/* config - vendor2 */
-	D_TEXT(20),	/* serial_no */
-	D_SHORT(3),	/* buf_type, buf_size - ecc_bytes */
-	D_TEXT(48),	/* fw_rev - model */
-	D_CHAR(2),	/* max_multsect - vendor3 */
-	D_SHORT(1),	/* dword_io */
-	D_CHAR(2),	/* vendor4 - capability */
-	D_SHORT(1),	/* reserved50 */
-	D_CHAR(4),	/* vendor5 - tDMA */
-	D_SHORT(4),	/* field_valid - cur_sectors */
-	D_INT(1),	/* cur_capacity */
-	D_CHAR(2),	/* multsect - multsect_valid */
-	D_INT(1),	/* lba_capacity */
-	D_SHORT(194)	/* dma_1word - reserved */
-};
-
-#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
-#endif /* CONFIG_AMIGA */
-
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-#if defined(CONFIG_AMIGA) || defined (CONFIG_MAC) || defined(M68K_IDE_SWAPW)
-   u_char *p = (u_char *)id;
-   int i, j, cnt;
-   u_char t;
-
-   if (!MACH_IS_AMIGA && !MACH_IS_MAC && !MACH_IS_Q40 && !MACH_IS_ATARI)
-   	return;
-#ifdef M68K_IDE_SWAPW
-   if (M68K_IDE_SWAPW)    /* fix bus byteorder first */
-      for (i=0; i < 512; i+=2) {
-	 t = p[i]; p[i] = p[i+1]; p[i+1] = t; 
-      }
-#endif
-   for (i = 0; i < num_driveid_types; i++) {
-      cnt = driveid_types[i] & T_MASK_COUNT;
-      switch (driveid_types[i] & T_MASK_TYPE) {
-         case T_CHAR:
-            p += cnt;
-            break;
-         case T_SHORT:
-            for (j = 0; j < cnt; j++) {
-	       t = p[0];
-	       p[0] = p[1];
-	       p[1] = t;
-               p += 2;
-            }
-            break;
-         case T_INT:
-            for (j = 0; j < cnt; j++) {
-	       t = p[0];
-	       p[0] = p[3];
-	       p[3] = t;
-	       t = p[1];
-	       p[1] = p[2];
-	       p[2] = t;
-               p += 4;
-            }
-            break;
-         case T_TEXT:
-            for (j = 0; j < cnt; j += 2) {
-	       t = p[0];
-	       p[0] = p[1];
-	       p[1] = t;
-               p += 2;
-            }
-            break;
-      }
-   }
-#endif /* CONFIG_AMIGA */
-}
+#ifdef CONFIG_ATARI
+#define IDE_ARCH_LOCK 1
 
 static __inline__ void ide_release_lock (int *ide_lock)
 {
-#ifdef CONFIG_ATARI
 	if (MACH_IS_ATARI) {
 		if (*ide_lock == 0) {
 			printk("ide_release_lock: bug\n");
@@ -333,12 +232,10 @@
 		*ide_lock = 0;
 		stdma_release();
 	}
-#endif /* CONFIG_ATARI */
 }
 
 static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *, struct pt_regs *), void *data)
 {
-#ifdef CONFIG_ATARI
 	if (MACH_IS_ATARI) {
 		if (*ide_lock == 0) {
 			if (in_interrupt() > 0)
@@ -347,39 +244,8 @@
 			*ide_lock = 1;
 		}
 	}
-#endif /* CONFIG_ATARI */
 }
-
-#define ide_ack_intr(hwif)	((hwif)->hw.ack_intr ? (hwif)->hw.ack_intr(hwif) : 1)
-
-/*
- * On the Atari, we sometimes can't enable interrupts:
- */
-
-/* MSch: changed sti() to STI() wherever possible in ide.c; moved STI() def. 
- * to asm/ide.h 
- */
-/* The Atari interrupt structure strictly requires that the IPL isn't lowered
- * uncontrolled in an interrupt handler. In the concrete case, the IDE
- * interrupt is already a slow int, so the irq is already disabled at the time
- * the handler is called, and the IPL has been lowered to the minimum value
- * possible. To avoid going below that, STI() checks for being called inside
- * an interrupt, and in that case it does nothing. Hope that is reasonable and
- * works. (Roman)
- */
-#ifdef MACH_ATARI_ONLY
-#define	ide__sti()					\
-    do {						\
-	if (!in_interrupt()) __sti();			\
-    } while(0)
-#elif defined(CONFIG_ATARI)
-#define	ide__sti()						\
-    do {							\
-	if (!MACH_IS_ATARI || !in_interrupt()) sti();		\
-    } while(0)
-#else /* !defined(CONFIG_ATARI) */
-#define	ide__sti()	__sti()
-#endif
+#endif /* CONFIG_ATARI */
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/system.h linux-2.4.21/include/asm-m68k/system.h
--- linux-2.4.20/include/asm-m68k/system.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-m68k/system.h	2002-12-18 18:58:04.000000000 +0000
@@ -47,7 +47,6 @@
   (last) = _last; \
 }
 
-
 /* interrupt control.. */
 #if 0
 #define __sti() asm volatile ("andiw %0,%%sr": : "i" (ALLOWINT) : "memory")
@@ -64,6 +63,7 @@
 
 /* For spinlocks etc */
 #define local_irq_save(x)	({ __save_flags(x); __cli(); })
+#define local_irq_set(x)	({ __save_flags(x); __sti(); })
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
@@ -72,7 +72,8 @@
 #define sti()			__sti()
 #define save_flags(x)		__save_flags(x)
 #define restore_flags(x)	__restore_flags(x)
-#define save_and_cli(flags)   do { save_flags(flags); cli(); } while(0)
+#define save_and_cli(x)		do { save_flags(x); cli(); } while(0)
+#define save_and_set(x)		do { save_flags(x); sti(); } while(0)
 
 /*
  * Force strict CPU ordering.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-mips/ide.h linux-2.4.21/include/asm-mips/ide.h
--- linux-2.4.20/include/asm-mips/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-mips/ide.h	2002-12-18 18:58:04.000000000 +0000
@@ -24,21 +24,11 @@
 # endif
 #endif
 
-#define ide__sti()	__sti()
-
 struct ide_ops {
 	int (*ide_default_irq)(ide_ioreg_t base);
 	ide_ioreg_t (*ide_default_io_base)(int index);
 	void (*ide_init_hwif_ports)(hw_regs_t *hw, ide_ioreg_t data_port,
 	                            ide_ioreg_t ctrl_port, int *irq);
-	int (*ide_request_irq)(unsigned int irq, void (*handler)(int, void *,
-	                       struct pt_regs *), unsigned long flags,
-	                       const char *device, void *dev_id);
-	void (*ide_free_irq)(unsigned int irq, void *dev_id);
-	int (*ide_check_region) (ide_ioreg_t from, unsigned int extent);
-	void (*ide_request_region)(ide_ioreg_t from, unsigned int extent,
-	                        const char *name);
-	void (*ide_release_region)(ide_ioreg_t from, unsigned int extent);
 };
 
 extern struct ide_ops *ide_ops;
@@ -73,74 +63,6 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-#ifdef __MIPSEB__
-		unsigned bit7		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned head		: 4;	/* always zeros here */
-#else
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-#endif
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-#ifdef __MIPSEB__
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-		unsigned reserved456	: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned bit0		: 1;
-#else
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-#endif
-	} b;
-} control_t;
-
-static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int,void *, struct pt_regs *),
-			unsigned long flags, const char *device, void *dev_id)
-{
-	return ide_ops->ide_request_irq(irq, handler, flags, device, dev_id);
-}
-
-static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
-{
-	ide_ops->ide_free_irq(irq, dev_id);
-}
-
-static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
-{
-	return ide_ops->ide_check_region(from, extent);
-}
-
-static __inline__ void ide_request_region(ide_ioreg_t from,
-                                          unsigned int extent, const char *name)
-{
-	ide_ops->ide_request_region(from, extent, name);
-}
-
-static __inline__ void ide_release_region(ide_ioreg_t from,
-                                          unsigned int extent)
-{
-	ide_ops->ide_release_region(from, extent);
-}
-
 #undef  SUPPORT_VLB_SYNC
 #define SUPPORT_VLB_SYNC 0
 
@@ -197,94 +119,8 @@
 	}
 }
 
-#define T_CHAR          (0x0000)        /* char:  don't touch  */
-#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
-#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
-#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
-
-#define T_MASK_TYPE     (0xc000)
-#define T_MASK_COUNT    (0x3fff)
-
-#define D_CHAR(cnt)     (T_CHAR  | (cnt))
-#define D_SHORT(cnt)    (T_SHORT | (cnt))
-#define D_INT(cnt)      (T_INT   | (cnt))
-#define D_TEXT(cnt)     (T_TEXT  | (cnt))
-
-static u_short driveid_types[] = {
-	D_SHORT(10),	/* config - vendor2 */
-	D_TEXT(20),	/* serial_no */
-	D_SHORT(3),	/* buf_type - ecc_bytes */
-	D_TEXT(48),	/* fw_rev - model */
-	D_CHAR(2),	/* max_multsect - vendor3 */
-	D_SHORT(1),	/* dword_io */
-	D_CHAR(2),	/* vendor4 - capability */
-	D_SHORT(1),	/* reserved50 */
-	D_CHAR(4),	/* vendor5 - tDMA */
-	D_SHORT(4),	/* field_valid - cur_sectors */
-	D_INT(1),	/* cur_capacity */
-	D_CHAR(2),	/* multsect - multsect_valid */
-	D_INT(1),	/* lba_capacity */
-	D_SHORT(194)	/* dma_1word - reservedyy */
-};
-
-#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
-
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-	u_char *p = (u_char *)id;
-	int i, j, cnt;
-	u_char t;
-
-	for (i = 0; i < num_driveid_types; i++) {
-		cnt = driveid_types[i] & T_MASK_COUNT;
-		switch (driveid_types[i] & T_MASK_TYPE) {
-		case T_CHAR:
-			p += cnt;
-			break;
-		case T_SHORT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		case T_INT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[3];
-				p[3] = t;
-				t = p[1];
-				p[1] = p[2];
-				p[2] = t;
-				p += 4;
-			}
-			break;
-		case T_TEXT:
-			for (j = 0; j < cnt; j += 2) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		};
-	}
-}
-
-#else /* defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)  */
-
-#define ide_fix_driveid(id)		do {} while (0)
-
 #endif
 
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
 #endif /* __KERNEL__ */
 
 #endif /* __ASM_IDE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-mips/system.h linux-2.4.21/include/asm-mips/system.h
--- linux-2.4.20/include/asm-mips/system.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-mips/system.h	2002-12-18 18:58:07.000000000 +0000
@@ -114,6 +114,8 @@
 	: /* no inputs */						\
 	: "memory")
 
+#define __save_and_sti(x)	do { __save_flags(x); __sti(); } while(0);
+
 __asm__(".macro\t__restore_flags flags\n\t"
 	".set\tnoreorder\n\t"
 	".set\tnoat\n\t"
@@ -152,6 +154,7 @@
 #  define save_flags(x) do { x = __global_save_flags(); } while (0)
 #  define restore_flags(x) __global_restore_flags(x)
 #  define save_and_cli(x) do { save_flags(x); cli(); } while(0)
+#  define save_and_sti(x) do { save_flags(x); sti(); } while(0)
 
 #else /* Single processor */
 
@@ -160,11 +163,13 @@
 #  define save_flags(x) __save_flags(x)
 #  define save_and_cli(x) __save_and_cli(x)
 #  define restore_flags(x) __restore_flags(x)
+#  define save_and_sti(x) __save_and_sti(x)
 
 #endif /* SMP */
 
 /* For spinlocks etc */
 #define local_irq_save(x)	__save_and_cli(x)
+#define local_irq_set(x)	__save_and_sti(x)
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-mips64/ide.h linux-2.4.21/include/asm-mips64/ide.h
--- linux-2.4.20/include/asm-mips64/ide.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-mips64/ide.h	2002-12-18 18:58:01.000000000 +0000
@@ -28,21 +28,11 @@
 # endif
 #endif
 
-#define ide__sti()	__sti()
-
 struct ide_ops {
 	int (*ide_default_irq)(ide_ioreg_t base);
 	ide_ioreg_t (*ide_default_io_base)(int index);
 	void (*ide_init_hwif_ports)(hw_regs_t *hw, ide_ioreg_t data_port,
 	                            ide_ioreg_t ctrl_port, int *irq);
-	int (*ide_request_irq)(unsigned int irq, void (*handler)(int, void *,
-	                       struct pt_regs *), unsigned long flags,
-	                       const char *device, void *dev_id);
-	void (*ide_free_irq)(unsigned int irq, void *dev_id);
-	int (*ide_check_region) (ide_ioreg_t from, unsigned int extent);
-	void (*ide_request_region)(ide_ioreg_t from, unsigned int extent,
-	                        const char *name);
-	void (*ide_release_region)(ide_ioreg_t from, unsigned int extent);
 };
 
 extern struct ide_ops *ide_ops;
@@ -77,215 +67,50 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-#ifdef __MIPSEB__
-		unsigned bit7           : 1;    /* always 1 */
-		unsigned lba            : 1;    /* using LBA instead of CHS */
-		unsigned bit5           : 1;    /* always 1 */
-		unsigned unit           : 1;    /* drive select number, 0 or 1 */
-		unsigned head           : 4;    /* always zeros here */
-#else
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-#endif
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-#ifdef __MIPSEB__
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-		unsigned reserved456	: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned bit0		: 1;
-#else
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-#endif
-	} b;
-} control_t;
-
-static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int,void *, struct pt_regs *),
-			unsigned long flags, const char *device, void *dev_id)
-{
-	return ide_ops->ide_request_irq(irq, handler, flags, device, dev_id);
-}
-
-static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
-{
-	ide_ops->ide_free_irq(irq, dev_id);
-}
-
-static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
-{
-	return ide_ops->ide_check_region(from, extent);
-}
-
-static __inline__ void ide_request_region(ide_ioreg_t from,
-                                          unsigned int extent, const char *name)
-{
-	ide_ops->ide_request_region(from, extent, name);
-}
-
-static __inline__ void ide_release_region(ide_ioreg_t from,
-                                          unsigned int extent)
-{
-	ide_ops->ide_release_region(from, extent);
-}
-
-
 #if defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)
 
-/* get rid of defs from io.h - ide has its private and conflicting versions */
-#ifdef insw
-#undef insw
-#endif
-#ifdef outsw
-#undef outsw
-#endif
 #ifdef insl
 #undef insl
 #endif
 #ifdef outsl
 #undef outsl
 #endif
-
-#define insw(port, addr, count) ide_insw(port, addr, count)
-#define insl(port, addr, count) ide_insl(port, addr, count)
-#define outsw(port, addr, count) ide_outsw(port, addr, count)
-#define outsl(port, addr, count) ide_outsl(port, addr, count)
-
-static inline void ide_insw(unsigned long port, void *addr, unsigned int count)
-{
-       while (count--) {
-               *(u16 *)addr = *(volatile u16 *)(mips_io_port_base + port);
-               addr += 2;
-       }
-}
-
-static inline void ide_outsw(unsigned long port, void *addr, unsigned int count)
-{
-       while (count--) {
-               *(volatile u16 *)(mips_io_port_base + (port)) = *(u16 *)addr;
-               addr += 2;
-       }
-}
-
-static inline void ide_insl(unsigned long port, void *addr, unsigned int count)
-{
-       while (count--) {
-               *(u32 *)addr = *(volatile u32 *)(mips_io_port_base + port);
-               addr += 4;
-       }
-}
-
-static inline void ide_outsl(unsigned long port, void *addr, unsigned int count)
-{
-       while (count--) {
-               *(volatile u32 *)(mips_io_port_base + (port)) = *(u32 *)addr;
-               addr += 4;
-       }
-}
-
-#define T_CHAR          (0x0000)        /* char:  don't touch  */
-#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
-#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
-#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
-
-#define T_MASK_TYPE     (0xc000)
-#define T_MASK_COUNT    (0x3fff)
-
-#define D_CHAR(cnt)     (T_CHAR  | (cnt))
-#define D_SHORT(cnt)    (T_SHORT | (cnt))
-#define D_INT(cnt)      (T_INT   | (cnt))
-#define D_TEXT(cnt)     (T_TEXT  | (cnt))
-
-static u_short driveid_types[] = {
-	D_SHORT(10),	/* config - vendor2 */
-	D_TEXT(20),	/* serial_no */
-	D_SHORT(3),	/* buf_type - ecc_bytes */
-	D_TEXT(48),	/* fw_rev - model */
-	D_CHAR(2),	/* max_multsect - vendor3 */
-	D_SHORT(1),	/* dword_io */
-	D_CHAR(2),	/* vendor4 - capability */
-	D_SHORT(1),	/* reserved50 */
-	D_CHAR(4),	/* vendor5 - tDMA */
-	D_SHORT(4),	/* field_valid - cur_sectors */
-	D_INT(1),	/* cur_capacity */
-	D_CHAR(2),	/* multsect - multsect_valid */
-	D_INT(1),	/* lba_capacity */
-	D_SHORT(194)	/* dma_1word - reservedyy */
-};
-
-#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
-
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-	u_char *p = (u_char *)id;
-	int i, j, cnt;
-	u_char t;
-
-	for (i = 0; i < num_driveid_types; i++) {
-		cnt = driveid_types[i] & T_MASK_COUNT;
-		switch (driveid_types[i] & T_MASK_TYPE) {
-		case T_CHAR:
-			p += cnt;
-			break;
-		case T_SHORT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		case T_INT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[3];
-				p[3] = t;
-				t = p[1];
-				p[1] = p[2];
-				p[2] = t;
-				p += 4;
-			}
-			break;
-		case T_TEXT:
-			for (j = 0; j < cnt; j += 2) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		};
-	}
-}
-
-#else /* defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)  */
-
-#define ide_fix_driveid(id)		do {} while (0)
-
+#ifdef insw
+#undef insw
 #endif
+#ifdef outsw
+#undef outsw
+#endif
+
+#define insw(p,a,c)							\
+do {									\
+	unsigned short *ptr = (unsigned short *)(a);			\
+	unsigned int i = (c);						\
+	while (i--)							\
+		*ptr++ = inw(p);					\
+} while (0)
+#define insl(p,a,c)							\
+do {									\
+	unsigned long *ptr = (unsigned long *)(a);			\
+	unsigned int i = (c);						\
+	while (i--)							\
+		*ptr++ = inl(p);					\
+} while (0)
+#define outsw(p,a,c)							\
+do {									\
+	unsigned short *ptr = (unsigned short *)(a);			\
+	unsigned int i = (c);						\
+	while (i--)							\
+		outw(*ptr++, (p));					\
+} while (0)
+#define outsl(p,a,c) {							\
+	unsigned long *ptr = (unsigned long *)(a);			\
+	unsigned int i = (c);						\
+	while (i--)							\
+		outl(*ptr++, (p));					\
+} while (0)
 
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+#endif /* defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)  */
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-mips64/system.h linux-2.4.21/include/asm-mips64/system.h
--- linux-2.4.20/include/asm-mips64/system.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-mips64/system.h	2002-12-18 18:58:07.000000000 +0000
@@ -109,6 +109,8 @@
 	: /* no inputs */						\
 	: "memory")
 
+#define __save_and_sti(x)       do { __save_flags(x); __sti(); } while(0);
+
 __asm__(".macro\t__restore_flags flags\n\t"
 	".set\tnoreorder\n\t"
 	".set\tnoat\n\t"
@@ -147,6 +149,7 @@
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
 #define save_and_cli(x) do { save_flags(x); cli(); } while(0)
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0)
 
 #else
 
@@ -155,11 +158,13 @@
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
 #define save_and_cli(x) __save_and_cli(x)
+#define save_and_sti(x) __save_and_sti(x)
 
 #endif /* CONFIG_SMP */
 
 /* For spinlocks etc */
 #define local_irq_save(x)	__save_and_cli(x)
+#define local_irq_set(x)	__save_and_sti(x)
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-parisc/hdreg.h linux-2.4.21/include/asm-parisc/hdreg.h
--- linux-2.4.20/include/asm-parisc/hdreg.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.21/include/asm-parisc/hdreg.h	2002-12-18 18:58:03.000000000 +0000
@@ -1,6 +1,7 @@
 #ifndef _ASM_HDREG_H
 #define _ASM_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+//typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-parisc/ide.h linux-2.4.21/include/asm-parisc/ide.h
--- linux-2.4.20/include/asm-parisc/ide.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-parisc/ide.h	2002-12-18 18:58:06.000000000 +0000
@@ -20,6 +20,8 @@
 #define MAX_HWIFS	2
 #endif
 
+#define ide__sti()      __sti()
+
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	switch (base) {
@@ -78,93 +80,28 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#define ide_check_region(from,extent)		check_region((from), (extent))
-#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
-#define ide_release_region(from,extent)		release_region((from), (extent))
-
-#define T_CHAR          (0x0000)        /* char:  don't touch  */
-#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
-#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
-#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
-
-#define T_MASK_TYPE     (0xc000)
-#define T_MASK_COUNT    (0x3fff)
-
-#define D_CHAR(cnt)     (T_CHAR  | (cnt))
-#define D_SHORT(cnt)    (T_SHORT | (cnt))
-#define D_INT(cnt)      (T_INT   | (cnt))
-#define D_TEXT(cnt)     (T_TEXT  | (cnt))
-
-static u_short driveid_types[] = {
-	D_SHORT(10),	/* config - vendor2 */
-	D_TEXT(20),	/* serial_no */
-	D_SHORT(3),	/* buf_type - ecc_bytes */
-	D_TEXT(48),	/* fw_rev - model */
-	D_CHAR(2),	/* max_multsect - vendor3 */
-	D_SHORT(1),	/* dword_io */
-	D_CHAR(2),	/* vendor4 - capability */
-	D_SHORT(1),	/* reserved50 */
-	D_CHAR(4),	/* vendor5 - tDMA */
-	D_SHORT(4),	/* field_valid - cur_sectors */
-	D_INT(1),	/* cur_capacity */
-	D_CHAR(2),	/* multsect - multsect_valid */
-	D_INT(1),	/* lba_capacity */
-	D_SHORT(194)	/* dma_1word - reservedyy */
-};
-
-#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
-
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-	u_char *p = (u_char *)id;
-	int i, j, cnt;
-	u_char t;
-
-	for (i = 0; i < num_driveid_types; i++) {
-		cnt = driveid_types[i] & T_MASK_COUNT;
-		switch (driveid_types[i] & T_MASK_TYPE) {
-		case T_CHAR:
-			p += cnt;
-			break;
-		case T_SHORT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		case T_INT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[3];
-				p[3] = t;
-				t = p[1];
-				p[1] = p[2];
-				p[2] = t;
-				p += 4;
-			}
-			break;
-		case T_TEXT:
-			for (j = 0; j < cnt; j += 2) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		};
-	}
-}
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit7		: 1;	/* always 1 */
+		unsigned lba		: 1;	/* using LBA instead of CHS */
+		unsigned bit5		: 1;	/* always 1 */
+		unsigned unit		: 1;	/* drive select number, 0 or 1 */
+		unsigned head		: 4;	/* always zeros here */
+	} b;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-parisc/system_irqsave.h linux-2.4.21/include/asm-parisc/system_irqsave.h
--- linux-2.4.20/include/asm-parisc/system_irqsave.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/include/asm-parisc/system_irqsave.h	2002-12-18 18:58:07.000000000 +0000
@@ -0,0 +1,17 @@
+#ifndef __PARISC_SYSTEM_IRQSAVE_H
+#define __PARISC_SYSTEM_IRQSAVE_H
+
+/* interrupt control */
+#define __save_flags(x)	__asm__ __volatile__("ssm 0, %0" : "=r" (x) : : "memory")
+#define __restore_flags(x) __asm__ __volatile__("mtsm %0" : : "r" (x) : "memory")
+#define __cli()	__asm__ __volatile__("rsm %0,%%r0\n" : : "i" (PSW_I) : "memory" )
+#define __sti()	__asm__ __volatile__("ssm %0,%%r0\n" : : "i" (PSW_I) : "memory" )
+
+#define local_irq_save(x) \
+	__asm__ __volatile__("rsm %1,%0" : "=r" (x) :"i" (PSW_I) : "memory" )
+#define local_irq_restore(x) \
+	__asm__ __volatile__("mtsm %0" : : "r" (x) : "memory" )
+#define local_irq_disable() __cli()
+#define local_irq_enable()  __sti()
+
+#endif /* __PARISC_SYSTEM_IRQSAVE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/hdreg.h linux-2.4.21/include/asm-ppc/hdreg.h
--- linux-2.4.20/include/asm-ppc/hdreg.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21/include/asm-ppc/hdreg.h	2002-12-18 18:58:03.000000000 +0000
@@ -14,7 +14,8 @@
 #ifndef __ASMPPC_HDREG_H
 #define __ASMPPC_HDREG_H
 
-typedef unsigned int ide_ioreg_t;
+//typedef unsigned int ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASMPPC_HDREG_H */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/hw_irq.h linux-2.4.21/include/asm-ppc/hw_irq.h
--- linux-2.4.20/include/asm-ppc/hw_irq.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-ppc/hw_irq.h	2002-12-18 18:58:10.000000000 +0000
@@ -21,6 +21,7 @@
 
 #define __save_flags(flags) __save_flags_ptr((unsigned long *)&flags)
 #define __save_and_cli(flags) ({__save_flags(flags);__cli();})
+#define __save_and_sti(flags) ({__save_flags(flags);__sti();})
 
 extern void do_lost_interrupts(unsigned long);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/ide.h linux-2.4.21/include/asm-ppc/ide.h
--- linux-2.4.20/include/asm-ppc/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-ppc/ide.h	2002-12-18 18:58:06.000000000 +0000
@@ -30,17 +30,9 @@
 #include <linux/ioport.h>
 #include <asm/io.h>
 
-extern void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
-
 struct ide_machdep_calls {
         int         (*default_irq)(ide_ioreg_t base);
         ide_ioreg_t (*default_io_base)(int index);
-        int         (*ide_check_region)(ide_ioreg_t from, unsigned int extent);
-        void        (*ide_request_region)(ide_ioreg_t from,
-                                      unsigned int extent,
-                                      const char *name);
-        void        (*ide_release_region)(ide_ioreg_t from,
-                                      unsigned int extent);
         void        (*ide_init_hwif)(hw_regs_t *hw,
                                      ide_ioreg_t data_port,
                                      ide_ioreg_t ctrl_port,
@@ -49,16 +41,11 @@
 
 extern struct ide_machdep_calls ppc_ide_md;
 
-void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
-#define ide_fix_driveid(id)	ppc_generic_ide_fix_driveid((id))
-
 #undef	SUPPORT_SLOW_DATA_PORTS
 #define	SUPPORT_SLOW_DATA_PORTS	0
 #undef	SUPPORT_VLB_SYNC
 #define SUPPORT_VLB_SYNC	0
 
-#define ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	if (ppc_ide_md.default_irq)
@@ -99,67 +86,13 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
-{
-	if (ppc_ide_md.ide_check_region)
-		return ppc_ide_md.ide_check_region(from, extent);
-	return 0;
-}
-
-static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name)
-{
-	if (ppc_ide_md.ide_request_region)
-		ppc_ide_md.ide_request_region(from, extent, name);
-}
-
-static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent)
-{
-	if (ppc_ide_md.ide_release_region)
-		ppc_ide_md.ide_release_region(from, extent);
-}
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit7		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned unit		: 1;	/* drive select number, 0/1 */
-		unsigned head		: 4;	/* always zeros here */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-		unsigned reserved456	: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned bit0		: 1;
-	} b;
-} control_t;
-
-#if !defined(ide_request_irq)
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#endif
-
-#if !defined(ide_free_irq)
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#endif
-
 /*
  * The following are not needed for the non-m68k ports
  * unless direct IDE on 8xx
  */
 #if (defined CONFIG_APUS || defined CONFIG_BLK_DEV_MPC8xx_IDE )
-#define ide_ack_intr(hwif) (hwif->hw.ack_intr ? hwif->hw.ack_intr(hwif) : 1)
-#else
-#define ide_ack_intr(hwif)		(1)
+#define IDE_ARCH_ACK_INTR 1
 #endif
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/semaphore.h linux-2.4.21/include/asm-ppc/semaphore.h
--- linux-2.4.20/include/asm-ppc/semaphore.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-ppc/semaphore.h	2002-12-18 18:58:09.000000000 +0000
@@ -12,7 +12,7 @@
  * -- Ani Joshi (ajoshi@unixbox.com)
  *
  * Remove spinlock-based RW semaphores; RW semaphore definitions are
- * now in rwsem.h and we use the the generic lib/rwsem.c implementation.
+ * now in rwsem.h and we use the generic lib/rwsem.c implementation.
  * Rework semaphores to use atomic_dec_if_positive.
  * -- Paul Mackerras (paulus@samba.org)
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/system.h linux-2.4.21/include/asm-ppc/system.h
--- linux-2.4.20/include/asm-ppc/system.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-ppc/system.h	2002-12-18 18:58:07.000000000 +0000
@@ -105,6 +105,7 @@
 #define save_flags(flags)	__save_flags(flags)
 #define restore_flags(flags)	__restore_flags(flags)
 #define save_and_cli(flags)	__save_and_cli(flags)
+#define save_and_sti(flags)	__save_and_sti(flags)
 
 #else /* CONFIG_SMP */
 
@@ -117,11 +118,15 @@
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
 
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0);
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
+
 #endif /* !CONFIG_SMP */
 
 #define local_irq_disable()		__cli()
 #define local_irq_enable()		__sti()
 #define local_irq_save(flags)		__save_and_cli(flags)
+#define local_irq_set(flags)		__save_and_sti(flags)
 #define local_irq_restore(flags)	__restore_flags(flags)
 
 static __inline__ unsigned long
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/hw_irq.h linux-2.4.21/include/asm-ppc64/hw_irq.h
--- linux-2.4.20/include/asm-ppc64/hw_irq.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-ppc64/hw_irq.h	2002-12-18 18:58:08.000000000 +0000
@@ -31,6 +31,7 @@
 #define __save_flags(flags)	((flags) = __no_use_save_flags())
 #define __restore_flags(flags)	__no_use_restore_flags((unsigned long)flags)
 #define __save_and_cli(flags)	({__save_flags(flags);__cli();})
+#define __save_and_sti(flags)	({__save_flags(flags);__sti();})
 
 #else
 
@@ -63,6 +64,7 @@
 }
 
 #define __save_and_cli(flags)          __do_save_and_cli(&flags)
+#define __save_and_sti(flags)		({__save_flags(flags);__sti();})
 
 #endif /* CONFIG_PPC_ISERIES */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/ide.h linux-2.4.21/include/asm-ppc64/ide.h
--- linux-2.4.20/include/asm-ppc64/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-ppc64/ide.h	2002-12-18 18:58:07.000000000 +0000
@@ -22,8 +22,6 @@
 #define MAX_HWIFS	4
 #endif
 
-#define ide__sti()	__sti()
-
 void ppc64_ide_fix_driveid(struct hd_driveid *id);
 #define ide_fix_driveid(id)	ppc64_ide_fix_driveid((id))
 
@@ -53,30 +51,6 @@
 {
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-	} select_t;
-
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#define ide_check_region(from,extent)		check_region((from), (extent))
-#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
-#define ide_release_region(from,extent)		release_region((from), (extent))
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
 #endif /* __KERNEL__ */
 
 #endif /* __ASMPPC64_IDE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/system.h linux-2.4.21/include/asm-ppc64/system.h
--- linux-2.4.20/include/asm-ppc64/system.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-ppc64/system.h	2002-12-18 18:58:06.000000000 +0000
@@ -90,6 +90,7 @@
 #define save_flags(flags)	__save_flags(flags)
 #define restore_flags(flags)	__restore_flags(flags)
 #define save_and_cli(flags)	__save_and_cli(flags)
+#define save_and_sti(flags)	__save_and_sti(flags)
 
 #else /* CONFIG_SMP */
 
@@ -102,11 +103,15 @@
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
 
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0);
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
+
 #endif /* !CONFIG_SMP */
 
 #define local_irq_disable()		__cli()
 #define local_irq_enable()		__sti()
 #define local_irq_save(flags)		__save_and_cli(flags)
+#define local_irq_set(flags)		__save_and_sti(flags)
 #define local_irq_restore(flags)	__restore_flags(flags)
 
 static __inline__ int __is_processor(unsigned long pv)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390/ide.h linux-2.4.21/include/asm-s390/ide.h
--- linux-2.4.20/include/asm-s390/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-s390/ide.h	2002-12-18 18:58:09.000000000 +0000
@@ -15,45 +15,6 @@
 #define MAX_HWIFS	0
 #endif
 
-#define ide__sti()	do {} while (0)
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-#define ide_request_irq(irq,hand,flg,dev,id)	do {} while (0)
-#define ide_free_irq(irq,dev_id)		do {} while (0)
-#define ide_check_region(from,extent)		do {} while (0)
-#define ide_request_region(from,extent,name)	do {} while (0)
-#define ide_release_region(from,extent)		do {} while (0)
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
 /*
  * We always use the new IDE port registering,
  * so these are fixed here.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390/io.h linux-2.4.21/include/asm-s390/io.h
--- linux-2.4.20/include/asm-s390/io.h	2001-07-25 21:12:02.000000000 +0000
+++ linux-2.4.21/include/asm-s390/io.h	2002-12-18 18:58:10.000000000 +0000
@@ -40,6 +40,11 @@
         return __io_virt(address);
 }
 
+/*
+ * Change "struct page" to physical address.
+ */
+#define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
+
 extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
 extern inline void * ioremap (unsigned long offset, unsigned long size)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390/rwsem.h linux-2.4.21/include/asm-s390/rwsem.h
--- linux-2.4.20/include/asm-s390/rwsem.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-s390/rwsem.h	2002-12-18 18:58:02.000000000 +0000
@@ -105,6 +105,27 @@
 }
 
 /*
+ * trylock for reading -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   l    %0,0(%2)\n"
+		"0: ltr  %1,%0\n"
+		"   jm   1f\n"
+		"   ahi  %1,%3\n"
+		"   cs   %0,%1,0(%2)\n"
+		"   jl   0b\n"
+		"1:"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
+		: "cc", "memory" );
+	return old >= 0 ? 1 : 0;
+}
+
+/*
  * lock for writing
  */
 static inline void __down_write(struct rw_semaphore *sem)
@@ -126,6 +147,26 @@
 }
 
 /*
+ * trylock for writing -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+	signed long old;
+
+	__asm__ __volatile__(
+		"   l    %0,0(%1)\n"
+		"0: ltr  %0,%0\n"
+		"   jnz  1f\n"
+		"   cs   %0,%2,0(%1)\n"
+		"   jl   0b\n"
+		"1:"
+                : "=&d" (old)
+		: "a" (&sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS)
+		: "cc", "memory" );
+	return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
+}
+
+/*
  * unlock after reading
  */
 static inline void __up_read(struct rw_semaphore *sem)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390/system.h linux-2.4.21/include/asm-s390/system.h
--- linux-2.4.20/include/asm-s390/system.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-s390/system.h	2002-12-18 18:58:08.000000000 +0000
@@ -206,8 +206,12 @@
                 : "cc", "0", "1", "2"); \
         })
 
+#define __save_and_cli(x)	do { __save_flags(x); __cli(); } while(0);
+#define __save_and_sti(x)	do { __save_flags(x); __sti(); } while(0);
+
 /* For spinlocks etc */
 #define local_irq_save(x)	((x) = __cli())
+#define local_irq_set(x)	__save_and_sti(x)
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
@@ -223,6 +227,8 @@
 #define sti() __global_sti()
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0);
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
 
 extern void smp_ctl_set_bit(int cr, int bit);
 extern void smp_ctl_clear_bit(int cr, int bit);
@@ -235,6 +241,8 @@
 #define sti() __sti()
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
+#define save_and_cli(x) __save_and_cli(x)
+#define save_and_sti(x) __save_and_sti(x)
 
 #define ctl_set_bit(cr, bit) __ctl_set_bit(cr, bit)
 #define ctl_clear_bit(cr, bit) __ctl_clear_bit(cr, bit)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390x/ide.h linux-2.4.21/include/asm-s390x/ide.h
--- linux-2.4.20/include/asm-s390x/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-s390x/ide.h	2002-12-18 18:58:01.000000000 +0000
@@ -15,45 +15,6 @@
 #define MAX_HWIFS	0
 #endif
 
-#define ide__sti()	do {} while (0)
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-#define ide_request_irq(irq,hand,flg,dev,id)	do {} while (0)
-#define ide_free_irq(irq,dev_id)		do {} while (0)
-#define ide_check_region(from,extent)		do {} while (0)
-#define ide_request_region(from,extent,name)	do {} while (0)
-#define ide_release_region(from,extent)		do {} while (0)
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
 /*
  * We always use the new IDE port registering,
  * so these are fixed here.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390x/io.h linux-2.4.21/include/asm-s390x/io.h
--- linux-2.4.20/include/asm-s390x/io.h	2001-07-25 21:12:02.000000000 +0000
+++ linux-2.4.21/include/asm-s390x/io.h	2002-12-18 18:58:04.000000000 +0000
@@ -40,6 +40,11 @@
         return __io_virt(address);
 }
 
+/*
+ * Change "struct page" to physical address.
+ */
+#define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
+
 extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
 extern inline void * ioremap (unsigned long offset, unsigned long size)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390x/rwsem.h linux-2.4.21/include/asm-s390x/rwsem.h
--- linux-2.4.20/include/asm-s390x/rwsem.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-s390x/rwsem.h	2002-12-18 18:58:04.000000000 +0000
@@ -105,6 +105,27 @@
 }
 
 /*
+ * trylock for reading -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   l    %0,0(%2)\n"
+		"0: ltr  %1,%0\n"
+		"   jm   1f\n"
+		"   ahi  %1,%3\n"
+		"   cs   %0,%1,0(%2)\n"
+		"   jl   0b\n"
+		"1:"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
+		: "cc", "memory" );
+	return old >= 0 ? 1 : 0;
+}
+
+/*
  * lock for writing
  */
 static inline void __down_write(struct rw_semaphore *sem)
@@ -126,6 +147,26 @@
 }
 
 /*
+ * trylock for writing -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+	signed long old;
+
+	__asm__ __volatile__(
+		"   l    %0,0(%1)\n"
+		"0: ltr  %0,%0\n"
+		"   jnz  1f\n"
+		"   cs   %0,%2,0(%1)\n"
+		"   jl   0b\n"
+		"1:"
+                : "=&d" (old)
+		: "a" (&sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS)
+		: "cc", "memory" );
+	return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
+}
+
+/*
  * unlock after reading
  */
 static inline void __up_read(struct rw_semaphore *sem)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390x/system.h linux-2.4.21/include/asm-s390x/system.h
--- linux-2.4.20/include/asm-s390x/system.h	2002-12-18 18:27:09.000000000 +0000
+++ linux-2.4.21/include/asm-s390x/system.h	2002-12-18 18:58:11.000000000 +0000
@@ -216,8 +216,13 @@
                 : "cc", "0", "1", "2"); \
         })
 
+
+#define __save_and_cli(x)       do { __save_flags(x); __cli(); } while(0);
+#define __save_and_sti(x)       do { __save_flags(x); __sti(); } while(0);
+
 /* For spinlocks etc */
 #define local_irq_save(x)	((x) = __cli())
+#define local_irq_set(x)	__save_and_sti(x)
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
@@ -233,6 +238,8 @@
 #define sti() __global_sti()
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0);
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
 
 extern void smp_ctl_set_bit(int cr, int bit);
 extern void smp_ctl_clear_bit(int cr, int bit);
@@ -245,6 +252,8 @@
 #define sti() __sti()
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
+#define save_and_cli(x) __save_and_cli(x)
+#define save_and_sti(x) __save_and_sti(x)
 
 #define ctl_set_bit(cr, bit) __ctl_set_bit(cr, bit)
 #define ctl_clear_bit(cr, bit) __ctl_clear_bit(cr, bit)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sh/hdreg.h linux-2.4.21/include/asm-sh/hdreg.h
--- linux-2.4.20/include/asm-sh/hdreg.h	2000-03-05 17:33:55.000000000 +0000
+++ linux-2.4.21/include/asm-sh/hdreg.h	2002-12-18 18:58:05.000000000 +0000
@@ -7,6 +7,7 @@
 #ifndef __ASM_SH_HDREG_H
 #define __ASM_SH_HDREG_H
 
-typedef unsigned int ide_ioreg_t;
+//typedef unsigned int ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASM_SH_HDREG_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sh/ide.h linux-2.4.21/include/asm-sh/ide.h
--- linux-2.4.20/include/asm-sh/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-sh/ide.h	2002-12-18 18:58:05.000000000 +0000
@@ -22,8 +22,6 @@
 #define MAX_HWIFS	2
 #endif
 
-#define ide__sti()	__sti()
-
 static __inline__ int ide_default_irq_hp600(ide_ioreg_t base)
 {
 	switch (base) {
@@ -107,42 +105,7 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#define ide_check_region(from,extent)		check_region((from), (extent))
-#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
-#define ide_release_region(from,extent)		release_region((from), (extent))
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+#include <asm-generic/ide_iops.h>
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sh/system.h linux-2.4.21/include/asm-sh/system.h
--- linux-2.4.20/include/asm-sh/system.h	2001-09-08 19:29:09.000000000 +0000
+++ linux-2.4.21/include/asm-sh/system.h	2002-12-18 18:58:11.000000000 +0000
@@ -215,8 +215,11 @@
 		: "=&r" (__dummy));			\
 } while (0)
 
+#define __save_and_sti(x)       do { __save_flags(x); __sti(); } while(0);
+
 /* For spinlocks etc */
 #define local_irq_save(x)	x = __save_and_cli()
+#define local_irq_set(x)	__save_and_sti(x)
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
@@ -231,13 +234,14 @@
 #define sti() __global_sti()
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
-
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
 #else
 
 #define cli() __cli()
 #define sti() __sti()
 #define save_flags(x) __save_flags(x)
 #define save_and_cli(x) x = __save_and_cli()
+#define save_and_sti(x) __save_and_sti(x)
 #define restore_flags(x) __restore_flags(x)
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc/ide.h linux-2.4.21/include/asm-sparc/ide.h
--- linux-2.4.20/include/asm-sparc/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-sparc/ide.h	2002-12-18 18:58:09.000000000 +0000
@@ -20,8 +20,6 @@
 #undef  MAX_HWIFS
 #define MAX_HWIFS	2
 
-#define	ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	return 0;
@@ -73,56 +71,6 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned int		all	: 8;	/* all of the bits together */
-	struct {
-		unsigned int	bit7	: 1;
-		unsigned int	lba	: 1;
-		unsigned int	bit5	: 1;
-		unsigned int	unit	: 1;
-		unsigned int	head	: 4;
-	} b;
-} select_t;
-
-typedef union {
-	unsigned int all		: 8;	/* all of the bits together */
-	struct {
-		unsigned int HOB	: 1;	/* 48-bit address ordering */
-		unsigned int reserved456: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned int SRST	: 1;	/* host soft reset bit */
-		unsigned int nIEN	: 1;	/* device INTRQ to host */
-		unsigned int bit0	: 1;
-	} b;
-} control_t;
-
-static __inline__ int ide_request_irq(unsigned int irq,
-				      void (*handler)(int, void *, struct pt_regs *),
-				      unsigned long flags, const char *name, void *devid)
-{
-	return request_irq(irq, handler, SA_SHIRQ, name, devid);
-}
-
-static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
-{
-	free_irq(irq, dev_id);
-}
-
-static __inline__ int ide_check_region(ide_ioreg_t base, unsigned int size)
-{
-	/* We leave these empty because pcic.c calls sparc_alloc_io() */
-	return 0;
-}
-
-static __inline__ void ide_request_region(ide_ioreg_t base, unsigned int size,
-					  const char *name)
-{
-}
-
-static __inline__ void ide_release_region(ide_ioreg_t base, unsigned int size)
-{
-}
-
 #undef  SUPPORT_SLOW_DATA_PORTS
 #define SUPPORT_SLOW_DATA_PORTS 0
 
@@ -215,103 +163,6 @@
 	/* __flush_dcache_range((unsigned long)src, end); */ /* P3 see hme */
 }
 
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-	int i;
-	u16 *stringcast;
-
-	id->config         = __le16_to_cpu(id->config);
-	id->cyls           = __le16_to_cpu(id->cyls);
-	id->reserved2      = __le16_to_cpu(id->reserved2);
-	id->heads          = __le16_to_cpu(id->heads);
-	id->track_bytes    = __le16_to_cpu(id->track_bytes);
-	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
-	id->sectors        = __le16_to_cpu(id->sectors);
-	id->vendor0        = __le16_to_cpu(id->vendor0);
-	id->vendor1        = __le16_to_cpu(id->vendor1);
-	id->vendor2        = __le16_to_cpu(id->vendor2);
-	stringcast = (u16 *)&id->serial_no[0];
-	for (i = 0; i < (20/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->buf_type       = __le16_to_cpu(id->buf_type);
-	id->buf_size       = __le16_to_cpu(id->buf_size);
-	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
-	stringcast = (u16 *)&id->fw_rev[0];
-	for (i = 0; i < (8/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	stringcast = (u16 *)&id->model[0];
-	for (i = 0; i < (40/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->dword_io       = __le16_to_cpu(id->dword_io);
-	id->reserved50     = __le16_to_cpu(id->reserved50);
-	id->field_valid    = __le16_to_cpu(id->field_valid);
-	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
-	id->cur_heads      = __le16_to_cpu(id->cur_heads);
-	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
-	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
-	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
-	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
-	id->dma_1word      = __le16_to_cpu(id->dma_1word);
-	id->dma_mword      = __le16_to_cpu(id->dma_mword);
-	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
-	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
-	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
-	id->eide_pio       = __le16_to_cpu(id->eide_pio);
-	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-	for (i = 0; i < 2; i++)
-		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
-        for (i = 0; i < 4; i++)
-                id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
-	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
-	for (i = 0; i < 4; i++)
-		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
-	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
-	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
-	id->command_set_1  = __le16_to_cpu(id->command_set_1);
-	id->command_set_2  = __le16_to_cpu(id->command_set_2);
-	id->cfsse          = __le16_to_cpu(id->cfsse);
-	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
-	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
-	id->csf_default    = __le16_to_cpu(id->csf_default);
-	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-	id->word89         = __le16_to_cpu(id->word89);
-	id->word90         = __le16_to_cpu(id->word90);
-	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-	id->word92         = __le16_to_cpu(id->word92);
-	id->hw_config      = __le16_to_cpu(id->hw_config);
-	id->acoustic       = __le16_to_cpu(id->acoustic);
-	for (i = 0; i < 5; i++)
-		id->words95_99[i]  = __le16_to_cpu(id->words95_99[i]);
-	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
-	for (i = 0; i < 22; i++)
-		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
-	id->last_lun       = __le16_to_cpu(id->last_lun);
-	id->word127        = __le16_to_cpu(id->word127);
-	id->dlf            = __le16_to_cpu(id->dlf);
-	id->csfo           = __le16_to_cpu(id->csfo);
-	for (i = 0; i < 26; i++)
-		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
-	id->word156        = __le16_to_cpu(id->word156);
-	for (i = 0; i < 3; i++)
-		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
-	id->cfa_power      = __le16_to_cpu(id->cfa_power);
-	for (i = 0; i < 14; i++)
-		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
-	for (i = 0; i < 31; i++)
-		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
-	for (i = 0; i < 48; i++)
-		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
-	id->integrity_word  = __le16_to_cpu(id->integrity_word);
-}
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-/* #define ide_ack_intr(hwif)	((hwif)->hw.ack_intr ? (hwif)->hw.ack_intr(hwif) : 1) */
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
 #endif /* __KERNEL__ */
 
 #endif /* _SPARC_IDE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc/irq.h linux-2.4.21/include/asm-sparc/irq.h
--- linux-2.4.20/include/asm-sparc/irq.h	2000-08-29 04:20:03.000000000 +0000
+++ linux-2.4.21/include/asm-sparc/irq.h	2002-12-18 18:58:01.000000000 +0000
@@ -19,7 +19,7 @@
 BTFIXUPDEF_CALL(char *, __irq_itoa, unsigned int)
 #define __irq_itoa(irq) BTFIXUP_CALL(__irq_itoa)(irq)
 
-#define NR_IRQS    15
+#define NR_IRQS    16
 
 /* Dave Redman (djhr@tadpole.co.uk)
  * changed these to function pointers.. it saves cycles and will allow
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc/system.h linux-2.4.21/include/asm-sparc/system.h
--- linux-2.4.20/include/asm-sparc/system.h	2001-10-30 23:08:11.000000000 +0000
+++ linux-2.4.21/include/asm-sparc/system.h	2002-12-18 18:58:10.000000000 +0000
@@ -146,7 +146,7 @@
 	  "i" ((const unsigned long)(&((struct task_struct *)0)->thread.kpsr)),		\
 	  "i" ((const unsigned long)(&((struct task_struct *)0)->thread.ksp)),		\
 	  "r" (task_pc)									\
-	: "g1", "g2", "g3", "g4", "g5", "g7", "l0", "l1",				\
+	: "g1", "g2", "g3", "g4", "g5", "g7", "l0", "l1", "l3",				\
 	"l4", "l5", "l6", "l7", "i0", "i1", "i2", "i3", "i4", "i5", "o0", "o1", "o2",	\
 	"o3");										\
 here:;  } while(0)
@@ -241,12 +241,31 @@
 	return retval;
 }
 
+extern __inline__ unsigned long read_psr_and_sti(void)
+{
+	unsigned long retval;
+
+	__asm__ __volatile__(
+		"rd	%%psr, %0\n\t"
+		"nop; nop; nop;\n\t"	/* Sun4m + Cypress + SMP bug */
+		"andn	%0, %1, %%g1\n\t"
+		"wr	%%g1, 0x0, %%psr\n\t"
+		"nop; nop; nop\n\t"
+		: "=r" (retval)
+		: "i" (PSR_PIL)
+		: "g1", "memory");
+
+	return retval;
+}
+
 #define __save_flags(flags)	((flags) = getipl())
 #define __save_and_cli(flags)	((flags) = read_psr_and_cli())
+#define __save_and_sti(flags)	((flags) = read_psr_and_sti())
 #define __restore_flags(flags)	setipl((flags))
 #define local_irq_disable()		__cli()
 #define local_irq_enable()		__sti()
 #define local_irq_save(flags)		__save_and_cli(flags)
+#define local_irq_set(flags)		__save_and_sti(flags)
 #define local_irq_restore(flags)	__restore_flags(flags)
 
 #ifdef CONFIG_SMP
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc64/ide.h linux-2.4.21/include/asm-sparc64/ide.h
--- linux-2.4.20/include/asm-sparc64/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-sparc64/ide.h	2002-12-18 18:58:07.000000000 +0000
@@ -20,8 +20,6 @@
 #undef  MAX_HWIFS
 #define MAX_HWIFS	2
 
-#define	ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	return 0;
@@ -69,57 +67,6 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned int		all	: 8;	/* all of the bits together */
-	struct {
-		unsigned int	bit7	: 1;
-		unsigned int	lba	: 1;
-		unsigned int	bit5	: 1;
-		unsigned int	unit	: 1;
-		unsigned int	head	: 4;
-	} b;
-} select_t;
-
-typedef union {
-	unsigned int all		: 8;	/* all of the bits together */
-	struct {
-		unsigned int HOB	: 1;	/* 48-bit address ordering */
-		unsigned int reserved456: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned int SRST	: 1;	/* host soft reset bit */
-		unsigned int nIEN	: 1;	/* device INTRQ to host */
-		unsigned int bit0	: 1;
-	} b;
-} control_t;
-
-static __inline__ int ide_request_irq(unsigned int irq,
-				      void (*handler)(int, void *, struct pt_regs *),
-				      unsigned long flags, const char *name, void *devid)
-{
-	return request_irq(irq, handler, SA_SHIRQ, name, devid);
-}
-
-static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
-{
-	free_irq(irq, dev_id);
-}
-
-static __inline__ int ide_check_region(ide_ioreg_t base, unsigned int size)
-{
-	return check_region(base, size);
-}
-
-static __inline__ void ide_request_region(ide_ioreg_t base, unsigned int size,
-					  const char *name)
-{
-	request_region(base, size, name);
-}
-
-static __inline__ void ide_release_region(ide_ioreg_t base, unsigned int size)
-{
-	release_region(base, size);
-}
-
 #undef  SUPPORT_SLOW_DATA_PORTS
 #define SUPPORT_SLOW_DATA_PORTS 0
 
@@ -129,26 +76,16 @@
 #undef  HD_DATA
 #define HD_DATA ((ide_ioreg_t)0)
 
-/* From m68k code... */
-
-#ifdef insl
-#undef insl
-#endif
-#ifdef outsl
-#undef outsl
-#endif
-#ifdef insw
-#undef insw
-#endif
-#ifdef outsw
-#undef outsw
-#endif
-
-#define insl(data_reg, buffer, wcount) insw(data_reg, buffer, (wcount)<<1)
-#define outsl(data_reg, buffer, wcount) outsw(data_reg, buffer, (wcount)<<1)
-
-#define insw(port, buf, nr) ide_insw((port), (buf), (nr))
-#define outsw(port, buf, nr) ide_outsw((port), (buf), (nr))
+#define __ide_insl(data_reg, buffer, wcount) \
+	__ide_insw(data_reg, buffer, (wcount)<<1)
+#define __ide_outsl(data_reg, buffer, wcount) \
+	__ide_outsw(data_reg, buffer, (wcount)<<1)
+
+/* On sparc64, I/O ports and MMIO registers are accessed identically.  */
+#define __ide_mm_insw	__ide_insw
+#define __ide_mm_insl	__ide_insl
+#define __ide_mm_outsw	__ide_outsw
+#define __ide_mm_outsl	__ide_outsl
 
 static __inline__ unsigned int inw_be(unsigned long addr)
 {
@@ -161,9 +98,9 @@
 	return ret;
 }
 
-static __inline__ void ide_insw(unsigned long port,
-				void *dst,
-				unsigned long count)
+static __inline__ void __ide_insw(unsigned long port,
+				  void *dst,
+				  u32 count)
 {
 #if (L1DCACHE_SIZE > PAGE_SIZE)		/* is there D$ aliasing problem */
 	unsigned long end = (unsigned long)dst + (count << 1);
@@ -200,9 +137,9 @@
 			     : "r" (w), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
 }
 
-static __inline__ void ide_outsw(unsigned long port,
-				 const void *src,
-				 unsigned long count)
+static __inline__ void __ide_outsw(unsigned long port,
+				   void *src,
+				   u32 count)
 {
 #if (L1DCACHE_SIZE > PAGE_SIZE)		/* is there D$ aliasing problem */
 	unsigned long end = (unsigned long)src + (count << 1);
@@ -232,102 +169,6 @@
 #endif
 }
 
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-	int i;
-	u16 *stringcast;
-
-	id->config         = __le16_to_cpu(id->config);
-	id->cyls           = __le16_to_cpu(id->cyls);
-	id->reserved2      = __le16_to_cpu(id->reserved2);
-	id->heads          = __le16_to_cpu(id->heads);
-	id->track_bytes    = __le16_to_cpu(id->track_bytes);
-	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
-	id->sectors        = __le16_to_cpu(id->sectors);
-	id->vendor0        = __le16_to_cpu(id->vendor0);
-	id->vendor1        = __le16_to_cpu(id->vendor1);
-	id->vendor2        = __le16_to_cpu(id->vendor2);
-	stringcast = (u16 *)&id->serial_no[0];
-	for (i = 0; i < (20/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->buf_type       = __le16_to_cpu(id->buf_type);
-	id->buf_size       = __le16_to_cpu(id->buf_size);
-	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
-	stringcast = (u16 *)&id->fw_rev[0];
-	for (i = 0; i < (8/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	stringcast = (u16 *)&id->model[0];
-	for (i = 0; i < (40/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->dword_io       = __le16_to_cpu(id->dword_io);
-	id->reserved50     = __le16_to_cpu(id->reserved50);
-	id->field_valid    = __le16_to_cpu(id->field_valid);
-	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
-	id->cur_heads      = __le16_to_cpu(id->cur_heads);
-	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
-	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
-	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
-	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
-	id->dma_1word      = __le16_to_cpu(id->dma_1word);
-	id->dma_mword      = __le16_to_cpu(id->dma_mword);
-	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
-	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
-	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
-	id->eide_pio       = __le16_to_cpu(id->eide_pio);
-	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-	for (i = 0; i < 2; i++)
-		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
-        for (i = 0; i < 4; i++)
-                id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
-	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
-	for (i = 0; i < 4; i++)
-		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
-	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
-	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
-	id->command_set_1  = __le16_to_cpu(id->command_set_1);
-	id->command_set_2  = __le16_to_cpu(id->command_set_2);
-	id->cfsse          = __le16_to_cpu(id->cfsse);
-	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
-	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
-	id->csf_default    = __le16_to_cpu(id->csf_default);
-	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-	id->word89         = __le16_to_cpu(id->word89);
-	id->word90         = __le16_to_cpu(id->word90);
-	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-	id->word92         = __le16_to_cpu(id->word92);
-	id->hw_config      = __le16_to_cpu(id->hw_config);
-	id->acoustic       = __le16_to_cpu(id->acoustic);
-	for (i = 0; i < 5; i++)
-		id->words95_99[i]  = __le16_to_cpu(id->words95_99[i]);
-	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
-	for (i = 0; i < 22; i++)
-		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
-	id->last_lun       = __le16_to_cpu(id->last_lun);
-	id->word127        = __le16_to_cpu(id->word127);
-	id->dlf            = __le16_to_cpu(id->dlf);
-	id->csfo           = __le16_to_cpu(id->csfo);
-	for (i = 0; i < 26; i++)
-		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
-	id->word156        = __le16_to_cpu(id->word156);
-	for (i = 0; i < 3; i++)
-		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
-	id->cfa_power      = __le16_to_cpu(id->cfa_power);
-	for (i = 0; i < 14; i++)
-		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
-	for (i = 0; i < 31; i++)
-		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
-	for (i = 0; i < 48; i++)
-		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
-	id->integrity_word  = __le16_to_cpu(id->integrity_word);
-}
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
 #endif /* __KERNEL__ */
 
 #endif /* _SPARC64_IDE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc64/irq.h linux-2.4.21/include/asm-sparc64/irq.h
--- linux-2.4.20/include/asm-sparc64/irq.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-sparc64/irq.h	2002-12-18 18:58:09.000000000 +0000
@@ -109,7 +109,7 @@
 	return buff;
 }
 
-#define NR_IRQS    15
+#define NR_IRQS    16
 
 extern void disable_irq(unsigned int);
 #define disable_irq_nosync disable_irq
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc64/system.h linux-2.4.21/include/asm-sparc64/system.h
--- linux-2.4.20/include/asm-sparc64/system.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/asm-sparc64/system.h	2002-12-18 18:58:01.000000000 +0000
@@ -62,12 +62,23 @@
 	retval; \
 })
 
+#define read_pil_and_sti() \
+({	unsigned long retval; \
+	__asm__ __volatile__("rdpr	%%pil, %0\n\t" \
+			     "wrpr	0, %%pil" \
+			     : "=r" (retval) \
+			     : : "memory"); \
+	retval; \
+})
+
 #define __save_flags(flags)		((flags) = getipl())
 #define __save_and_cli(flags)		((flags) = read_pil_and_cli())
+#define __save_and_sti(flags)		((flags) = read_pil_and_sti())
 #define __restore_flags(flags)		setipl((flags))
 #define local_irq_disable()		__cli()
 #define local_irq_enable()		__sti()
 #define local_irq_save(flags)		__save_and_cli(flags)
+#define local_irq_set(flags)		__save_and_sti(flags)
 #define local_irq_restore(flags)	__restore_flags(flags)
 
 #ifndef CONFIG_SMP
@@ -172,6 +183,11 @@
 	 * not preserve it's value.  Hairy, but it lets us remove 2 loads
 	 * and 2 stores in this critical code path.  -DaveM
 	 */
+#if __GNUC__ >= 3
+#define EXTRA_CLOBBER ,"%l1"
+#else
+#define EXTRA_CLOBBER
+#endif
 #define switch_to(prev, next, last)						\
 do {	CHECK_LOCKS(prev);							\
 	if (current->thread.flags & SPARC_FLAG_PERFCTR) {			\
@@ -220,10 +236,11 @@
 	  "i" ((const unsigned long)(&((struct task_struct *)0)->thread.flags)),\
 	  "i" ((const unsigned long)(&((struct task_struct *)0)->thread.cwp)),	\
 	  "i" (SPARC_FLAG_NEWCHILD)						\
-	: "cc", "g1", "g2", "g3", "g5", "g7",					\
-	  "l2", "l3", "l4", "l5", "l6", "l7",					\
+	: "cc",									\
+                "g1", "g2", "g3",       "g5",       "g7",			\
+	              "l2", "l3", "l4", "l5", "l6", "l7",			\
 	  "i0", "i1", "i2", "i3", "i4", "i5",					\
-	  "o0", "o1", "o2", "o3", "o4", "o5", "o7");				\
+	  "o0", "o1", "o2", "o3", "o4", "o5",       "o7" EXTRA_CLOBBER);	\
 	/* If you fuck with this, update ret_from_syscall code too. */		\
 	if (current->thread.flags & SPARC_FLAG_PERFCTR) {			\
 		write_pcr(current->thread.pcr_reg);				\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/hdreg.h linux-2.4.21/include/asm-x86_64/hdreg.h
--- linux-2.4.20/include/asm-x86_64/hdreg.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/include/asm-x86_64/hdreg.h	2002-12-18 18:58:05.000000000 +0000
@@ -7,6 +7,7 @@
 #ifndef __ASMx86_64_HDREG_H
 #define __ASMx86_64_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+//typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASMx86_64_HDREG_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/ide.h linux-2.4.21/include/asm-x86_64/ide.h
--- linux-2.4.20/include/asm-x86_64/ide.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/include/asm-x86_64/ide.h	2002-12-18 18:58:05.000000000 +0000
@@ -5,7 +5,7 @@
  */
 
 /*
- *  This file contains the x86_64 architecture specific IDE code.
+ *  This file contains the i386 architecture specific IDE code.
  */
 
 #ifndef __ASMx86_64_IDE_H
@@ -23,8 +23,6 @@
 # endif
 #endif
 
-#define ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	switch (base) {
@@ -86,42 +84,7 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#define ide_check_region(from,extent)		check_region((from), (extent))
-#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
-#define ide_release_region(from,extent)		release_region((from), (extent))
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+#include <asm-generic/ide_iops.h>
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/agp_backend.h linux-2.4.21/include/linux/agp_backend.h
--- linux-2.4.20/include/linux/agp_backend.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/include/linux/agp_backend.h	2002-12-18 18:58:05.000000000 +0000
@@ -60,6 +60,7 @@
 	VIA_APOLLO_PRO,
 	VIA_APOLLO_KX133,
 	VIA_APOLLO_KT133,
+	VIA_APOLLO_KT400,
 	SIS_GENERIC,
 	AMD_GENERIC,
 	AMD_IRONGATE,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/blkcdb.h linux-2.4.21/include/linux/blkcdb.h
--- linux-2.4.20/include/linux/blkcdb.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/include/linux/blkcdb.h	2002-12-18 18:58:01.000000000 +0000
@@ -0,0 +1,101 @@
+/*
+ * 2.5 Command Descriptor Block (CDB) Block Pre-Handler.
+ *
+ * Copyright (C) 2001 Andre Hedrick <andre@linux-ide.org>
+ *
+ * This program is free software; you can redistribute it 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 more details.
+ *
+ * You should have received a copy of the GNU General Public Licens
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-
+ */
+
+#ifndef _LINUX_BLKCDB_H
+#define _LINUX_BLKCDB_H
+
+typedef struct cdb_list {
+#if 0
+        unsigned char cdb_0;
+        unsigned char cdb_1;
+        unsigned char cdb_2;
+        unsigned char cdb_3;
+        unsigned char cdb_4;
+        unsigned char cdb_5;
+        unsigned char cdb_6;
+        unsigned char cdb_7;
+        unsigned char cdb_8;
+        unsigned char cdb_9;
+        unsigned char cdb_10;
+        unsigned char cdb_11;
+        unsigned char cdb_12;
+        unsigned char cdb_13;
+        unsigned char cdb_14;
+        unsigned char cdb_15;
+#else
+        unsigned char cdb_regs[16];
+#endif
+} cdb_list_t;
+
+#if 0
+
+typedef cdb_list_t * (queue_proc) (kdev_t dev);
+
+request_queue_t *ide_get_queue (kdev_t dev)
+{
+        ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[MAJOR(dev)].data;
+
+        return &hwif->drives[DEVICE_NR(dev) & 1].queue;
+}
+
+static request_queue_t *sd_find_queue(kdev_t dev)
+{
+        Scsi_Disk *dpnt;
+        int target;
+        target = DEVICE_NR(dev);
+
+        dpnt = &rscsi_disks[target];
+        if (!dpnt)
+                return NULL;    /* No such device */
+        return &dpnt->device->request_queue;
+}
+
+prebuilder:             NULL,
+block_device_operations
+struct block_device {
+
+void do_ide_request(request_queue_t *q)
+
+ide_do_request
+
+typedef cdb_list_t (request_cdb_proc) (request_queue_t *q);
+
+typedef cdb_list_t (request_cdb_proc) (request_queue_t *q);
+typedef void (request_fn_proc) (request_queue_t *q);
+
+srb
+
+switch (SCpnt->request.cmd)
+SCpnt->cmnd[0] = WRITE_6/READ_6;
+SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
+			((SCpnt->lun << 5) & 0xe0) : 0;
+SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
+SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff;
+SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff;
+SCpnt->cmnd[5] = (unsigned char) block & 0xff;
+SCpnt->cmnd[6] = 0;
+SCpnt->cmnd[7] = (unsigned char) (this_count >> 8) & 0xff;
+SCpnt->cmnd[8] = (unsigned char) this_count & 0xff;
+SCpnt->cmnd[9] = 0;
+
+#endif
+
+#endif /* _LINUX_BLKCDB_H */
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/blkdev.h linux-2.4.21/include/linux/blkdev.h
--- linux-2.4.20/include/linux/blkdev.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/include/linux/blkdev.h	2002-12-18 18:58:04.000000000 +0000
@@ -140,6 +140,22 @@
 	wait_queue_head_t	wait_for_requests[2];
 };
 
+#define blk_queue_plugged(q)	(q)->plugged
+#define blk_fs_request(rq)	((rq)->cmd == READ || (rq)->cmd == WRITE)
+#define blk_queue_empty(q)	list_empty(&(q)->queue_head)
+
+extern inline int rq_data_dir(struct request *rq)
+{
+	if (rq->cmd == READ)
+		return READ;
+	else if (rq->cmd == WRITE)
+		return WRITE;
+	else {
+		BUG();
+		return -1; /* ahem */
+	}
+}
+
 extern unsigned long blk_max_low_pfn, blk_max_pfn;
 
 #define BLK_BOUNCE_HIGH		(blk_max_low_pfn << PAGE_SHIFT)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/cciss_ioctl.h linux-2.4.21/include/linux/cciss_ioctl.h
--- linux-2.4.20/include/linux/cciss_ioctl.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/linux/cciss_ioctl.h	2002-12-18 18:58:07.000000000 +0000
@@ -73,10 +73,10 @@
 #define TYPE_MSG				0x01
 
 // Type defs used in the following structs
-#define BYTE __u8
-#define WORD __u16
-#define HWORD __u16
-#define DWORD __u32
+typedef __u8 BYTE;
+typedef __u16 WORD; 
+typedef __u16 HWORD; 
+typedef __u32 DWORD; 
 
 #define CISS_MAX_LUN	16	
 
@@ -169,6 +169,18 @@
   BYTE			   *buf;
 } IOCTL_Command_struct;
 
+#define MAX_KMALLOC_SIZE 128000
+
+typedef struct _BIG_IOCTL_Command_struct {
+  LUNAddr_struct	   LUN_info;
+  RequestBlock_struct      Request;
+  ErrorInfo_struct  	   error_info; 
+  DWORD			   malloc_size; /* < MAX_KMALLOC_SIZE in cciss.c */
+  DWORD			   buf_size;    /* size in bytes of the buf */
+  				        /* < malloc_size * MAXSGENTRIES */
+  BYTE			   *buf;
+} BIG_IOCTL_Command_struct;
+
 typedef struct _LogvolInfo_struct{
    __u32	LunID;
    int		num_opens;  /* number of opens on the logical volume */
@@ -189,7 +201,11 @@
 #define CCISS_GETDRIVVER   _IOR(CCISS_IOC_MAGIC, 9, DriverVer_type)
 #define CCISS_REVALIDVOLS  _IO(CCISS_IOC_MAGIC, 10) /* obsolete */
 #define CCISS_PASSTHRU	   _IOWR(CCISS_IOC_MAGIC, 11, IOCTL_Command_struct)
+#define CCISS_DEREGDISK	   _IO(CCISS_IOC_MAGIC, 12)
+#define CCISS_REGNEWDISK  _IOW(CCISS_IOC_MAGIC, 13, __u64)
+#define CCISS_REGNEWD	   _IO(CCISS_IOC_MAGIC, 14)
+#define CCISS_RESCANDISK   _IO(CCISS_IOC_MAGIC, 16)
 #define CCISS_GETLUNINFO  _IOR(CCISS_IOC_MAGIC, 17, LogvolInfo_struct)
-
+#define CCISS_BIG_PASSTHRU _IOWR(CCISS_IOC_MAGIC, 18, BIG_IOCTL_Command_struct)
 
 #endif  
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/com20020.h linux-2.4.21/include/linux/com20020.h
--- linux-2.4.20/include/linux/com20020.h	2001-08-12 18:42:31.000000000 +0000
+++ linux-2.4.21/include/linux/com20020.h	2002-12-18 18:58:03.000000000 +0000
@@ -32,7 +32,7 @@
 void com20020_remove(struct net_device *dev);
 
 /* The number of low I/O ports used by the card. */
-#define ARCNET_TOTAL_SIZE 9
+#define ARCNET_TOTAL_SIZE 8
 
 /* various register addresses */
 #define _INTMASK  (ioaddr+0)	/* writable */
@@ -59,6 +59,8 @@
 
 /* in SETUP register */
 #define PROMISCset	0x10	/* enable RCV_ALL */
+#define P1MODE          0x80    /* enable P1-MODE for Backplane */
+#define SLOWARB         0x01    /* enable Slow Arbitration for >=5Mbps */
 
 /* COM2002x */
 #define SUB_TENTATIVE	0	/* tentative node ID */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/cyclades.h linux-2.4.21/include/linux/cyclades.h
--- linux-2.4.20/include/linux/cyclades.h	2002-02-25 19:38:13.000000000 +0000
+++ linux-2.4.21/include/linux/cyclades.h	2002-12-18 18:58:12.000000000 +0000
@@ -514,9 +514,7 @@
     int nports;		/* Number of ports in the card */
     int bus_index;	/* address shift - 0 for ISA, 1 for PCI */
     int	intr_enabled;	/* FW Interrupt flag - 0 disabled, 1 enabled */
-    struct resource *resource;
-    unsigned long res_start;
-    unsigned long res_len;
+    struct pci_dev *pdev;
 #ifdef __KERNEL__
     spinlock_t card_lock;
 #else
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/ethtool.h linux-2.4.21/include/linux/ethtool.h
--- linux-2.4.20/include/linux/ethtool.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/include/linux/ethtool.h	2002-12-18 18:58:05.000000000 +0000
@@ -2,7 +2,7 @@
  * ethtool.h: Defines for Linux ethtool.
  *
  * Copyright (C) 1998 David S. Miller (davem@redhat.com)
- * Copyright 2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+ * Copyright 2001 Jeff Garzik <jgarzik@pobox.com>
  * Portions Copyright 2001 Sun Microsystems (thockin@sun.com)
  * Portions Copyright 2002 Intel (eli.kupermann@intel.com,
  *                                christopher.leech@intel.com,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/fs.h linux-2.4.21/include/linux/fs.h
--- linux-2.4.20/include/linux/fs.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/include/linux/fs.h	2002-12-18 18:58:05.000000000 +0000
@@ -219,6 +219,7 @@
 	BH_Async,	/* 1 if the buffer is under end_buffer_io_async I/O */
 	BH_Wait_IO,	/* 1 if we should write out this buffer */
 	BH_Launder,	/* 1 if we can throttle on this buffer */
+	BH_Attached,	/* 1 if b_inode_buffers is linked into a list */
 	BH_JBD,		/* 1 if it has an attached journal_head */
 
 	BH_PrivateStart,/* not a state bit, but the first bit available
@@ -266,7 +267,6 @@
 	unsigned long b_rsector;	/* Real buffer location on disk */
 	wait_queue_head_t b_wait;
 
-	struct inode *	     b_inode;
 	struct list_head     b_inode_buffers;	/* doubly linked list of inode dirty buffers */
 };
 
@@ -879,6 +879,9 @@
  * without the big kernel lock held in all filesystems.
  */
 struct super_operations {
+   	struct inode *(*alloc_inode)(struct super_block *sb);
+	void (*destroy_inode)(struct inode *);
+
 	void (*read_inode) (struct inode *);
   
   	/* reiserfs kludge.  reiserfs needs 64 bits of information to
@@ -894,6 +897,7 @@
 	void (*delete_inode) (struct inode *);
 	void (*put_super) (struct super_block *);
 	void (*write_super) (struct super_block *);
+	int (*sync_fs) (struct super_block *);
 	void (*write_super_lockfs) (struct super_block *);
 	void (*unlockfs) (struct super_block *);
 	int (*statfs) (struct super_block *, struct statfs *);
@@ -1170,8 +1174,18 @@
 extern void FASTCALL(__mark_dirty(struct buffer_head *bh));
 extern void FASTCALL(__mark_buffer_dirty(struct buffer_head *bh));
 extern void FASTCALL(mark_buffer_dirty(struct buffer_head *bh));
-extern void FASTCALL(buffer_insert_inode_queue(struct buffer_head *, struct inode *));
-extern void FASTCALL(buffer_insert_inode_data_queue(struct buffer_head *, struct inode *));
+
+extern void FASTCALL(buffer_insert_list(struct buffer_head *, struct list_head *));
+
+static inline void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
+{
+	buffer_insert_list(bh, &inode->i_dirty_buffers);
+}
+
+static inline void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode)
+{
+	buffer_insert_list(bh, &inode->i_dirty_data_buffers);
+}
 
 static inline int atomic_set_buffer_dirty(struct buffer_head *bh)
 {
@@ -1186,6 +1200,21 @@
 		clear_bit(BH_Async, &bh->b_state);
 }
 
+static inline void set_buffer_attached(struct buffer_head *bh)
+{
+	__set_bit(BH_Attached, &bh->b_state);
+}
+
+static inline void clear_buffer_attached(struct buffer_head *bh)
+{
+	clear_bit(BH_Attached, &bh->b_state);
+}
+
+static inline int buffer_attached(struct buffer_head *bh)
+{
+	return test_bit(BH_Attached, &bh->b_state);
+}
+
 /*
  * If an error happens during the make_request, this function
  * has to be recalled. It marks the buffer as clean and not
@@ -1240,7 +1269,7 @@
 extern int inode_has_buffers(struct inode *);
 extern int filemap_fdatasync(struct address_space *);
 extern int filemap_fdatawait(struct address_space *);
-extern void sync_supers(kdev_t);
+extern void sync_supers(kdev_t dev, int wait);
 extern int bmap(struct inode *, int);
 extern int notify_change(struct dentry *, struct iattr *);
 extern int permission(struct inode *, int);
@@ -1342,6 +1371,7 @@
 #define user_path_walk(name,nd)	 __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
 #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
 
+extern void inode_init_once(struct inode *);
 extern void iput(struct inode *);
 extern void force_delete(struct inode *);
 extern struct inode * igrab(struct inode *);
@@ -1355,18 +1385,7 @@
 }
 
 extern void clear_inode(struct inode *);
-extern struct inode * get_empty_inode(void);
-
-static inline struct inode * new_inode(struct super_block *sb)
-{
-	struct inode *inode = get_empty_inode();
-	if (inode) {
-		inode->i_sb = sb;
-		inode->i_dev = sb->s_dev;
-		inode->i_blkbits = sb->s_blocksize_bits;
-	}
-	return inode;
-}
+extern struct inode *new_inode(struct super_block *sb);
 extern void remove_suid(struct inode *inode);
 
 extern void insert_inode_hash(struct inode *);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/hdreg.h linux-2.4.21/include/linux/hdreg.h
--- linux-2.4.20/include/linux/hdreg.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/linux/hdreg.h	2002-12-18 18:58:08.000000000 +0000
@@ -34,6 +34,7 @@
 #define ECC_STAT		0x04	/* Corrected error */
 #define DRQ_STAT		0x08
 #define SEEK_STAT		0x10
+#define SRV_STAT		0x10
 #define WRERR_STAT		0x20
 #define READY_STAT		0x40
 #define BUSY_STAT		0x80
@@ -49,6 +50,13 @@
 #define BBD_ERR			0x80	/* pre-EIDE meaning:  block marked bad */
 #define ICRC_ERR		0x80	/* new meaning:  CRC error during transfer */
 
+/* Bits of HD_NSECTOR */
+#define CD			0x01
+#define IO			0x02
+#define REL			0x04
+#define TAG_MASK		0xf8
+
+
 /*
  * Command Header sizes for IOCTL commands
  *	HDIO_DRIVE_CMD, HDIO_DRIVE_TASK, and HDIO_DRIVE_TASKFILE
@@ -61,6 +69,8 @@
 typedef unsigned char task_ioreg_t;
 #endif
 
+typedef unsigned long sata_ioreg_t;
+
 #define HDIO_DRIVE_CMD_HDR_SIZE		4*sizeof(task_ioreg_t)
 #define HDIO_DRIVE_TASK_HDR_SIZE	8*sizeof(task_ioreg_t)
 #define HDIO_DRIVE_HOB_HDR_SIZE		8*sizeof(task_ioreg_t)
@@ -131,8 +141,8 @@
  */
 #define IDE_TASKFILE_STD_OUT_FLAGS	0xFE
 #define IDE_TASKFILE_STD_IN_FLAGS	0xFE
-#define IDE_HOB_STD_OUT_FLAGS		0xC0
-#define IDE_HOB_STD_IN_FLAGS		0xC0
+#define IDE_HOB_STD_OUT_FLAGS		0x3C
+#define IDE_HOB_STD_IN_FLAGS		0x3C
 
 typedef struct ide_task_request_s {
 	task_ioreg_t	io_ports[8];
@@ -177,37 +187,82 @@
 
 /* ATA/ATAPI Commands pre T13 Spec */
 #define WIN_NOP				0x00
+/*
+ *	0x01->0x02 Reserved
+ */
 #define CFA_REQ_EXT_ERROR_CODE		0x03 /* CFA Request Extended Error Code */
+/*
+ *	0x04->0x07 Reserved
+ */
 #define WIN_SRST			0x08 /* ATAPI soft reset command */
 #define WIN_DEVICE_RESET		0x08
-#define WIN_RESTORE			0x10
+/*
+ *	0x09->0x0F Reserved
+ */
+#define WIN_RECAL			0x10
+#define WIN_RESTORE			WIN_RECAL
+/*
+ *	0x10->0x1F Reserved
+ */
 #define WIN_READ			0x20 /* 28-Bit */
+#define WIN_READ_ONCE			0x21 /* 28-Bit without retries */
+#define WIN_READ_LONG			0x22 /* 28-Bit */
+#define WIN_READ_LONG_ONCE		0x23 /* 28-Bit without retries */
 #define WIN_READ_EXT			0x24 /* 48-Bit */
 #define WIN_READDMA_EXT			0x25 /* 48-Bit */
 #define WIN_READDMA_QUEUED_EXT		0x26 /* 48-Bit */
 #define WIN_READ_NATIVE_MAX_EXT		0x27 /* 48-Bit */
+/*
+ *	0x28
+ */
 #define WIN_MULTREAD_EXT		0x29 /* 48-Bit */
+/*
+ *	0x2A->0x2F Reserved
+ */
 #define WIN_WRITE			0x30 /* 28-Bit */
+#define WIN_WRITE_ONCE			0x31 /* 28-Bit without retries */
+#define WIN_WRITE_LONG			0x32 /* 28-Bit */
+#define WIN_WRITE_LONG_ONCE		0x33 /* 28-Bit without retries */
 #define WIN_WRITE_EXT			0x34 /* 48-Bit */
 #define WIN_WRITEDMA_EXT		0x35 /* 48-Bit */
 #define WIN_WRITEDMA_QUEUED_EXT		0x36 /* 48-Bit */
 #define WIN_SET_MAX_EXT			0x37 /* 48-Bit */
 #define CFA_WRITE_SECT_WO_ERASE		0x38 /* CFA Write Sectors without erase */
 #define WIN_MULTWRITE_EXT		0x39 /* 48-Bit */
+/*
+ *	0x3A->0x3B Reserved
+ */
 #define WIN_WRITE_VERIFY		0x3C /* 28-Bit */
+/*
+ *	0x3D->0x3F Reserved
+ */
 #define WIN_VERIFY			0x40 /* 28-Bit - Read Verify Sectors */
+#define WIN_VERIFY_ONCE			0x41 /* 28-Bit - without retries */
 #define WIN_VERIFY_EXT			0x42 /* 48-Bit */
+/*
+ *	0x43->0x4F Reserved
+ */
 #define WIN_FORMAT			0x50
+/*
+ *	0x51->0x5F Reserved
+ */
 #define WIN_INIT			0x60
-#define WIN_SEEK			0x70
+/*
+ *	0x61->0x5F Reserved
+ */
+#define WIN_SEEK			0x70 /* 0x70-0x7F Reserved */
 #define CFA_TRANSLATE_SECTOR		0x87 /* CFA Translate Sector */
 #define WIN_DIAGNOSE			0x90
 #define WIN_SPECIFY			0x91 /* set drive geometry translation */
 #define WIN_DOWNLOAD_MICROCODE		0x92
 #define WIN_STANDBYNOW2			0x94
+#define WIN_STANDBY2			0x96
 #define WIN_SETIDLE2			0x97
 #define WIN_CHECKPOWERMODE2		0x98
 #define WIN_SLEEPNOW2			0x99
+/*
+ *	0x9A VENDOR
+ */
 #define WIN_PACKETCMD			0xA0 /* Send a packet command. */
 #define WIN_PIDENTIFY			0xA1 /* identify ATAPI device	*/
 #define WIN_QUEUED_SERVICE		0xA2
@@ -218,10 +273,15 @@
 #define WIN_SETMULT			0xC6 /* enable/disable multiple mode */
 #define WIN_READDMA_QUEUED		0xC7 /* read sectors using Queued DMA transfers */
 #define WIN_READDMA			0xC8 /* read sectors using DMA transfers */
+#define WIN_READDMA_ONCE		0xC9 /* 28-Bit - without retries */
 #define WIN_WRITEDMA			0xCA /* write sectors using DMA transfers */
+#define WIN_WRITEDMA_ONCE		0xCB /* 28-Bit - without retries */
 #define WIN_WRITEDMA_QUEUED		0xCC /* write sectors using Queued DMA transfers */
 #define CFA_WRITE_MULTI_WO_ERASE	0xCD /* CFA Write multiple without erase */
 #define WIN_GETMEDIASTATUS		0xDA	
+#define WIN_ACKMEDIACHANGE		0xDB /* ATA-1, ATA-2 vendor */
+#define WIN_POSTBOOT			0xDC
+#define WIN_PREBOOT			0xDD
 #define WIN_DOORLOCK			0xDE /* lock door on removable drives */
 #define WIN_DOORUNLOCK			0xDF /* unlock door on removable drives */
 #define WIN_STANDBYNOW1			0xE0
@@ -233,6 +293,8 @@
 #define WIN_SLEEPNOW1			0xE6
 #define WIN_FLUSH_CACHE			0xE7
 #define WIN_WRITE_BUFFER		0xE8 /* force write only 1 sector */
+#define WIN_WRITE_SAME			0xE9 /* read ata-2 to use */
+	/* SET_FEATURES 0x22 or 0xDD */
 #define WIN_FLUSH_CACHE_EXT		0xEA /* 48-Bit */
 #define WIN_IDENTIFY			0xEC /* ask drive to identify itself	*/
 #define WIN_MEDIAEJECT			0xED
@@ -270,7 +332,7 @@
 #define SMART_HCYL_PASS			0xC2
 		
 /* WIN_SETFEATURES sub-commands */
-
+#define SETFEATURES_EN_8BIT	0x01	/* Enable 8-Bit Transfers */
 #define SETFEATURES_EN_WCACHE	0x02	/* Enable write cache */
 #define SETFEATURES_XFER	0x03	/* Set transfer mode */
 #	define XFER_UDMA_7	0x47	/* 0100|0111 */
@@ -295,22 +357,33 @@
 #	define XFER_PIO_SLOW	0x00	/* 0000|0000 */
 #define SETFEATURES_DIS_DEFECT	0x04	/* Disable Defect Management */
 #define SETFEATURES_EN_APM	0x05	/* Enable advanced power management */
+#define SETFEATURES_EN_SAME_R	0x22	/* for a region ATA-1 */
 #define SETFEATURES_DIS_MSN	0x31	/* Disable Media Status Notification */
+#define SETFEATURES_DIS_RETRY	0x33	/* Disable Retry */
 #define SETFEATURES_EN_AAM	0x42	/* Enable Automatic Acoustic Management */
+#define SETFEATURES_RW_LONG	0x44	/* Set Lenght of VS bytes */
+#define SETFEATURES_SET_CACHE	0x54	/* Set Cache segments to SC Reg. Val */
 #define SETFEATURES_DIS_RLA	0x55	/* Disable read look-ahead feature */
 #define SETFEATURES_EN_RI	0x5D	/* Enable release interrupt */
 #define SETFEATURES_EN_SI	0x5E	/* Enable SERVICE interrupt */
 #define SETFEATURES_DIS_RPOD	0x66	/* Disable reverting to power on defaults */
+#define SETFEATURES_DIS_ECC	0x77	/* Disable ECC byte count */
+#define SETFEATURES_DIS_8BIT	0x81	/* Disable 8-Bit Transfers */
 #define SETFEATURES_DIS_WCACHE	0x82	/* Disable write cache */
 #define SETFEATURES_EN_DEFECT	0x84	/* Enable Defect Management */
 #define SETFEATURES_DIS_APM	0x85	/* Disable advanced power management */
+#define SETFEATURES_EN_ECC	0x88	/* Enable ECC byte count */
 #define SETFEATURES_EN_MSN	0x95	/* Enable Media Status Notification */
+#define SETFEATURES_EN_RETRY	0x99	/* Enable Retry */
 #define SETFEATURES_EN_RLA	0xAA	/* Enable read look-ahead feature */
 #define SETFEATURES_PREFETCH	0xAB	/* Sets drive prefetch value */
+#define SETFEATURES_EN_REST	0xAC	/* ATA-1 */
+#define SETFEATURES_4B_RW_LONG	0xBB	/* Set Lenght of 4 bytes */
 #define SETFEATURES_DIS_AAM	0xC2	/* Disable Automatic Acoustic Management */
 #define SETFEATURES_EN_RPOD	0xCC	/* Enable reverting to power on defaults */
-#define SETFEATURES_DIS_RI	0xDD	/* Disable release interrupt */
-#define SETFEATURES_DIS_SI	0xDE	/* Disable SERVICE interrupt */
+#define SETFEATURES_DIS_RI	0xDD	/* Disable release interrupt ATAPI */
+#define SETFEATURES_EN_SAME_M	0xDD	/* for a entire device ATA-1 */
+#define SETFEATURES_DIS_SI	0xDE	/* Disable SERVICE interrupt ATAPI */
 
 /* WIN_SECURITY sub-commands */
 
@@ -341,6 +414,9 @@
 #define HDIO_GET_UNMASKINTR	0x0302	/* get current unmask setting */
 #define HDIO_GET_MULTCOUNT	0x0304	/* get current IDE blockmode setting */
 #define HDIO_GET_QDMA		0x0305	/* get use-qdma flag */
+
+#define HDIO_SET_XFER		0x0306	/* set transfer rate via proc */
+
 #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 */
@@ -389,6 +465,9 @@
 #define HDIO_GETGEO_BIG		0x0330	/* */
 #define HDIO_GETGEO_BIG_RAW	0x0331	/* */
 
+#define HDIO_SET_IDE_SCSI	0x0338
+#define HDIO_SET_SCSI_IDE	0x0339
+
 #define __NEW_HD_DRIVE_ID
 /* structure returned by HDIO_GET_IDENTITY,
  * as per ANSI NCITS ATA6 rev.1b spec
@@ -501,7 +580,10 @@
 					 * cmd set-feature supported extensions
 					 * 15:	Shall be ZERO
 					 * 14:	Shall be ONE
-					 * 13:3	reserved
+					 * 13:6	reserved
+					 *  5:	General Purpose Logging
+					 *  4:	Streaming Feature Set
+					 *  3:	Media Card Pass Through
 					 *  2:	Media Serial Number Valid
 					 *  1:	SMART selt-test supported
 					 *  0:	SMART error logging
@@ -548,19 +630,22 @@
 					 * command set-feature default
 					 * 15:	Shall be ZERO
 					 * 14:	Shall be ONE
-					 * 13:3	reserved
+					 * 13:6	reserved
+					 *  5:	General Purpose Logging enabled
+					 *  4:	Valid CONFIGURE STREAM executed
+					 *  3:	Media Card Pass Through enabled
 					 *  2:	Media Serial Number Valid
 					 *  1:	SMART selt-test supported
 					 *  0:	SMART error logging
 					 */
 	unsigned short  dma_ultra;	/* (word 88) */
-	unsigned short	word89;		/* reserved (word 89) */
-	unsigned short	word90;		/* reserved (word 90) */
+	unsigned short	trseuc;		/* time required for security erase */
+	unsigned short	trsEuc;		/* time required for enhanced erase */
 	unsigned short	CurAPMvalues;	/* current APM values */
-	unsigned short	word92;		/* reserved (word 92) */
+	unsigned short	mprc;		/* master password revision code */
 	unsigned short	hw_config;	/* hardware config (word 93)
-					 * 15:
-					 * 14:
+					 * 15:	Shall be ZERO
+					 * 14:	Shall be ONE
 					 * 13:
 					 * 12:
 					 * 11:
@@ -574,18 +659,17 @@
 					 *  3:
 					 *  2:
 					 *  1:
-					 *  0:
+					 *  0:	Shall be ONE
 					 */
 	unsigned short	acoustic;	/* (word 94)
 					 * 15:8	Vendor's recommended value
 					 *  7:0	current value
 					 */
-	unsigned short	words95_99[5];	/* reserved words 95-99 */
-#if 0
-	unsigned short	words100_103[4]	;/* reserved words 100-103 */
-#else
+	unsigned short	msrqs;		/* min stream request size */
+	unsigned short	sxfert;		/* stream transfer time */
+	unsigned short	sal;		/* stream access latency */
+	unsigned int	spg;		/* stream performance granularity */
 	unsigned long long lba_capacity_2;/* 48-bit total number of sectors */
-#endif
 	unsigned short	words104_125[22];/* reserved words 104-125 */
 	unsigned short	last_lun;	/* (word 126) */
 	unsigned short	word127;	/* (word 127) Feature Set
@@ -626,9 +710,9 @@
 					 * 12
 					 * 11:0
 					 */
-	unsigned short	words161_175[14];/* Reserved for CFA */
-	unsigned short	words176_205[31];/* Current Media Serial Number */
-	unsigned short	words206_254[48];/* reserved words 206-254 */
+	unsigned short	words161_175[15];/* Reserved for CFA */
+	unsigned short	words176_205[30];/* Current Media Serial Number */
+	unsigned short	words206_254[49];/* reserved words 206-254 */
 	unsigned short	integrity_word;	/* (word 255)
 					 * 15:8 Checksum
 					 *  7:0 Signature
@@ -654,7 +738,7 @@
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 int ide_register(int io_port, int ctl_port, int irq);
-void ide_unregister(unsigned int);
+int ide_unregister(unsigned int);
 #endif /* CONFIG_BLK_DEV_IDE || CONFIG_BLK_DEV_IDE_MODULE */
 
 #endif  /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/ide.h linux-2.4.21/include/linux/ide.h
--- linux-2.4.20/include/linux/ide.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/include/linux/ide.h	2002-12-18 18:58:04.000000000 +0000
@@ -3,7 +3,7 @@
 /*
  *  linux/include/linux/ide.h
  *
- *  Copyright (C) 1994-1998  Linus Torvalds & authors
+ *  Copyright (C) 1994-2002  Linus Torvalds & authors
  */
 
 #include <linux/config.h>
@@ -14,7 +14,37 @@
 #include <linux/blkdev.h>
 #include <linux/proc_fs.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/highmem.h>
+#include <linux/pci.h>
+#include <asm/byteorder.h>
+#include <asm/system.h>
 #include <asm/hdreg.h>
+#include <asm/io.h>
+
+#define CLASSIC_BUILTINS_METHOD				1
+//#undef CLASSIC_BUILTINS_METHOD
+#define HWIF_PROBE_CLASSIC_METHOD			1
+//#undef HWIF_PROBE_CLASSIC_METHOD
+
+#ifdef CLASSIC_BUILTINS_METHOD
+#  undef FAKE_CLASSIC_ATTACH_METHOD
+#  undef DIRECT_HWIF_PROBE_ATTACH_METHOD
+#else /* ! CLASSIC_BUILTINS_METHOD */
+#  ifdef HWIF_PROBE_CLASSIC_METHOD
+#    undef FAKE_CLASSIC_ATTACH_METHOD
+#    undef DIRECT_HWIF_PROBE_ATTACH_METHOD
+#  else /* ! HWIF_PROBE_CLASSIC_METHOD */
+//#    define FAKE_CLASSIC_ATTACH_METHOD			1
+#    undef FAKE_CLASSIC_ATTACH_METHOD
+#    ifdef FAKE_CLASSIC_ATTACH_METHOD
+#      undef DIRECT_HWIF_PROBE_ATTACH_METHOD
+#    else /* ! FAKE_CLASSIC_ATTACH_METHOD */
+#      define DIRECT_HWIF_PROBE_ATTACH_METHOD		1
+#    endif /* FAKE_CLASSIC_ATTACH_METHOD */
+#  endif /* HWIF_PROBE_CLASSIC_METHOD */
+#endif /* CLASSIC_BUILTINS_METHOD */
 
 /*
  * This is the multiple IDE interface driver, as evolved from hd.c.
@@ -88,8 +118,17 @@
 #define ERROR_RECAL	1	/* Recalibrate every 2nd retry */
 
 /*
+ * Tune flags
+ */
+#define IDE_TUNE_BIOS		3
+#define IDE_TUNE_NOAUTO		2
+#define IDE_TUNE_AUTO		1
+#define IDE_TUNE_DEFAULT	0
+
+/*
  * state flags
  */
+
 #define DMA_PIO_RETRY	1	/* retrying in PIO */
 
 /*
@@ -160,9 +199,6 @@
 #define IDE_BCOUNTL_REG		IDE_LCYL_REG
 #define IDE_BCOUNTH_REG		IDE_HCYL_REG
 
-#define GET_ERR()		IN_BYTE(IDE_ERROR_REG)
-#define GET_STAT()		IN_BYTE(IDE_STATUS_REG)
-#define GET_ALTSTAT()		IN_BYTE(IDE_CONTROL_REG)
 #define OK_STAT(stat,good,bad)	(((stat)&((good)|(bad)))==(good))
 #define BAD_R_STAT		(BUSY_STAT   | ERR_STAT)
 #define BAD_W_STAT		(BAD_R_STAT  | WRERR_STAT)
@@ -170,6 +206,43 @@
 #define DRIVE_READY		(READY_STAT  | SEEK_STAT)
 #define DATA_READY		(DRQ_STAT)
 
+#define BAD_CRC			(ABRT_ERR    | ICRC_ERR)
+
+#define SATA_NR_PORTS		(3)	/* 16 possible ?? */
+
+#define SATA_STATUS_OFFSET	(0)
+#define SATA_STATUS_REG		(HWIF(drive)->sata_scr[SATA_STATUS_OFFSET])
+#define SATA_ERROR_OFFSET	(1)
+#define SATA_ERROR_REG		(HWIF(drive)->sata_scr[SATA_ERROR_OFFSET])
+#define SATA_CONTROL_OFFSET	(2)
+#define SATA_CONTROL_REG	(HWIF(drive)->sata_scr[SATA_CONTROL_OFFSET])
+
+#define SATA_MISC_OFFSET	(0)
+#define SATA_MISC_REG		(HWIF(drive)->sata_misc[SATA_MISC_OFFSET])
+#define SATA_PHY_OFFSET		(1)
+#define SATA_PHY_REG		(HWIF(drive)->sata_misc[SATA_PHY_OFFSET])
+#define SATA_IEN_OFFSET		(2)
+#define SATA_IEN_REG		(HWIF(drive)->sata_misc[SATA_IEN_OFFSET])
+
+/*
+ * 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
+ * two or more sectors, we could get by with a limit of 128 entries here for
+ * the usual worst case.  Most requests seem to include some contiguous blocks,
+ * further reducing the number of table entries required.
+ *
+ * The driver reverts to PIO mode for individual requests that exceed
+ * this limit (possible with 512 byte blocksizes, eg. MSDOS f/s), so handling
+ * 100% of all crazy scenarios here is not necessary.
+ *
+ * As it turns out though, we must allocate a full 4KB page for this,
+ * so the two PRD tables (ide0 & ide1) will each get half of that,
+ * allowing each to have about 256 entries (8 bytes each) from this.
+ */
+#define PRD_BYTES       8
+#define PRD_ENTRIES     (PAGE_SIZE / (2 * PRD_BYTES))
+
 /*
  * Some more useful definitions
  */
@@ -178,21 +251,12 @@
 #define PARTN_BITS	6	/* number of minor dev bits for partitions */
 #define PARTN_MASK	((1<<PARTN_BITS)-1)	/* a useful bit mask */
 #define MAX_DRIVES	2	/* per interface; 2 assumed by lots of code */
-#define CASCADE_DRIVES	8	/* per interface; 8|2 assumed by lots of code */
 #define SECTOR_SIZE	512
 #define SECTOR_WORDS	(SECTOR_SIZE / 4)	/* number of 32bit words per sector */
 #define IDE_LARGE_SEEK(b1,b2,t)	(((b1) > (b2) + (t)) || ((b2) > (b1) + (t)))
 #define IDE_MIN(a,b)	((a)<(b) ? (a):(b))
 #define IDE_MAX(a,b)	((a)>(b) ? (a):(b))
 
-#ifndef SPLIT_WORD
-#  define SPLIT_WORD(W,HB,LB) ((HB)=(W>>8), (LB)=(W-((W>>8)<<8)))
-#endif
-#ifndef MAKE_WORD
-#  define MAKE_WORD(W,HB,LB) ((W)=((HB<<8)+LB))
-#endif
-
-
 /*
  * Timeouts for various operations:
  */
@@ -207,39 +271,6 @@
 #define WAIT_CMD	(10*HZ)	/* 10sec  - maximum wait for an IRQ to happen */
 #define WAIT_MIN_SLEEP	(2*HZ/100)	/* 20msec - minimum sleep time */
 
-#define SELECT_DRIVE(hwif,drive)				\
-{								\
-	if (hwif->selectproc)					\
-		hwif->selectproc(drive);			\
-	OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \
-}
-
-#define SELECT_INTERRUPT(hwif,drive)				\
-{								\
-	if (hwif->intrproc)					\
-		hwif->intrproc(drive);				\
-	else							\
-		OUT_BYTE((drive)->ctl|2, hwif->io_ports[IDE_CONTROL_OFFSET]);	\
-}
-
-#define SELECT_MASK(hwif,drive,mask)				\
-{								\
-	if (hwif->maskproc)					\
-		hwif->maskproc(drive,mask);			\
-}
-
-#define SELECT_READ_WRITE(hwif,drive,func)			\
-{								\
-	if (hwif->rwproc)					\
-		hwif->rwproc(drive,func);			\
-}
-
-#define QUIRK_LIST(hwif,drive)					\
-{								\
-	if (hwif->quirkproc)					\
-		(drive)->quirk_list = hwif->quirkproc(drive);	\
-}
-
 #define HOST(hwif,chipset)					\
 {								\
 	return ((hwif)->chipset == chipset) ? 1 : 0;		\
@@ -267,9 +298,24 @@
 		ide_qd65xx,	ide_umc8672,	ide_ht6560b,
 		ide_pdc4030,	ide_rz1000,	ide_trm290,
 		ide_cmd646,	ide_cy82c693,	ide_4drives,
-		ide_pmac,	ide_etrax100
+		ide_pmac,	ide_etrax100,	ide_acorn
 } hwif_chipset_t;
 
+typedef struct ide_io_ops_s {
+	/* insert io operations here! */
+	void (*OUTB)(u8 addr, unsigned long port);
+	void (*OUTW)(u16 addr, unsigned long port);
+	void (*OUTL)(u32 addr, unsigned long port);
+	void (*OUTSW)(unsigned long port, void *addr, u32 count);
+	void (*OUTSL)(unsigned long port, void *addr, u32 count);
+
+	u8  (*INB)(unsigned long port);
+	u16 (*INW)(unsigned long port);
+	u32 (*INL)(unsigned long port);
+	void (*INSW)(unsigned long port, void *addr, u32 count);
+	void (*INSL)(unsigned long port, void *addr, u32 count);
+} ide_io_ops_t;
+
 /*
  * Structure to hold all information about the location of this port
  */
@@ -280,6 +326,11 @@
 	ide_ack_intr_t	*ack_intr;		/* acknowledge interrupt */
 	void		*priv;			/* interface specific data */
 	hwif_chipset_t  chipset;
+#if 0
+	ide_io_ops_t	*iops;			/* */
+#endif
+	sata_ioreg_t	sata_scr[SATA_NR_PORTS];
+	sata_ioreg_t	sata_misc[SATA_NR_PORTS];
 } hw_regs_t;
 
 /*
@@ -296,34 +347,26 @@
 			ide_ioreg_t ctrl,
 			ide_ioreg_t intr,
 			ide_ack_intr_t *ack_intr,
+#if 0
+			ide_io_ops_t *iops,
+#endif
 			int irq);
 
 #include <asm/ide.h>
 
-/*
- * If the arch-dependant ide.h did not declare/define any OUT_BYTE
- * or IN_BYTE functions, we make some defaults here.
- */
-
-#ifndef HAVE_ARCH_OUT_BYTE
-#ifdef REALLY_FAST_IO
-#define OUT_BYTE(b,p)          outb((b),(p))
-#define OUT_WORD(w,p)          outw((w),(p))
+/* Currently only m68k, apus and m8xx need it */
+#ifdef IDE_ARCH_ACK_INTR
+extern int ide_irq_lock;
+# define ide_ack_intr(hwif) (hwif->hw.ack_intr ? hwif->hw.ack_intr(hwif) : 1)
 #else
-#define OUT_BYTE(b,p)          outb_p((b),(p))
-#define OUT_WORD(w,p)          outw_p((w),(p))
-#endif
+# define ide_ack_intr(hwif) (1)
 #endif
 
-#ifndef HAVE_ARCH_IN_BYTE
-#ifdef REALLY_FAST_IO
-#define IN_BYTE(p)             (byte)inb(p)
-#define IN_WORD(p)             (short)inw(p)
-#else
-#define IN_BYTE(p)             (byte)inb_p(p)
-#define IN_WORD(p)             (short)inw_p(p)
-#endif
-#endif
+/* Currently only Atari needs it */
+#ifndef IDE_ARCH_LOCK
+# define ide_release_lock(lock)			do {} while (0)
+# define ide_get_lock(lock, hdlr, data)		do {} while (0)
+#endif /* IDE_ARCH_LOCK */
 
 /*
  * Now for the data we need to maintain per-drive:  ide_drive_t
@@ -336,235 +379,638 @@
 #define ide_tape	0x1
 #define ide_floppy	0x0
 
+/*
+ * Special Driver Flags
+ *
+ * set_geometry	: respecify drive geometry
+ * recalibrate	: seek to cyl 0
+ * set_multmode	: set multmode count
+ * set_tune	: tune interface for drive
+ * serviced	: service command
+ * reserved	: unused
+ */
 typedef union {
-	unsigned all			: 8;	/* all of the bits together */
+	unsigned all			: 8;
 	struct {
-		unsigned set_geometry	: 1;	/* respecify drive geometry */
-		unsigned recalibrate	: 1;	/* seek to cyl 0      */
-		unsigned set_multmode	: 1;	/* set multmode count */
-		unsigned set_tune	: 1;	/* tune interface for drive */
-		unsigned reserved	: 4;	/* unused */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned set_geometry	: 1;
+		unsigned recalibrate	: 1;
+		unsigned set_multmode	: 1;
+		unsigned set_tune	: 1;
+		unsigned serviced	: 1;
+		unsigned reserved	: 3;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned reserved	: 3;
+		unsigned serviced	: 1;
+		unsigned set_tune	: 1;
+		unsigned set_multmode	: 1;
+		unsigned recalibrate	: 1;
+		unsigned set_geometry	: 1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
 	} b;
 } special_t;
 
+/*
+ * ATA DATA Register Special.
+ * ATA NSECTOR Count Register().
+ * ATAPI Byte Count Register.
+ * Channel index ordering pairs.
+ */
+typedef union {
+	unsigned all			:16;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned low		:8;	/* LSB */
+		unsigned high		:8;	/* MSB */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned high		:8;	/* MSB */
+		unsigned low		:8;	/* LSB */
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} ata_nsector_t, ata_data_t, atapi_bcount_t, ata_index_t;
+
+/*
+ * ATA-IDE Error Register
+ *
+ * mark		: Bad address mark
+ * tzero	: Couldn't find track 0
+ * abrt		: Aborted Command
+ * mcr		: Media Change Request
+ * id		: ID field not found
+ * mce		: Media Change Event
+ * ecc		: Uncorrectable ECC error
+ * bdd		: dual meaing
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned mark		:1;
+		unsigned tzero		:1;
+		unsigned abrt		:1;
+		unsigned mcr		:1;
+		unsigned id		:1;
+		unsigned mce		:1;
+		unsigned ecc		:1;
+		unsigned bdd		:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned bdd		:1;
+		unsigned ecc		:1;
+		unsigned mce		:1;
+		unsigned id		:1;
+		unsigned mcr		:1;
+		unsigned abrt		:1;
+		unsigned tzero		:1;
+		unsigned mark		:1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} ata_error_t;
+
+/*
+ * ATA-IDE Select Register, aka Device-Head
+ *
+ * head		: always zeros here
+ * unit		: drive select number: 0/1
+ * bit5		: always 1
+ * lba		: using LBA instead of CHS
+ * bit7		: always 1
+ */
+typedef union {
+	unsigned all			: 8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned head		: 4;
+		unsigned unit		: 1;
+		unsigned bit5		: 1;
+		unsigned lba		: 1;
+		unsigned bit7		: 1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned bit7		: 1;
+		unsigned lba		: 1;
+		unsigned bit5		: 1;
+		unsigned unit		: 1;
+		unsigned head		: 4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} select_t, ata_select_t;
+
+/*
+ * The ATA-IDE Status Register.
+ * The ATAPI Status Register.
+ *
+ * check	: Error occurred
+ * idx		: Index Error
+ * corr		: Correctable error occurred
+ * drq		: Data is request by the device
+ * dsc		: Disk Seek Complete			: ata
+ *		: Media access command finished		: atapi
+ * df		: Device Fault				: ata
+ *		: Reserved				: atapi
+ * drdy		: Ready, Command Mode Capable		: ata
+ *		: Ignored for ATAPI commands		: atapi
+ * bsy		: Disk is Busy
+ *		: The device has access to the command block
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned check		:1;
+		unsigned idx		:1;
+		unsigned corr		:1;
+		unsigned drq		:1;
+		unsigned dsc		:1;
+		unsigned df		:1;
+		unsigned drdy		:1;
+		unsigned bsy		:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned bsy		:1;
+		unsigned drdy		:1;
+		unsigned df		:1;
+		unsigned dsc		:1;
+		unsigned drq		:1;
+		unsigned corr           :1;
+		unsigned idx		:1;
+		unsigned check		:1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} ata_status_t, atapi_status_t;
+
+/*
+ * ATA-IDE Control Register
+ *
+ * bit0		: Should be set to zero
+ * nIEN		: device INTRQ to host
+ * SRST		: host soft reset bit
+ * bit3		: ATA-2 thingy, Should be set to 1
+ * reserved456	: Reserved
+ * HOB		: 48-bit address ordering, High Ordered Bit
+ */
+typedef union {
+	unsigned all			: 8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;
+		unsigned SRST		: 1;
+		unsigned bit3		: 1;
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned HOB		: 1;
+		unsigned reserved456	: 3;
+		unsigned bit3		: 1;
+		unsigned SRST		: 1;
+		unsigned nIEN		: 1;
+		unsigned bit0		: 1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} ata_control_t;
+
+/*
+ * ATAPI Feature Register
+ *
+ * dma		: Using DMA or PIO
+ * reserved321	: Reserved
+ * reserved654	: Reserved (Tag Type)
+ * reserved7	: Reserved
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned dma		:1;
+		unsigned reserved321	:3;
+		unsigned reserved654	:3;
+		unsigned reserved7	:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned reserved7	:1;
+		unsigned reserved654	:3;
+		unsigned reserved321	:3;
+		unsigned dma		:1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} atapi_feature_t;
+
+/*
+ * ATAPI Interrupt Reason Register.
+ *
+ * cod		: Information transferred is command (1) or data (0)
+ * io		: The device requests us to read (1) or write (0)
+ * reserved	: Reserved
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned cod		:1;
+		unsigned io		:1;
+		unsigned reserved	:6;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned reserved	:6;
+		unsigned io		:1;
+		unsigned cod		:1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} atapi_ireason_t;
+
+/*
+ * The ATAPI error register.
+ *
+ * ili		: Illegal Length Indication
+ * eom		: End Of Media Detected
+ * abrt		: Aborted command - As defined by ATA
+ * mcr		: Media Change Requested - As defined by ATA
+ * sense_key	: Sense key of the last failed packet command
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned ili		:1;
+		unsigned eom		:1;
+		unsigned abrt		:1;
+		unsigned mcr		:1;
+		unsigned sense_key	:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned sense_key	:4;
+		unsigned mcr		:1;
+		unsigned abrt		:1;
+		unsigned eom		:1;
+		unsigned ili		:1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} atapi_error_t;
+
+/*
+ * ATAPI floppy Drive Select Register
+ *
+ * sam_lun	: Logical unit number
+ * reserved3	: Reserved
+ * drv		: The responding drive will be drive 0 (0) or drive 1 (1)
+ * one5		: Should be set to 1
+ * reserved6	: Reserved
+ * one7		: Should be set to 1
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned sam_lun	:3;
+		unsigned reserved3	:1;
+		unsigned drv		:1;
+		unsigned one5		:1;
+		unsigned reserved6	:1;
+		unsigned one7		:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned one7		:1;
+		unsigned reserved6	:1;
+		unsigned one5		:1;
+		unsigned drv		:1;
+		unsigned reserved3	:1;
+		unsigned sam_lun	:3;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} atapi_select_t;
+
+struct ide_driver_s;
+struct ide_settings_s;
+
 typedef struct ide_drive_s {
-	request_queue_t		 queue;	/* request queue */
+	char		name[4];	/* drive name, such as "hda" */
+        char            driver_req[10];	/* requests specific driver */
+
+	request_queue_t		queue;	/* request queue */
+
+	wait_queue_head_t wqueue;	/* used to wait for drive in open() */
+	struct request		*rq;	/* current request */
 	struct ide_drive_s 	*next;	/* circular list of hwgroup drives */
+	struct ide_driver_s	*driver;/* (ide_driver_t *) */
+	void		*driver_data;	/* extra driver data */
+	struct hd_driveid	*id;	/* drive model identification info */
+	struct hd_struct	*part;	/* drive partition table */
+	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
+	struct ide_settings_s *settings;/* /proc/ide/ drive settings */
+	devfs_handle_t		de;	/* directory for device */
+
+	struct hwif_s		*hwif;	/* actually (ide_hwif_t *) */
+
 	unsigned long sleep;		/* sleep until this time */
 	unsigned long service_start;	/* time we started last request */
 	unsigned long service_time;	/* service time of last request */
 	unsigned long timeout;		/* max time to wait for irq */
+
 	special_t	special;	/* special action flags */
-	byte     keep_settings;		/* restore settings after drive reset */
-	byte     using_dma;		/* disk is using dma for read/write */
-	byte	 retry_pio;		/* retrying dma capable host in pio */
-	byte	 state;			/* retry state */
-	byte     waiting_for_dma;	/* dma currently in progress */
-	byte     unmask;		/* flag: okay to unmask other irqs */
-	byte     slow;			/* flag: slow data port */
-	byte     bswap;			/* flag: byte swap data */
-	byte     dsc_overlap;		/* flag: DSC overlap */
-	byte     nice1;			/* flag: give potential excess bandwidth */
+	select_t	select;		/* basic drive/head select reg value */
+
+	u8	keep_settings;		/* restore settings after drive reset */
+	u8	autodma;		/* device can safely use dma on host */
+	u8	using_dma;		/* disk is using dma for read/write */
+	u8	using_tcq;		/* disk is using queueing */
+	u8	retry_pio;		/* retrying dma capable host in pio */
+	u8	state;			/* retry state */
+	u8	waiting_for_dma;	/* dma currently in progress */
+	u8	unmask;			/* okay to unmask other irqs */
+	u8	slow;			/* slow data port */
+	u8	bswap;			/* byte swap data */
+	u8	dsc_overlap;		/* DSC overlap */
+	u8	nice1;			/* give potential excess bandwidth */
+
 	unsigned present	: 1;	/* drive is physically present */
 	unsigned noprobe 	: 1;	/* from:  hdx=noprobe */
 	unsigned busy		: 1;	/* currently doing revalidate_disk() */
 	unsigned removable	: 1;	/* 1 if need to do check_media_change */
+	unsigned is_flash	: 1;	/* 1 if probed as flash */
 	unsigned forced_geom	: 1;	/* 1 if hdx=c,h,s was given at boot */
 	unsigned no_unmask	: 1;	/* disallow setting unmask bit */
 	unsigned no_io_32bit	: 1;	/* disallow enabling 32bit I/O */
-	unsigned nobios		: 1;	/* flag: do not probe bios for drive */
+	unsigned nobios		: 1;	/* do not probe bios for drive */
 	unsigned revalidate	: 1;	/* request revalidation */
-	unsigned atapi_overlap	: 1;	/* flag: ATAPI overlap (not supported) */
-	unsigned nice0		: 1;	/* flag: give obvious excess bandwidth */
-	unsigned nice2		: 1;	/* flag: give a share in our own bandwidth */
-	unsigned doorlocking	: 1;	/* flag: for removable only: door lock/unlock works */
+	unsigned atapi_overlap	: 1;	/* ATAPI overlap (not supported) */
+	unsigned nice0		: 1;	/* give obvious excess bandwidth */
+	unsigned nice2		: 1;	/* give a share in our own bandwidth */
+	unsigned doorlocking	: 1;	/* for removable only: door lock/unlock works */
 	unsigned autotune	: 2;	/* 1=autotune, 2=noautotune, 0=default */
 	unsigned remap_0_to_1	: 2;	/* 0=remap if ezdrive, 1=remap, 2=noremap */
 	unsigned ata_flash	: 1;	/* 1=present, 0=default */
-	unsigned	addressing;	/* : 2; 0=28-bit, 1=48-bit, 2=64-bit */
-	byte		scsi;		/* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */
-	byte		media;		/* disk, cdrom, tape, floppy, ... */
-	select_t	select;		/* basic drive/head select reg value */
-	byte		ctl;		/* "normal" value for IDE_CONTROL_REG */
-	byte		ready_stat;	/* min status value for drive ready */
-	byte		mult_count;	/* current multiple sector setting */
-	byte 		mult_req;	/* requested multiple sector setting */
-	byte 		tune_req;	/* requested drive tuning setting */
-	byte		io_32bit;	/* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
-	byte		bad_wstat;	/* used for ignoring WRERR_STAT */
-	byte		nowerr;		/* used for ignoring WRERR_STAT */
-	byte		sect0;		/* offset of first sector for DM6:DDO */
-	unsigned int	usage;		/* current "open()" count for drive */
-	byte 		head;		/* "real" number of heads */
-	byte		sect;		/* "real" sectors per track */
-	byte		bios_head;	/* BIOS/fdisk/LILO number of heads */
-	byte		bios_sect;	/* BIOS/fdisk/LILO sectors per track */
+	unsigned dead		: 1;	/* 1=dead, no new attachments */
+	unsigned addressing;		/*      : 3;
+					 *  0=28-bit
+					 *  1=48-bit
+					 *  2=48-bit doing 28-bit
+					 *  3=64-bit
+					 */
+
+	u8	scsi;		/* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */
+        u8	quirk_list;	/* considered quirky, set for a specific host */
+        u8	suspend_reset;	/* drive suspend mode flag, soft-reset recovers */
+        u8	init_speed;	/* transfer rate set at boot */
+        u8	current_speed;	/* current transfer rate set */
+        u8	dn;		/* now wide spread use */
+        u8	wcache;		/* status of write cache */
+	u8	acoustic;	/* acoustic management */
+	u8	media;		/* disk, cdrom, tape, floppy, ... */
+	u8	ctl;		/* "normal" value for IDE_CONTROL_REG */
+	u8	ready_stat;	/* min status value for drive ready */
+	u8	mult_count;	/* current multiple sector setting */
+	u8	mult_req;	/* requested multiple sector setting */
+	u8	tune_req;	/* requested drive tuning setting */
+	u8	io_32bit;	/* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
+	u8	bad_wstat;	/* used for ignoring WRERR_STAT */
+	u8	nowerr;		/* used for ignoring WRERR_STAT */
+	u8	sect0;		/* offset of first sector for DM6:DDO */
+	u8	head;		/* "real" number of heads */
+	u8	sect;		/* "real" sectors per track */
+	u8	bios_head;	/* BIOS/fdisk/LILO number of heads */
+	u8	bios_sect;	/* BIOS/fdisk/LILO sectors per track */
+
 	unsigned int	bios_cyl;	/* BIOS/fdisk/LILO number of cyls */
 	unsigned int	cyl;		/* "real" number of cyls */
-	unsigned long	capacity;	/* total number of sectors */
-	unsigned long long capacity48;	/* total number of sectors */
-	unsigned int	drive_data;	/* for use by tuneproc/selectproc as needed */
-	void		  *hwif;	/* actually (ide_hwif_t *) */
-	wait_queue_head_t wqueue;	/* used to wait for drive in open() */
-	struct hd_driveid *id;		/* drive model identification info */
-	struct hd_struct  *part;	/* drive partition table */
-	char		name[4];	/* drive name, such as "hda" */
-	void 		*driver;	/* (ide_driver_t *) */
-	void		*driver_data;	/* extra driver data */
-	devfs_handle_t	de;		/* directory for device */
-	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
-	void		*settings;	/* /proc/ide/ drive settings */
-	char		driver_req[10];	/* requests specific driver */
+	unsigned int	drive_data;	/* use by tuneproc/selectproc */
+	unsigned int	usage;		/* current "open()" count for drive */
+	unsigned int	failures;	/* current failure count */
+	unsigned int	max_failures;	/* maximum allowed failure count */
+
+	u32		capacity;	/* total number of sectors */
+	u64		capacity48;	/* total number of sectors */
+
 	int		last_lun;	/* last logical unit */
 	int		forced_lun;	/* if hdxlun was given at boot */
 	int		lun;		/* logical unit */
 	int		crc_count;	/* crc counter to reduce drive speed */
-	byte		quirk_list;	/* drive is considered quirky if set for a specific host */
-	byte		suspend_reset;	/* drive suspend mode flag, soft-reset recovers */
-	byte		init_speed;	/* transfer rate set at boot */
-	byte		current_speed;	/* current transfer rate set */
-	byte		dn;		/* now wide spread use */
-	byte		wcache;		/* status of write cache */
-	byte		acoustic;	/* acoustic management */
-	unsigned int	failures;	/* current failure count */
-	unsigned int	max_failures;	/* maximum allowed failure count */
 } ide_drive_t;
 
-/*
- * An ide_dmaproc_t() initiates/aborts DMA read/write operations on a drive.
- *
- * The caller is assumed to have selected the drive and programmed the drive's
- * sector address using CHS or LBA.  All that remains is to prepare for DMA
- * and then issue the actual read/write DMA/PIO command to the drive.
- *
- * Returns 0 if all went well.
- * Returns 1 if DMA read/write could not be started, in which case the caller
- * should either try again later, or revert to PIO for the current request.
- */
-typedef enum {	ide_dma_read,	ide_dma_write,		ide_dma_begin,
-		ide_dma_end,	ide_dma_check,		ide_dma_on,
-		ide_dma_off,	ide_dma_off_quietly,	ide_dma_test_irq,
-		ide_dma_bad_drive,			ide_dma_good_drive,
-		ide_dma_verbose,			ide_dma_retune,
-		ide_dma_lostirq,			ide_dma_timeout
-} ide_dma_action_t;
-
-typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
+typedef struct ide_pio_ops_s {
+	void (*ata_input_data)(ide_drive_t *, void *, u32);
+	void (*ata_output_data)(ide_drive_t *, void *, u32);
+
+	void (*atapi_input_bytes)(ide_drive_t *, void *, u32);
+	void (*atapi_output_bytes)(ide_drive_t *, void *, u32);
+} ide_pio_ops_t;
+
+typedef struct ide_dma_ops_s {
+	/* insert dma operations here! */
+	int (*ide_dma_read)(ide_drive_t *drive);
+	int (*ide_dma_write)(ide_drive_t *drive);
+	int (*ide_dma_begin)(ide_drive_t *drive);
+	int (*ide_dma_end)(ide_drive_t *drive);
+	int (*ide_dma_check)(ide_drive_t *drive);
+	int (*ide_dma_on)(ide_drive_t *drive);
+	int (*ide_dma_off)(ide_drive_t *drive);
+	int (*ide_dma_off_quietly)(ide_drive_t *drive);
+	int (*ide_dma_test_irq)(ide_drive_t *drive);
+	int (*ide_dma_host_on)(ide_drive_t *drive);
+	int (*ide_dma_host_off)(ide_drive_t *drive);
+	int (*ide_dma_bad_drive)(ide_drive_t *drive);
+	int (*ide_dma_good_drive)(ide_drive_t *drive);
+	int (*ide_dma_count)(ide_drive_t *drive);
+	int (*ide_dma_verbose)(ide_drive_t *drive);
+	int (*ide_dma_retune)(ide_drive_t *drive);
+	int (*ide_dma_lostirq)(ide_drive_t *drive);
+	int (*ide_dma_timeout)(ide_drive_t *drive);
+} ide_dma_ops_t;
 
 /*
- * An ide_ideproc_t() performs CPU-polled transfers to/from a drive.
- * Arguments are: the drive, the buffer pointer, and the length (in bytes or
- * words depending on if it's an IDE or ATAPI call).
- *
- * If it is not defined for a controller, standard-code is used from ide.c.
- *
- * Controllers which are not memory-mapped in the standard way need to 
- * override that mechanism using this function to work.
+ * mapping stuff, prepare for highmem...
  *
+ * temporarily mapping a (possible) highmem bio for PIO transfer
  */
-typedef enum { ideproc_ide_input_data,    ideproc_ide_output_data,
-	       ideproc_atapi_input_bytes, ideproc_atapi_output_bytes
-} ide_ide_action_t;
-
-typedef void (ide_ideproc_t)(ide_ide_action_t, ide_drive_t *, void *, unsigned int);
+#define ide_rq_offset(rq) \
+	(((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)
 
-/*
- * An ide_tuneproc_t() is used to set the speed of an IDE interface
- * to a particular PIO mode.  The "byte" parameter is used
- * to select the PIO mode by number (0,1,2,3,4,5), and a value of 255
- * indicates that the interface driver should "auto-tune" the PIO mode
- * according to the drive capabilities in drive->id;
- *
- * Not all interface types support tuning, and not all of those
- * support all possible PIO settings.  They may silently ignore
- * or round values as they see fit.
- */
-typedef void (ide_tuneproc_t) (ide_drive_t *, byte);
-typedef int (ide_speedproc_t) (ide_drive_t *, byte);
-
-/*
- * This is used to provide support for strange interfaces
- */
-typedef void (ide_selectproc_t) (ide_drive_t *);
-typedef void (ide_resetproc_t) (ide_drive_t *);
-typedef int (ide_quirkproc_t) (ide_drive_t *);
-typedef void (ide_intrproc_t) (ide_drive_t *);
-typedef void (ide_maskproc_t) (ide_drive_t *, int);
-typedef void (ide_rw_proc_t) (ide_drive_t *, ide_dma_action_t);
+extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags)
+{
+	return bh_kmap_irq(rq->bh, flags) + ide_rq_offset(rq);
+}
 
-/*
- * ide soft-power support
- */
-typedef int (ide_busproc_t) (ide_drive_t *, int);
+extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags)
+{
+	bh_kunmap_irq(buffer, flags);
+}
 
 #define IDE_CHIPSET_PCI_MASK	\
     ((1<<ide_pci)|(1<<ide_cmd646)|(1<<ide_ali14xx))
 #define IDE_CHIPSET_IS_PCI(c)	((IDE_CHIPSET_PCI_MASK >> (c)) & 1)
 
-#ifdef CONFIG_BLK_DEV_IDEPCI
-typedef struct ide_pci_devid_s {
-	unsigned short	vid;
-	unsigned short	did;
-} ide_pci_devid_t;
-
-#define IDE_PCI_DEVID_NULL	((ide_pci_devid_t){0,0})
-#define IDE_PCI_DEVID_EQ(a,b)	(a.vid == b.vid && a.did == b.did)
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+struct ide_pci_device_s;
 
 typedef struct hwif_s {
-	struct hwif_s	*next;		/* for linked-list in ide_hwgroup_t */
-	void		*hwgroup;	/* actually (ide_hwgroup_t *) */
-	ide_ioreg_t	io_ports[IDE_NR_PORTS];	/* task file registers */
+	struct hwif_s *next;		/* for linked-list in ide_hwgroup_t */
+	struct hwif_s *mate;		/* other hwif from same PCI chip */
+	struct hwgroup_s *hwgroup;	/* actually (ide_hwgroup_t *) */
+	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
+	struct gendisk *gd;		/* gendisk structure */
+
+	char name[6];			/* name of interface, eg. "ide0" */
+
+		/* task file registers for pata and sata */
+	ide_ioreg_t	io_ports[IDE_NR_PORTS];
+	sata_ioreg_t	sata_scr[SATA_NR_PORTS];
+	sata_ioreg_t	sata_misc[SATA_NR_PORTS];
+
 	hw_regs_t	hw;		/* Hardware info */
 	ide_drive_t	drives[MAX_DRIVES];	/* drive info */
-	struct gendisk	*gd;		/* gendisk structure */
-	ide_tuneproc_t	*tuneproc;	/* routine to tune PIO mode for drives */
-	ide_speedproc_t	*speedproc;	/* routine to retune DMA modes for drives */
-	ide_selectproc_t *selectproc;	/* tweaks hardware to select drive */
-	ide_resetproc_t	*resetproc;	/* routine to reset controller after a disk reset */
-	ide_intrproc_t	*intrproc;	/* special interrupt handling for shared pci interrupts */
-	ide_maskproc_t	*maskproc;	/* special host masking for drive selection */
-	ide_quirkproc_t	*quirkproc;	/* check host's drive quirk list */
-	ide_rw_proc_t	*rwproc;	/* adjust timing based upon rq->cmd direction */
-	ide_ideproc_t   *ideproc;       /* CPU-polled transfer routine */
-	ide_dmaproc_t	*dmaproc;	/* dma read/write/abort routine */
-	unsigned int	*dmatable_cpu;	/* dma physical region descriptor table (cpu view) */
-	dma_addr_t	dmatable_dma;	/* dma physical region descriptor table (dma view) */
-	struct scatterlist *sg_table;	/* Scatter-gather list used to build the above */
+
+	u8 major;	/* our major number */
+	u8 index;	/* 0 for ide0; 1 for ide1; ... */
+	u8 channel;	/* for dual-port chips: 0=primary, 1=secondary */
+	u8 straight8;	/* Alan's straight 8 check */
+	u8 bus_state;	/* power state of the IDE bus */
+
+	u8 atapi_dma;	/* host supports atapi_dma */
+	u8 ultra_mask;
+	u8 mwdma_mask;
+	u8 swdma_mask;
+
+	hwif_chipset_t chipset;	/* sub-module for tuning.. */
+
+	struct pci_dev  *pci_dev;	/* for pci chipsets */
+	struct ide_pci_device_s	*cds;	/* chipset device struct */
+
+#if 0
+	ide_hwif_ops_t	*hwifops;
+#else
+	/* routine is for HBA specific IDENTITY operations */
+	int	(*identify)(ide_drive_t *);
+	/* routine to tune PIO mode for drives */
+	void	(*tuneproc)(ide_drive_t *, u8);
+	/* routine to retune DMA modes for drives */
+	int	(*speedproc)(ide_drive_t *, u8);
+	/* tweaks hardware to select drive */
+	void	(*selectproc)(ide_drive_t *);
+	/* chipset polling based on hba specifics */
+	int	(*reset_poll)(ide_drive_t *);
+	/* chipset specific changes to default for device-hba resets */
+	void	(*pre_reset)(ide_drive_t *);
+	/* routine to reset controller after a disk reset */
+	void	(*resetproc)(ide_drive_t *);
+	/* special interrupt handling for shared pci interrupts */
+	void	(*intrproc)(ide_drive_t *);
+	/* special host masking for drive selection */
+	void	(*maskproc)(ide_drive_t *, int);
+	/* check host's drive quirk list */
+	int	(*quirkproc)(ide_drive_t *);
+	/* driver soft-power interface */
+	int	(*busproc)(ide_drive_t *, int);
+//	/* host rate limiter */
+//	u8	(*ratemask)(ide_drive_t *);
+//	/* device rate limiter */
+//	u8	(*ratefilter)(ide_drive_t *, u8);
+#endif
+
+#if 0
+	ide_pio_ops_t	*pioops;
+#else
+	void (*ata_input_data)(ide_drive_t *, void *, u32);
+	void (*ata_output_data)(ide_drive_t *, void *, u32);
+
+	void (*atapi_input_bytes)(ide_drive_t *, void *, u32);
+	void (*atapi_output_bytes)(ide_drive_t *, void *, u32);
+#endif
+
+#if 0
+	ide_dma_ops_t	*dmaops;
+#else
+	int (*ide_dma_read)(ide_drive_t *drive);
+	int (*ide_dma_write)(ide_drive_t *drive);
+	int (*ide_dma_begin)(ide_drive_t *drive);
+	int (*ide_dma_end)(ide_drive_t *drive);
+	int (*ide_dma_check)(ide_drive_t *drive);
+	int (*ide_dma_on)(ide_drive_t *drive);
+	int (*ide_dma_off)(ide_drive_t *drive);
+	int (*ide_dma_off_quietly)(ide_drive_t *drive);
+	int (*ide_dma_test_irq)(ide_drive_t *drive);
+	int (*ide_dma_host_on)(ide_drive_t *drive);
+	int (*ide_dma_host_off)(ide_drive_t *drive);
+	int (*ide_dma_bad_drive)(ide_drive_t *drive);
+	int (*ide_dma_good_drive)(ide_drive_t *drive);
+	int (*ide_dma_count)(ide_drive_t *drive);
+	int (*ide_dma_verbose)(ide_drive_t *drive);
+	int (*ide_dma_retune)(ide_drive_t *drive);
+	int (*ide_dma_lostirq)(ide_drive_t *drive);
+	int (*ide_dma_timeout)(ide_drive_t *drive);
+#endif
+
+#if 0
+	ide_io_ops_t	*iops;
+#else
+	void (*OUTB)(u8 addr, unsigned long port);
+	void (*OUTW)(u16 addr, unsigned long port);
+	void (*OUTL)(u32 addr, unsigned long port);
+	void (*OUTSW)(unsigned long port, void *addr, u32 count);
+	void (*OUTSL)(unsigned long port, void *addr, u32 count);
+
+	u8  (*INB)(unsigned long port);
+	u16 (*INW)(unsigned long port);
+	u32 (*INL)(unsigned long port);
+	void (*INSW)(unsigned long port, void *addr, u32 count);
+	void (*INSL)(unsigned long port, void *addr, u32 count);
+#endif
+
+	/* dma physical region descriptor table (cpu view) */
+	unsigned int	*dmatable_cpu;
+	/* dma physical region descriptor table (dma view) */
+	dma_addr_t	dmatable_dma;
+	/* Scatter-gather list used to build the above */
+	struct scatterlist *sg_table;
 	int sg_nents;			/* Current number of entries in it */
 	int sg_dma_direction;		/* dma transfer direction */
 	int sg_dma_active;		/* is it in use */
-	struct hwif_s	*mate;		/* other hwif from same PCI chip */
+
+	int		mmio;		/* hosts iomio (0), mmio (1) or custom (2) select */
+	int		rqsize;		/* max sectors per request */
+	int		addressing;	/* hosts addressing */
+	int		irq;		/* our irq number */
+	int		initializing;	/* set while initializing self */
+
+	unsigned long	dma_master;	/* reference base addr dmabase */
 	unsigned long	dma_base;	/* base addr for dma ports */
+	unsigned long	dma_command;	/* dma command register */
+	unsigned long	dma_vendor1;	/* dma vendor 1 register */
+	unsigned long	dma_status;	/* dma status register */
+	unsigned long	dma_vendor3;	/* dma vendor 3 register */
+	unsigned long	dma_prdtable;	/* actual prd table address */
+	unsigned long	dma_base2;	/* extended base addr for dma ports */
+
 	unsigned	dma_extra;	/* extra addr for dma ports */
 	unsigned long	config_data;	/* for use by chipset-specific code */
 	unsigned long	select_data;	/* for use by chipset-specific code */
-	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
-	int		irq;		/* our irq number */
-	byte		major;		/* our major number */
-	char 		name[6];	/* name of interface, eg. "ide0" */
-	byte		index;		/* 0 for ide0; 1 for ide1; ... */
-	hwif_chipset_t	chipset;	/* sub-module for tuning.. */
+#if (DISK_RECOVERY_TIME > 0)
+	unsigned long	last_time;	/* time when previous rq was done */
+#endif
+
+
 	unsigned	noprobe    : 1;	/* don't probe for this interface */
 	unsigned	present    : 1;	/* this interface exists */
-	unsigned	serialized : 1;	/* serialized operation with mate hwif */
+	unsigned	serialized : 1;	/* serialized all channel operation */
 	unsigned	sharing_irq: 1;	/* 1 = sharing irq with another hwif */
 	unsigned	reset      : 1;	/* reset after probe */
-	unsigned	autodma    : 1;	/* automatically try to enable DMA at boot */
+	unsigned	autodma    : 1;	/* auto-attempt using DMA at boot */
 	unsigned	udma_four  : 1;	/* 1=ATA-66 capable, 0=default */
-	unsigned	no_highio  : 1; /* don't trust pci dma mask, bounce */
-	byte		channel;	/* for dual-port chips: 0=primary, 1=secondary */
-#ifdef CONFIG_BLK_DEV_IDEPCI
-	struct pci_dev	*pci_dev;	/* for pci chipsets */
-	ide_pci_devid_t	pci_devid;	/* for pci chipsets: {VID,DID} */
-#endif /* CONFIG_BLK_DEV_IDEPCI */
-#if (DISK_RECOVERY_TIME > 0)
-	unsigned long	last_time;	/* time when previous rq was done */
-#endif
-	byte		straight8;	/* Alan's straight 8 check */
+	unsigned	highmem    : 1;	/* can do full 32-bit dma */
+	unsigned	no_dsc     : 1;	/* 0 default, 1 dsc_overlap disabled */
+
 	void		*hwif_data;	/* extra hwif data */
-	ide_busproc_t	*busproc;	/* driver soft-power interface */
-	byte		bus_state;	/* power state of the IDE bus */
 } ide_hwif_t;
 
 /*
@@ -572,7 +1018,7 @@
  */
 typedef enum {
 	ide_stopped,	/* no drive operation was started */
-	ide_started	/* a drive operation was started, and a handler was set */
+	ide_started	/* a drive operation was started, handler was set */
 } ide_startstop_t;
 
 /*
@@ -581,24 +1027,39 @@
 typedef ide_startstop_t (ide_pre_handler_t)(ide_drive_t *, struct request *);
 typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
 typedef ide_startstop_t (ide_post_handler_t)(ide_drive_t *);
-
-/*
- * when ide_timer_expiry fires, invoke a handler of this type
- * to decide what to do.
- */
 typedef int (ide_expiry_t)(ide_drive_t *);
 
 typedef struct hwgroup_s {
-	ide_handler_t		*handler;/* irq handler, if active */
-	volatile int		busy;	/* BOOL: protects all fields below */
-	int			sleeping; /* BOOL: wake us up on timer expiry */
-	ide_drive_t		*drive;	/* current drive */
-	ide_hwif_t		*hwif;	/* ptr to current hwif in linked-list */
-	struct request		*rq;	/* current request */
-	struct timer_list	timer;	/* failsafe timer */
-	struct request		wrq;	/* local copy of current write rq */
-	unsigned long		poll_timeout;	/* timeout value during long polls */
-	ide_expiry_t		*expiry;	/* queried upon timeouts */
+		/* irq handler, if active */
+	ide_startstop_t	(*handler)(ide_drive_t *);
+		/* irq handler, suspended if active */
+	ide_startstop_t	(*handler_save)(ide_drive_t *);
+		/* BOOL: protects all fields below */
+	volatile int busy;
+		/* BOOL: wake us up on timer expiry */
+	int sleeping;
+		/* current drive */
+	ide_drive_t *drive;
+		/* ptr to current hwif in linked-list */
+	ide_hwif_t *hwif;
+
+		/* for pci chipsets */
+	struct pci_dev *pci_dev;
+		/* chipset device struct */
+	struct ide_pci_device_s *cds;
+
+		/* current request */
+	struct request *rq;
+		/* failsafe timer */
+	struct timer_list timer;
+		/* local copy of current write rq */
+	struct request wrq;
+		/* timeout value during long polls */
+	unsigned long poll_timeout;
+		/* queried upon timeouts */
+	int (*expiry)(ide_drive_t *);
+		/* ide_system_bus_speed */
+	int pio_clock;
 } ide_hwgroup_t;
 
 /* structure attached to the request for IDE_TASK_CMDS */
@@ -651,14 +1112,14 @@
 } ide_proc_entry_t;
 
 #ifdef CONFIG_PROC_FS
-void proc_ide_create(void);
-void proc_ide_destroy(void);
-void recreate_proc_ide_device(ide_hwif_t *, ide_drive_t *);
-void destroy_proc_ide_device(ide_hwif_t *, ide_drive_t *);
-void destroy_proc_ide_drives(ide_hwif_t *);
-void create_proc_ide_interfaces(void);
-void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data);
-void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p);
+extern void proc_ide_create(void);
+extern void proc_ide_destroy(void);
+extern void recreate_proc_ide_device(ide_hwif_t *, ide_drive_t *);
+extern void destroy_proc_ide_device(ide_hwif_t *, ide_drive_t *);
+extern void destroy_proc_ide_drives(ide_hwif_t *);
+extern void create_proc_ide_interfaces(void);
+extern void ide_add_proc_entries(struct proc_dir_entry *, ide_proc_entry_t *, void *);
+extern void ide_remove_proc_entries(struct proc_dir_entry *, ide_proc_entry_t *);
 read_proc_t proc_ide_read_capacity;
 read_proc_t proc_ide_read_geometry;
 
@@ -686,51 +1147,39 @@
  */
 #define IDE_SUBDRIVER_VERSION	1
 
-typedef int		(ide_cleanup_proc)(ide_drive_t *);
-typedef int		(ide_standby_proc)(ide_drive_t *);
-typedef int		(ide_flushcache_proc)(ide_drive_t *);
-typedef ide_startstop_t	(ide_do_request_proc)(ide_drive_t *, struct request *, unsigned long);
-typedef void		(ide_end_request_proc)(byte, ide_hwgroup_t *);
-typedef int		(ide_ioctl_proc)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
-typedef int		(ide_open_proc)(struct inode *, struct file *, ide_drive_t *);
-typedef void		(ide_release_proc)(struct inode *, struct file *, ide_drive_t *);
-typedef int		(ide_check_media_change_proc)(ide_drive_t *);
-typedef void		(ide_revalidate_proc)(ide_drive_t *);
-typedef void		(ide_pre_reset_proc)(ide_drive_t *);
-typedef unsigned long	(ide_capacity_proc)(ide_drive_t *);
-typedef ide_startstop_t	(ide_special_proc)(ide_drive_t *);
-typedef void		(ide_setting_proc)(ide_drive_t *);
-typedef int		(ide_reinit_proc)(ide_drive_t *);
-typedef void		(ata_prebuilder_proc)(ide_drive_t *);
-typedef void		(atapi_prebuilder_proc)(ide_drive_t *);
-
 typedef struct ide_driver_s {
 	const char			*name;
 	const char			*version;
-	byte				media;
+	u8				media;
 	unsigned busy			: 1;
 	unsigned supports_dma		: 1;
 	unsigned supports_dsc_overlap	: 1;
-	ide_cleanup_proc		*cleanup;
-	ide_standby_proc		*standby;
-	ide_flushcache_proc		*flushcache;
-	ide_do_request_proc		*do_request;
-	ide_end_request_proc		*end_request;
-	ide_ioctl_proc			*ioctl;
-	ide_open_proc			*open;
-	ide_release_proc		*release;
-	ide_check_media_change_proc	*media_change;
-	ide_revalidate_proc		*revalidate;
-	ide_pre_reset_proc		*pre_reset;
-	ide_capacity_proc		*capacity;
-	ide_special_proc		*special;
-	ide_proc_entry_t		*proc;
-	ide_reinit_proc			*reinit;
-	ata_prebuilder_proc		*ata_prebuilder;
-	atapi_prebuilder_proc		*atapi_prebuilder;
+	int		(*cleanup)(ide_drive_t *);
+	int		(*shutdown)(ide_drive_t *);
+	int		(*standby)(ide_drive_t *);
+	int		(*suspend)(ide_drive_t *);
+	int		(*resume)(ide_drive_t *);
+	int		(*flushcache)(ide_drive_t *);
+	ide_startstop_t	(*do_request)(ide_drive_t *, struct request *, unsigned long);
+	int		(*end_request)(ide_drive_t *, int);
+	u8		(*sense)(ide_drive_t *, const char *, u8);
+	ide_startstop_t	(*error)(ide_drive_t *, const char *, u8);
+	int		(*ioctl)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
+	int		(*open)(struct inode *, struct file *, ide_drive_t *);
+	void		(*release)(struct inode *, struct file *, ide_drive_t *);
+	int		(*media_change)(ide_drive_t *);
+	void		(*revalidate)(ide_drive_t *);
+	void		(*pre_reset)(ide_drive_t *);
+	unsigned long	(*capacity)(ide_drive_t *);
+	ide_startstop_t	(*special)(ide_drive_t *);
+	ide_proc_entry_t	*proc;
+	int		(*init)(void);
+	int		(*attach)(ide_drive_t *);
+	void		(*ata_prebuilder)(ide_drive_t *);
+	void		(*atapi_prebuilder)(ide_drive_t *);
 } ide_driver_t;
 
-#define DRIVER(drive)		((ide_driver_t *)((drive)->driver))
+#define DRIVER(drive)		((drive)->driver)
 
 /*
  * IDE modules.
@@ -748,6 +1197,53 @@
 	struct ide_module_s		*next;
 } ide_module_t;
 
+typedef struct ide_devices_s {
+	char			name[4];		/* hdX */
+	unsigned		attached	: 1;	/* native */
+	unsigned		alttached	: 1;	/* alternate */
+	struct ide_devices_s	*next;
+} ide_devices_t;
+
+#if 0
+typedef enum {
+	IDE_MEDIA_FLOPPY	= ide_floppy,
+	IDE_MEDIA_TAPE		= ide_tape,
+	IDE_MEDIA_CDROM		= ide_cdrom,
+	IDE_MEDIA_OPTICAL	= ide_optical,
+	IDE_MEDIA_DISK		= ide_disk,
+	IDE_MEDIA_SCSI		= ide_scsi,
+} ide_media_type;
+
+struct ide_media {
+	ide_media_type type;
+	char name[4];
+	atomic_t refcount;	/* Maybe this should be a struct module*
+				   with MOD_INC instead */
+	struct list_head devices;
+};
+
+struct {
+	struct ide_media floppy;
+	struct ide_media tape;
+	struct ide_media cdrom;
+	struct ide_media optical;
+	struct ide_media disk;
+	struct ide_media scsi;
+} ide_medias;
+
+void __init init_media(void)
+{
+	memset(&ide_medias, 0, sizeof(ide_medias));
+
+	ide_medias.floppy.type	= IDE_MEDIA_FLOPPY;
+	ide_medias.tape.type	= IDE_MEDIA_TAPE;
+	ide_medias.cdrom.type	= IDE_MEDIA_CDROM;
+	ide_medias.optical.type	= IDE_MEDIA_OPTICAL;
+	ide_medias.disk.type	= IDE_MEDIA_DISK;
+	ide_medias.scsi.type	= IDE_MEDIA_SCSI;
+};
+#endif
+
 /*
  * ide_hwifs[] is the master data structure used to keep track
  * of just about everything in ide.c.  Whenever possible, routines
@@ -758,8 +1254,16 @@
  */
 #ifndef _IDE_C
 extern	ide_hwif_t	ide_hwifs[];		/* master data repository */
+extern	ide_module_t	*ide_chipsets;
 extern	ide_module_t	*ide_modules;
 extern	ide_module_t	*ide_probe;
+
+extern	ide_devices_t	*idedisk;
+extern	ide_devices_t	*idecd;
+extern	ide_devices_t	*idefloppy;
+extern	ide_devices_t	*idetape;
+extern	ide_devices_t	*idescsi;
+
 #endif
 extern int noautodma;
 
@@ -768,56 +1272,50 @@
  */
 #define IDE_DRIVER		/* Toggle some magic bits in blk.h */
 #define LOCAL_END_REQUEST	/* Don't generate end_request in blk.h */
+//#define DEVICE_NR(device)	(MINOR(device) >> PARTN_BITS)
 #include <linux/blk.h>
 
-void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup);
-
-/*
- * This is used for (nearly) all data transfers from/to the IDE interface
- * FIXME for 2.5, to a pointer pass verses memcpy........
- */
-void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
-void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
-
-/*
- * This is used for (nearly) all ATAPI data transfers from/to the IDE interface
- * FIXME for 2.5, to a pointer pass verses memcpy........
- */
-void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
-void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
-
-int drive_is_ready (ide_drive_t *drive);
+extern int ide_end_request(ide_drive_t *, int /* uptodate */);
 
 /*
  * This is used on exit from the driver, to designate the next irq handler
  * and also to start the safety timer.
  */
-void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry);
+extern void ide_set_handler(ide_drive_t *, ide_handler_t *, unsigned int, ide_expiry_t *);
 
 /*
  * Error reporting, in human readable form (luxurious, but a memory hog).
+ *
+ * (drive, msg, status)
  */
-byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat);
+extern u8 ide_dump_status(ide_drive_t *, const char *, u8);
 
 /*
  * ide_error() takes action based on the error returned by the controller.
  * The caller should return immediately after invoking this.
+ *
+ * (drive, msg, status)
  */
-ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat);
+extern ide_startstop_t ide_error(ide_drive_t *, const char *, u8);
 
 /*
  * Issue a simple drive command
  * The drive must be selected beforehand.
+ *
+ * (drive, command, nsector, handler)
  */
-void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler);
+extern void ide_cmd(ide_drive_t *, u8, u8, ide_handler_t *);
 
+extern void ide_fix_driveid(struct hd_driveid *);
 /*
  * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
  * removing leading/trailing blanks and compressing internal blanks.
  * It is primarily used to tidy up the model name/number fields as
  * returned by the WIN_[P]IDENTIFY commands.
+ *
+ * (s, bytecount, byteswap)
  */
-void ide_fixstring (byte *s, const int bytecount, const int byteswap);
+extern void ide_fixstring(u8 *, const int, const int);
 
 /*
  * This routine busy-waits for the drive status to be not "busy".
@@ -826,43 +1324,44 @@
  * cases return 1 after doing "*startstop = ide_error()", and the
  * caller should return the updated value of "startstop" in this case.
  * "startstop" is unchanged when the function returns 0;
+ *  (startstop, drive, good, bad, timeout)
  */
-int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout);
-
-int ide_wait_noerr (ide_drive_t *drive, byte good, byte bad, unsigned long timeout);
+extern int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long);
 
 /*
  * This routine is called from the partition-table code in genhd.c
  * to "convert" a drive to a logical geometry with fewer than 1024 cyls.
  */
-int ide_xlate_1024 (kdev_t, int, int, const char *);
+extern int ide_xlate_1024(kdev_t, int, int, const char *);
 
 /*
  * Convert kdev_t structure into ide_drive_t * one.
  */
-ide_drive_t *get_info_ptr (kdev_t i_rdev);
+extern ide_drive_t *get_info_ptr(kdev_t i_rdev);
 
 /*
  * Return the current idea about the total capacity of this drive.
  */
-unsigned long current_capacity (ide_drive_t *drive);
+extern unsigned long current_capacity(ide_drive_t *);
+
+extern void ide_revalidate_drive(ide_drive_t *);
 
 /*
  * Start a reset operation for an IDE interface.
  * The caller should return immediately after invoking this.
  */
-ide_startstop_t ide_do_reset (ide_drive_t *);
+extern ide_startstop_t ide_do_reset(ide_drive_t *);
 
 /*
  * Re-Start an operation for an IDE interface.
  * The caller should return immediately after invoking this.
  */
-ide_startstop_t restart_request (ide_drive_t *);
+extern int restart_request(ide_drive_t *, struct request *);
 
 /*
  * This function is intended to be used prior to invoking ide_do_drive_cmd().
  */
-void ide_init_drive_cmd (struct request *rq);
+extern void ide_init_drive_cmd(struct request *);
 
 /*
  * "action" parameter type for ide_do_drive_cmd() below.
@@ -875,21 +1374,6 @@
 } ide_action_t;
 
 /*
- * temporarily mapping a (possible) highmem bio
- */
-#define ide_rq_offset(rq) (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)
-
-extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags)
-{
-	return bh_kmap_irq(rq->bh, flags) + ide_rq_offset(rq);
-}
-
-extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags)
-{
-	bh_kunmap_irq(buffer, flags);
-}
-
-/*
  * This function issues a special IDE device request
  * onto the request queue.
  *
@@ -914,23 +1398,35 @@
  * for the new rq to be completed. This is again intended for careful
  * use by the ATAPI tape/cdrom driver code.
  */
-int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action);
+extern int ide_do_drive_cmd(ide_drive_t *, struct request *, ide_action_t);
 
 /*
  * Clean up after success/failure of an explicit drive cmd.
  * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD).
  * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASK_MASK).
+ *
+ * (ide_drive_t *drive, u8 stat, u8 err)
  */
-void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err);
+extern void ide_end_drive_cmd(ide_drive_t *, u8, u8);
 
 /*
- * Issue ATA command and wait for completion. use for implementing commands in kernel
+ * Issue ATA command and wait for completion.
+ * Use for implementing commands in kernel
+ *
+ *  (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
  */
-int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf);
+extern int ide_wait_cmd(ide_drive_t *, u8, u8, u8, u8, u8 *);
+
+/* (ide_drive_t *drive, u8 *buf) */
+extern int ide_wait_cmd_task(ide_drive_t *, u8 *);
 
-int ide_wait_cmd_task (ide_drive_t *drive, byte *buf);
- 
 typedef struct ide_task_s {
+/*
+ *	struct hd_drive_task_hdr	tf;
+ *	task_struct_t		tf;
+ *	struct hd_drive_hob_hdr		hobf;
+ *	hob_struct_t		hobf;
+ */
 	task_ioreg_t		tfRegister[8];
 	task_ioreg_t		hobRegister[8];
 	ide_reg_valid_t		tf_out_flags;
@@ -940,71 +1436,147 @@
 	ide_pre_handler_t	*prehandler;
 	ide_handler_t		*handler;
 	ide_post_handler_t	*posthandler;
-	void			*special;	/* valid_t generally */
 	struct request		*rq;		/* copy of request */
-	unsigned long		block;		/* copy of block */
+	void			*special;	/* valid_t generally */
 } ide_task_t;
 
 typedef struct pkt_task_s {
+/*
+ *	struct hd_drive_task_hdr	pktf;
+ *	task_struct_t		pktf;
+ *	u8			pkcdb[12];
+ */
 	task_ioreg_t		tfRegister[8];
 	int			data_phase;
 	int			command_type;
 	ide_handler_t		*handler;
-	void			*special;
 	struct request		*rq;		/* copy of request */
-	unsigned long		block;		/* copy of block */
+	void			*special;
 } pkt_task_t;
 
-/*
- * taskfile io for disks for now...
- */
-ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task);
+extern inline void SELECT_DRIVE(ide_drive_t *);
+extern inline void SELECT_INTERRUPT(ide_drive_t *);
+extern inline void SELECT_MASK(ide_drive_t *, int);
+extern inline void QUIRK_LIST(ide_drive_t *);
+
+extern void ata_input_data(ide_drive_t *, void *, u32);
+extern void ata_output_data(ide_drive_t *, void *, u32);
+extern void atapi_input_bytes(ide_drive_t *, void *, u32);
+extern void atapi_output_bytes(ide_drive_t *, void *, u32);
+extern void taskfile_input_data(ide_drive_t *, void *, u32);
+extern void taskfile_output_data(ide_drive_t *, void *, u32);
+
+extern int drive_is_ready(ide_drive_t *);
+extern int wait_for_ready(ide_drive_t *, int /* timeout */);
 
 /*
- * Builds request from ide_ioctl
+ * taskfile io for disks for now...and builds request from ide_ioctl
  */
-void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler);
+extern ide_startstop_t do_rw_taskfile(ide_drive_t *, ide_task_t *);
+
+/* (ide_drive_t *drive, u8 stat, u8 err) */
+extern void ide_end_taskfile(ide_drive_t *, u8, u8);
 
 /*
  * Special Flagged Register Validation Caller
  */
-// ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task);
+extern ide_startstop_t flagged_taskfile(ide_drive_t *, ide_task_t *);
+
+extern ide_startstop_t set_multmode_intr(ide_drive_t *);
+extern ide_startstop_t set_geometry_intr(ide_drive_t *);
+extern ide_startstop_t recal_intr(ide_drive_t *);
+extern ide_startstop_t task_no_data_intr(ide_drive_t *);
+extern ide_startstop_t task_in_intr(ide_drive_t *);
+extern ide_startstop_t task_mulin_intr(ide_drive_t *);
+extern ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *);
+extern ide_startstop_t task_out_intr(ide_drive_t *);
+extern ide_startstop_t pre_task_mulout_intr(ide_drive_t *, struct request *);
+extern ide_startstop_t task_mulout_intr(ide_drive_t *);
+extern void ide_init_drive_taskfile(struct request *);
 
-ide_startstop_t set_multmode_intr (ide_drive_t *drive);
-ide_startstop_t set_geometry_intr (ide_drive_t *drive);
-ide_startstop_t recal_intr (ide_drive_t *drive);
-ide_startstop_t task_no_data_intr (ide_drive_t *drive);
-ide_startstop_t task_in_intr (ide_drive_t *drive);
-ide_startstop_t task_mulin_intr (ide_drive_t *drive);
-ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq);
-ide_startstop_t task_out_intr (ide_drive_t *drive);
-ide_startstop_t task_mulout_intr (ide_drive_t *drive);
-void ide_init_drive_taskfile (struct request *rq);
+extern int ide_raw_taskfile(ide_drive_t *, ide_task_t *, u8 *);
 
-int ide_wait_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf);
+extern ide_pre_handler_t * ide_pre_handler_parser(struct hd_drive_task_hdr *, struct hd_drive_hob_hdr *);
 
-int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *cmd, byte *buf);
+extern ide_handler_t * ide_handler_parser(struct hd_drive_task_hdr *, struct hd_drive_hob_hdr *);
+
+extern ide_post_handler_t * ide_post_handler_parser(struct hd_drive_task_hdr *, struct hd_drive_hob_hdr *);
 
-ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
-ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
 /* Expects args is a full set of TF registers and parses the command type */
-int ide_cmd_type_parser (ide_task_t *args);
+extern int ide_cmd_type_parser(ide_task_t *);
+
+int ide_taskfile_ioctl(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
+int ide_cmd_ioctl(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
+int ide_task_ioctl(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
+
+#if 0
+
+#define IDEFLOPPY_PC_BUFFER_SIZE        256
+#define IDETAPE_PC_BUFFER_SIZE          256
+#define IDE_PC_BUFFER_SIZE          256
+
+typedef struct ide_packet_command_s {
+		/* Actual packet bytes */
+	u8 c[12];
+		/* On each retry, we increment retries */
+	int retries;
+		/* Error code */
+	int error;
+		/* Bytes to transfer */
+	int request_transfer;
+		/* Bytes actually transferred */
+	int actually_transferred;
+		/* Size of our data buffer */
+	int buffer_size;
+
+	struct buffer_head *bh;
+	u8 *b_data;
+		/* The corresponding request */
+	struct request *rq;
+# if 0
+		/* Scatter gather table */
+	struct scatterlist *sg;
+# endif
+	int b_count;
+		/* Data buffer */
+	u8 *buffer;
+		/* Pointer into the above buffer */
+	u8 *current_position;
+		/* Called when this packet command is completed */
+	ide_startstop_t (*callback) (ide_drive_t *);
+		/* Temporary buffer */
+	u8 pc_buffer[IDE_PC_BUFFER_SIZE];
+		/* Status/Action bit flags: long for set_bit */
+	unsigned long flags;
+} ide_pc_t;
+
+ide-cd orthoginal :-/
+struct packet_command {
+        char *buffer;
+        int buflen;
+        int stat;
+        int quiet;
+        int timeout;
+        struct request_sense *sense;
+        unsigned char c[12];
+};
 
-int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+#endif
 
 #ifdef CONFIG_PKT_TASK_IOCTL
-int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+extern int pkt_taskfile_ioctl(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
 #endif /* CONFIG_PKT_TASK_IOCTL */
 
-void ide_delay_50ms (void);
-int system_bus_clock(void);
+extern void ide_delay_50ms(void);
+extern int system_bus_clock(void);
 
-byte ide_auto_reduce_xfer (ide_drive_t *drive);
-int ide_driveid_update (ide_drive_t *drive);
-int ide_ata66_check (ide_drive_t *drive, ide_task_t *args);
-int ide_config_drive_speed (ide_drive_t *drive, byte speed);
-byte eighty_ninty_three (ide_drive_t *drive);
-int set_transfer (ide_drive_t *drive, ide_task_t *args);
+extern u8 ide_auto_reduce_xfer(ide_drive_t *);
+extern int ide_driveid_update(ide_drive_t *);
+extern int ide_ata66_check(ide_drive_t *, ide_task_t *);
+extern int ide_config_drive_speed(ide_drive_t *, u8);
+extern u8 eighty_ninty_three (ide_drive_t *);
+extern int set_transfer(ide_drive_t *, ide_task_t *);
+extern int taskfile_lib_get_identify(ide_drive_t *drive, u8 *);
 
 /*
  * ide_system_bus_speed() returns what we think is the system VESA/PCI
@@ -1012,107 +1584,176 @@
  * The default is 40 for known PCI systems, 50 otherwise.
  * The "idebus=xx" parameter can be used to override this value.
  */
-int ide_system_bus_speed (void);
-
-/*
- * ide_multwrite() transfers a block of up to mcount sectors of data
- * to a drive as part of a disk multwrite operation.
- */
-int ide_multwrite (ide_drive_t *drive, unsigned int mcount);
+extern int ide_system_bus_speed(void);
 
 /*
  * ide_stall_queue() can be used by a drive to give excess bandwidth back
  * to the hwgroup by sleeping for timeout jiffies.
  */
-void ide_stall_queue (ide_drive_t *drive, unsigned long timeout);
+extern void ide_stall_queue(ide_drive_t *, unsigned long);
 
 /*
  * ide_get_queue() returns the queue which corresponds to a given device.
  */
-request_queue_t *ide_get_queue (kdev_t dev);
+extern request_queue_t *ide_get_queue(kdev_t dev);
 
 /*
  * CompactFlash cards and their brethern pretend to be removable hard disks,
  * but they never have a slave unit, and they don't have doorlock mechanisms.
- * This test catches them, and is invoked elsewhere when setting appropriate config bits.
+ * This test catches them, and is invoked elsewhere when setting appropriate
+ * config bits.
  */
-int drive_is_flashcard (ide_drive_t *drive);
+extern int drive_is_flashcard(ide_drive_t *);
 
-int ide_spin_wait_hwgroup (ide_drive_t *drive);
-void ide_timer_expiry (unsigned long data);
-void ide_intr (int irq, void *dev_id, struct pt_regs *regs);
-void do_ide_request (request_queue_t * q);
-void ide_init_subdrivers (void);
+extern int ide_spin_wait_hwgroup(ide_drive_t *);
+extern void ide_timer_expiry(unsigned long);
+extern void ide_intr(int irq, void *dev_id, struct pt_regs *regs);
+extern void do_ide_request(request_queue_t *);
+extern void ide_init_subdrivers(void);
 
-#ifndef _IDE_C
 extern struct block_device_operations ide_fops[];
 extern ide_proc_entry_t generic_subdriver_entries[];
-#endif
 
-int ide_reinit_drive (ide_drive_t *drive);
+extern int ide_attach_drive(ide_drive_t *);
 
-#ifdef _IDE_C
-#ifdef CONFIG_BLK_DEV_IDE
-int ideprobe_init (void);
-#endif /* CONFIG_BLK_DEV_IDE */
-#ifdef CONFIG_BLK_DEV_IDEDISK
-int idedisk_reinit (ide_drive_t *drive);
-int idedisk_init (void);
-#endif /* CONFIG_BLK_DEV_IDEDISK */
-#ifdef CONFIG_BLK_DEV_IDECD
-int ide_cdrom_reinit (ide_drive_t *drive);
-int ide_cdrom_init (void);
-#endif /* CONFIG_BLK_DEV_IDECD */
-#ifdef CONFIG_BLK_DEV_IDETAPE
-int idetape_reinit (ide_drive_t *drive);
-int idetape_init (void);
-#endif /* CONFIG_BLK_DEV_IDETAPE */
-#ifdef CONFIG_BLK_DEV_IDEFLOPPY
-int idefloppy_reinit (ide_drive_t *drive);
-int idefloppy_init (void);
-#endif /* CONFIG_BLK_DEV_IDEFLOPPY */
-#ifdef CONFIG_BLK_DEV_IDESCSI
-int idescsi_reinit (ide_drive_t *drive);
-int idescsi_init (void);
-#endif /* CONFIG_BLK_DEV_IDESCSI */
-#endif /* _IDE_C */
-
-int ide_register_module (ide_module_t *module);
-void ide_unregister_module (ide_module_t *module);
-ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n);
-int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version);
-int ide_unregister_subdriver (ide_drive_t *drive);
-int ide_replace_subdriver(ide_drive_t *drive, const char *driver);
+extern int ideprobe_init(void);
+extern int idedisk_attach(ide_drive_t *);
+extern int idedisk_init(void);
+extern int ide_cdrom_attach(ide_drive_t *);
+extern int ide_cdrom_init(void);
+extern int idetape_attach(ide_drive_t *);
+extern int idetape_init(void);
+extern int idefloppy_attach(ide_drive_t *);
+extern int idefloppy_init(void);
+extern int idescsi_attach(ide_drive_t *);
+extern int idescsi_init(void);
+
+extern void ide_scan_pcibus(int scan_direction) __init;
+extern int ide_pci_register_driver(struct pci_driver *driver);
+extern void ide_pci_unregister_driver(struct pci_driver *driver);
+
+extern void default_hwif_iops(ide_hwif_t *);
+extern void default_hwif_mmiops(ide_hwif_t *);
+extern void default_hwif_transport(ide_hwif_t *);
+
+
+extern int ide_register_module(ide_module_t *module);
+extern void ide_unregister_module(ide_module_t *module);
+extern ide_drive_t *ide_scan_devices(u8, const char *, ide_driver_t *, int);
+extern int ide_register_subdriver(ide_drive_t *, ide_driver_t *, int /* ver */);
+extern int ide_unregister_subdriver(ide_drive_t *);
+extern int ide_replace_subdriver(ide_drive_t *, const char * /* driver*/);
+
+#ifdef CONFIG_PROC_FS
+typedef struct ide_pci_host_proc_s {
+	char				*name;
+        u8				set;
+	get_info_t			*get_info;
+	struct proc_dir_entry		*parent;
+	struct ide_pci_host_proc_s	*next;
+} ide_pci_host_proc_t;
+
+void ide_pci_register_host_proc(ide_pci_host_proc_t *);
+#endif /* CONFIG_PROC_FS */
 
-#ifdef CONFIG_BLK_DEV_IDEPCI
 #define ON_BOARD		1
 #define NEVER_BOARD		0
+
 #ifdef CONFIG_BLK_DEV_OFFBOARD
 #  define OFF_BOARD		ON_BOARD
 #else /* CONFIG_BLK_DEV_OFFBOARD */
 #  define OFF_BOARD		NEVER_BOARD
 #endif /* CONFIG_BLK_DEV_OFFBOARD */
 
-unsigned long ide_find_free_region (unsigned short size) __init;
-void ide_scan_pcibus (int scan_direction) __init;
-#endif
-#ifdef CONFIG_BLK_DEV_IDEDMA
+#define NODMA 0
+#define NOAUTODMA 1
+#define AUTODMA 2
+#define EOL 255
+
+typedef struct ide_pci_enablebit_s {
+	u8	reg;	/* byte pci reg holding the enable-bit */
+	u8	mask;	/* mask to isolate the enable-bit */
+	u8	val;	/* value of masked reg when "enabled" */
+} ide_pci_enablebit_t;
+
+typedef struct ide_pci_device_s {
+	u16			vendor;
+	u16			device;
+	char			*name;
+	void			(*init_setup)(struct pci_dev *, struct ide_pci_device_s *);
+	unsigned int		(*init_chipset)(struct pci_dev *, const char *);
+	void			(*init_iops)(ide_hwif_t *);
+	void                    (*init_hwif)(ide_hwif_t *);
+	void			(*init_dma)(ide_hwif_t *, unsigned long);
+	u8			channels;
+	u8			autodma;
+	ide_pci_enablebit_t	enablebits[2];
+	u8			bootable;
+	unsigned int		extra;
+	struct ide_pci_device_s	*next;
+} ide_pci_device_t;
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+extern void ide_setup_pci_devices(struct pci_dev *, struct pci_dev *, ide_pci_device_t *);
+
 #define BAD_DMA_DRIVE		0
 #define GOOD_DMA_DRIVE		1
-int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func);
-void ide_destroy_dmatable (ide_drive_t *drive);
-ide_startstop_t ide_dma_intr (ide_drive_t *drive);
-int check_drive_lists (ide_drive_t *drive, int good_bad);
-int report_drive_dmaing (ide_drive_t *drive);
-int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
-int ide_release_dma (ide_hwif_t *hwif);
-void ide_setup_dma (ide_hwif_t *hwif, unsigned long dmabase, unsigned int num_ports) __init;
-unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
+extern int ide_build_dmatable(ide_drive_t *, struct request *, int);
+extern void ide_destroy_dmatable(ide_drive_t *);
+extern ide_startstop_t ide_dma_intr(ide_drive_t *);
+extern int ide_release_dma(ide_hwif_t *);
+extern void ide_setup_dma(ide_hwif_t *, unsigned long, unsigned int);
+
+extern int __ide_dma_host_off(ide_drive_t *);
+extern int __ide_dma_off_quietly(ide_drive_t *);
+extern int __ide_dma_off(ide_drive_t *);
+extern int __ide_dma_host_on(ide_drive_t *);
+extern int __ide_dma_on(ide_drive_t *);
+extern int __ide_dma_check(ide_drive_t *);
+extern int __ide_dma_read(ide_drive_t *);
+extern int __ide_dma_write(ide_drive_t *);
+extern int __ide_dma_begin(ide_drive_t *);
+extern int __ide_dma_end(ide_drive_t *);
+extern int __ide_dma_test_irq(ide_drive_t *);
+extern int __ide_dma_bad_drive(ide_drive_t *);
+extern int __ide_dma_good_drive(ide_drive_t *);
+extern int __ide_dma_count(ide_drive_t *);
+extern int __ide_dma_verbose(ide_drive_t *);
+extern int __ide_dma_retune(ide_drive_t *);
+extern int __ide_dma_lostirq(ide_drive_t *);
+extern int __ide_dma_timeout(ide_drive_t *);
+#else
+static inline void ide_release_dma(ide_hwif_t *x) {;}
 #endif
 
-void hwif_unregister (ide_hwif_t *hwif);
+extern void hwif_unregister(ide_hwif_t *);
+
+extern void export_ide_init_queue(ide_drive_t *);
+extern u8 export_probe_for_drive(ide_drive_t *);
+extern int probe_hwif_init(ide_hwif_t *);
+
+static inline void *ide_get_hwifdata (ide_hwif_t * hwif)
+{
+	return hwif->hwif_data;
+}
+
+static inline void ide_set_hwifdata (ide_hwif_t * hwif, void *data)
+{
+	hwif->hwif_data = data;
+}
+
+/* ide-lib.c */
+extern u8 ide_dma_speed(ide_drive_t *drive, u8 mode);
+extern u8 ide_rate_filter(u8 mode, u8 speed);
+extern int ide_dma_enable(ide_drive_t *drive);
+extern char *ide_xfer_verbose(u8 xfer_rate);
+extern void ide_toggle_bounce(ide_drive_t *drive, int on);
+extern int ide_set_xfer_rate(ide_drive_t *drive, u8 rate);
+
+#define ide_lock		(io_request_lock)
+#define DRIVE_LOCK(drive)       ((drive)->queue.queue_lock)
 
-void export_ide_init_queue (ide_drive_t *drive);
-byte export_probe_for_drive (ide_drive_t *drive);
 
 #endif /* _IDE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/input.h linux-2.4.21/include/linux/input.h
--- linux-2.4.20/include/linux/input.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/include/linux/input.h	2002-12-18 18:58:08.000000000 +0000
@@ -426,6 +426,7 @@
  */
 
 #define MSC_SERIAL		0x00
+#define MSC_PULSELED		0x01
 #define MSC_MAX			0x07
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/interrupt.h linux-2.4.21/include/linux/interrupt.h
--- linux-2.4.20/include/linux/interrupt.h	2001-11-22 19:46:19.000000000 +0000
+++ linux-2.4.21/include/linux/interrupt.h	2002-12-18 18:58:01.000000000 +0000
@@ -10,6 +10,7 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 #include <asm/ptrace.h>
+#include <asm/system.h>
 
 struct irqaction {
 	void (*handler)(int, void *, struct pt_regs *);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/meye.h linux-2.4.21/include/linux/meye.h
--- linux-2.4.20/include/linux/meye.h	2001-07-04 21:41:33.000000000 +0000
+++ linux-2.4.21/include/linux/meye.h	2002-12-18 18:58:05.000000000 +0000
@@ -1,7 +1,9 @@
 /* 
  * Motion Eye video4linux driver for Sony Vaio PictureBook
  *
- * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ * Copyright (C) 2001-2002 Stelian Pop <stelian@popies.net>
+ *
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
  *
  * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/miscdevice.h linux-2.4.21/include/linux/miscdevice.h
--- linux-2.4.20/include/linux/miscdevice.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/linux/miscdevice.h	2002-12-18 18:58:02.000000000 +0000
@@ -3,38 +3,39 @@
 
 #include <linux/devfs_fs_kernel.h>
 
-#define BUSMOUSE_MINOR 0
-#define PSMOUSE_MINOR  1
-#define MS_BUSMOUSE_MINOR 2
-#define ATIXL_BUSMOUSE_MINOR 3
-#define AMIGAMOUSE_MINOR 4
-#define ATARIMOUSE_MINOR 5
-#define SUN_MOUSE_MINOR 6
-#define APOLLO_MOUSE_MINOR 7
-#define PC110PAD_MINOR 9
-#define ADB_MOUSE_MINOR 10
-#define MK712_MINOR 15			/* MK712 touch screen */
+#define BUSMOUSE_MINOR		0
+#define PSMOUSE_MINOR		1
+#define MS_BUSMOUSE_MINOR	2
+#define ATIXL_BUSMOUSE_MINOR	3
+#define AMIGAMOUSE_MINOR	4
+#define ATARIMOUSE_MINOR	5
+#define SUN_MOUSE_MINOR		6
+#define APOLLO_MOUSE_MINOR	7
+#define PC110PAD_MINOR		9
+#define ADB_MOUSE_MINOR		10
+#define MK712_MINOR 		15	/* MK712 touch screen */
+#define SYNTH_MINOR    		25
 #define WATCHDOG_MINOR		130	/* Watchdog timer     */
 #define TEMP_MINOR		131	/* Temperature Sensor */
-#define RTC_MINOR 135
+#define RTC_MINOR		135
 #define EFI_RTC_MINOR		136	/* EFI Time services */
-#define SUN_OPENPROM_MINOR 139
-#define NVRAM_MINOR 144
-#define I2O_MINOR 166
+#define SUN_OPENPROM_MINOR	139
+#define NVRAM_MINOR		144
+#define I2O_MINOR		166
 #define MICROCODE_MINOR		184
-#define MWAVE_MINOR	219		/* ACP/Mwave Modem */
-#define MPT_MINOR	220
-#define MISC_DYNAMIC_MINOR 255
-
-#define SGI_GRAPHICS_MINOR   146
-#define SGI_OPENGL_MINOR     147
-#define SGI_GFX_MINOR        148
-#define SGI_STREAMS_MOUSE    149
-#define SGI_STREAMS_KEYBOARD 150
+#define MWAVE_MINOR		219	/* ACP/Mwave Modem */
+#define MPT_MINOR		220
+#define MISC_DYNAMIC_MINOR	255
+
+#define SGI_GRAPHICS_MINOR	146
+#define SGI_OPENGL_MINOR	147
+#define SGI_GFX_MINOR		148
+#define SGI_STREAMS_MOUSE	149
+#define SGI_STREAMS_KEYBOARD	150
 /* drivers/sgi/char/usema.c */
-#define SGI_USEMACLONE	     151
+#define SGI_USEMACLONE	    	151
 
-#define TUN_MINOR	     200
+#define TUN_MINOR	     	200
 
 extern int misc_init(void);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/mm.h linux-2.4.21/include/linux/mm.h
--- linux-2.4.20/include/linux/mm.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21/include/linux/mm.h	2002-12-18 18:58:02.000000000 +0000
@@ -297,6 +297,7 @@
 #define PG_arch_1		13
 #define PG_reserved		14
 #define PG_launder		15	/* written out by VM pressure.. */
+#define PG_fs_1			16	/* Filesystem specific */
 
 /* Make it prettier to test the above... */
 #define UnlockPage(page)	unlock_page(page)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/nfs_fs.h linux-2.4.21/include/linux/nfs_fs.h
--- linux-2.4.20/include/linux/nfs_fs.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/include/linux/nfs_fs.h	2002-12-18 18:58:06.000000000 +0000
@@ -269,6 +269,10 @@
 extern int  nfs_scan_lru_read(struct nfs_server *, struct list_head *);
 extern int  nfs_scan_lru_read_timeout(struct nfs_server *, struct list_head *);
 
+#define NFS_SetPageSync(page)		set_bit(PG_fs_1, &(page)->flags)
+#define NFS_ClearPageSync(page)		clear_bit(PG_fs_1, &(page)->flags)
+#define NFS_TestClearPageSync(page)	test_and_clear_bit(PG_fs_1, &(page)->flags)
+
 /*
  * linux/fs/mount_clnt.c
  * (Used only by nfsroot module)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/nfsd/const.h linux-2.4.21/include/linux/nfsd/const.h
--- linux-2.4.20/include/linux/nfsd/const.h	2000-04-01 16:04:27.000000000 +0000
+++ linux-2.4.21/include/linux/nfsd/const.h	2002-12-18 18:58:03.000000000 +0000
@@ -21,7 +21,7 @@
 /*
  * Maximum blocksize supported by daemon currently at 8K
  */
-#define NFSSVC_MAXBLKSIZE	8192
+#define NFSSVC_MAXBLKSIZE	(8*1024)
 
 #ifdef __KERNEL__
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/pci.h linux-2.4.21/include/linux/pci.h
--- linux-2.4.20/include/linux/pci.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/include/linux/pci.h	2002-12-18 18:58:08.000000000 +0000
@@ -65,9 +65,9 @@
 #define  PCI_HEADER_TYPE_CARDBUS 2
 
 #define PCI_BIST		0x0f	/* 8 bits */
-#define PCI_BIST_CODE_MASK	0x0f	/* Return result */
-#define PCI_BIST_START		0x40	/* 1 to start BIST, 2 secs or less */
-#define PCI_BIST_CAPABLE	0x80	/* 1 if BIST capable */
+#define  PCI_BIST_CODE_MASK	0x0f	/* Return result */
+#define  PCI_BIST_START		0x40	/* 1 to start BIST, 2 secs or less */
+#define  PCI_BIST_CAPABLE	0x80	/* 1 if BIST capable */
 
 /*
  * Base addresses specify locations in memory or I/O space.
@@ -195,6 +195,7 @@
 #define  PCI_CAP_ID_SLOTID	0x04	/* Slot Identification */
 #define  PCI_CAP_ID_MSI		0x05	/* Message Signalled Interrupts */
 #define  PCI_CAP_ID_CHSWP	0x06	/* CompactPCI HotSwap */
+#define  PCI_CAP_ID_PCIX	0x07	/* PCI-X */
 #define PCI_CAP_LIST_NEXT	1	/* Next capability in the list */
 #define PCI_CAP_FLAGS		2	/* Capability defined flags (16 bits) */
 #define PCI_CAP_SIZEOF		4
@@ -271,6 +272,37 @@
 #define PCI_MSI_DATA_32		8	/* 16 bits of data for 32-bit devices */
 #define PCI_MSI_DATA_64		12	/* 16 bits of data for 64-bit devices */
 
+/* CompactPCI Hotswap Register */
+
+#define PCI_CHSWP_CSR		2	/* Control and Status Register */
+#define  PCI_CHSWP_DHA		0x01	/* Device Hiding Arm */
+#define  PCI_CHSWP_EIM		0x02	/* ENUM# Signal Mask */
+#define  PCI_CHSWP_PIE		0x04	/* Pending Insert or Extract */
+#define  PCI_CHSWP_LOO		0x08	/* LED On / Off */
+#define  PCI_CHSWP_PI		0x30	/* Programming Interface */
+#define  PCI_CHSWP_EXT		0x40	/* ENUM# status - extraction */
+#define  PCI_CHSWP_INS		0x80	/* ENUM# status - insertion */
+
+/* PCI-X registers */
+
+#define PCI_X_CMD		2	/* Modes & Features */
+#define  PCI_X_CMD_DPERR_E	0x0001	/* Data Parity Error Recovery Enable */
+#define  PCI_X_CMD_ERO		0x0002	/* Enable Relaxed Ordering */
+#define  PCI_X_CMD_MAX_READ	0x000c	/* Max Memory Read Byte Count */
+#define  PCI_X_CMD_MAX_SPLIT	0x0070	/* Max Outstanding Split Transactions */
+#define PCI_X_DEVFN		4	/* A copy of devfn. */
+#define PCI_X_BUSNR		5	/* Bus segment number */
+#define PCI_X_STATUS		6	/* PCI-X capabilities */
+#define  PCI_X_STATUS_64BIT	0x0001	/* 64-bit device */
+#define  PCI_X_STATUS_133MHZ	0x0002	/* 133 MHz capable */
+#define  PCI_X_STATUS_SPL_DISC	0x0004	/* Split Completion Discarded */
+#define  PCI_X_STATUS_UNX_SPL	0x0008	/* Unexpected Split Completion */
+#define  PCI_X_STATUS_COMPLEX	0x0010	/* Device Complexity */
+#define  PCI_X_STATUS_MAX_READ	0x0060	/* Designed Maximum Memory Read Count */
+#define  PCI_X_STATUS_MAX_SPLIT	0x0380	/* Design Max Outstanding Split Trans */
+#define  PCI_X_STATUS_MAX_CUM	0x1c00	/* Designed Max Cumulative Read Size */
+#define  PCI_X_STATUS_SPL_ERR	0x2000	/* Rcvd Split Completion Error Msg */
+
 /* Include the ID list */
 
 #include <linux/pci_ids.h>
@@ -767,6 +799,7 @@
 #define PCIPCI_NATOMA		4
 #define PCIPCI_VIAETBF		8
 #define PCIPCI_VSFX		16
+#define PCIPCI_ALIMAGIK		32
 
 #endif /* __KERNEL__ */
 #endif /* LINUX_PCI_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/pci_ids.h linux-2.4.21/include/linux/pci_ids.h
--- linux-2.4.20/include/linux/pci_ids.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/include/linux/pci_ids.h	2002-12-18 18:58:07.000000000 +0000
@@ -143,6 +143,7 @@
 #define PCI_DEVICE_ID_COMPAQ_NETEL100I	0xb011
 #define PCI_DEVICE_ID_COMPAQ_CISS	0xb060
 #define PCI_DEVICE_ID_COMPAQ_CISSB	0xb178
+#define PCI_DEVICE_ID_COMPAQ_CISSC 	0x0046
 #define PCI_DEVICE_ID_COMPAQ_THUNDER	0xf130
 #define PCI_DEVICE_ID_COMPAQ_NETFLEX3B	0xf150
 
@@ -172,6 +173,8 @@
 #define PCI_DEVICE_ID_LSI_FC929_LAN	0x0623
 #define PCI_DEVICE_ID_LSI_FC919		0x0624
 #define PCI_DEVICE_ID_LSI_FC919_LAN	0x0625
+#define PCI_DEVICE_ID_LSI_FC929X	0x0626
+#define PCI_DEVICE_ID_LSI_FC919X	0x0628
 #define PCI_DEVICE_ID_NCR_YELLOWFIN	0x0701
 #define PCI_DEVICE_ID_LSI_61C102	0x0901
 #define PCI_DEVICE_ID_LSI_63C815	0x1000
@@ -265,6 +268,8 @@
 #define PCI_DEVICE_ID_ATI_RADEON_RB	0x5145
 #define PCI_DEVICE_ID_ATI_RADEON_RC	0x5146
 #define PCI_DEVICE_ID_ATI_RADEON_RD	0x5147
+/* RadeonIGP */
+#define PCI_DEVICE_ID_ATI_RADEON_IGP	0xCAB0
 
 #define PCI_VENDOR_ID_VLSI		0x1004
 #define PCI_DEVICE_ID_VLSI_82C592	0x0005
@@ -288,6 +293,12 @@
 #define PCI_DEVICE_ID_NS_87560_USB	0x0012
 #define PCI_DEVICE_ID_NS_83815		0x0020
 #define PCI_DEVICE_ID_NS_83820		0x0022
+#define PCI_DEVICE_ID_NS_SCx200_BRIDGE	0x0500
+#define PCI_DEVICE_ID_NS_SCx200_SMI	0x0501
+#define PCI_DEVICE_ID_NS_SCx200_IDE	0x0502
+#define PCI_DEVICE_ID_NS_SCx200_AUDIO	0x0503
+#define PCI_DEVICE_ID_NS_SCx200_VIDEO	0x0504
+#define PCI_DEVICE_ID_NS_SCx200_XBUS	0x0505
 #define PCI_DEVICE_ID_NS_87410		0xd001
 
 #define PCI_VENDOR_ID_TSENG		0x100c
@@ -372,7 +383,7 @@
 #define PCI_DEVICE_ID_AMD_FE_GATE_7006	0x7006
 #define PCI_DEVICE_ID_AMD_FE_GATE_7007	0x7007
 #define PCI_DEVICE_ID_AMD_FE_GATE_700C	0x700C
-#define PCI_DEVIDE_ID_AMD_FE_GATE_700D	0x700D
+#define PCI_DEVICE_ID_AMD_FE_GATE_700D	0x700D
 #define PCI_DEVICE_ID_AMD_FE_GATE_700E	0x700E
 #define PCI_DEVICE_ID_AMD_FE_GATE_700F	0x700F
 #define PCI_DEVICE_ID_AMD_COBRA_7400	0x7400
@@ -387,11 +398,17 @@
 #define PCI_DEVICE_ID_AMD_VIPER_7411	0x7411
 #define PCI_DEVICE_ID_AMD_VIPER_7413	0x7413
 #define PCI_DEVICE_ID_AMD_VIPER_7414	0x7414
-#define PCI_DEVICE_ID_AMD_VIPER_7440	0x7440
-#define PCI_DEVICE_ID_AMD_VIPER_7441	0x7441
-#define PCI_DEVICE_ID_AMD_VIPER_7443	0x7443
-#define PCI_DEVICE_ID_AMD_VIPER_7448	0x7448
-#define PCI_DEVICE_ID_AMD_VIPER_7449	0x7449
+#define PCI_DEVICE_ID_AMD_OPUS_7440	0x7440
+#	define PCI_DEVICE_ID_AMD_VIPER_7440	PCI_DEVICE_ID_AMD_OPUS_7440
+#define PCI_DEVICE_ID_AMD_OPUS_7441	0x7441
+#	define PCI_DEVICE_ID_AMD_VIPER_7441	PCI_DEVICE_ID_AMD_OPUS_7441
+#define PCI_DEVICE_ID_AMD_OPUS_7443	0x7443
+#	define PCI_DEVICE_ID_AMD_VIPER_7443	PCI_DEVICE_ID_AMD_OPUS_7443
+#define PCI_DEVICE_ID_AMD_OPUS_7448	0x7448
+# define	PCI_DEVICE_ID_AMD_VIPER_7448	PCI_DEVICE_ID_AMD_OPUS_7448
+#define PCI_DEVICE_ID_AMD_OPUS_7449	0x7449
+#	define PCI_DEVICE_ID_AMD_VIPER_7449	PCI_DEVICE_ID_AMD_OPUS_7449
+#define PCI_DEVICE_ID_AMD_8111_LAN	0x7462
 #define PCI_DEVICE_ID_AMD_8111_IDE     0x7469
 #define PCI_DEVICE_ID_AMD_8111_AC97    0x746d
 
@@ -477,20 +494,28 @@
 #define PCI_DEVICE_ID_SI_635		0x0635
 #define PCI_DEVICE_ID_SI_640		0x0640
 #define PCI_DEVICE_ID_SI_645		0x0645
-#define PCI_DEVICE_ID_SI_646        0x0646
+#define PCI_DEVICE_ID_SI_646		0x0646
+#define PCI_DEVICE_ID_SI_648		0x0648
 #define PCI_DEVICE_ID_SI_650		0x0650
+#define PCI_DEVICE_ID_SI_651		0x0651
+#define PCI_DEVICE_ID_SI_652		0x0652
 #define PCI_DEVICE_ID_SI_730		0x0730
 #define PCI_DEVICE_ID_SI_630_VGA	0x6300
 #define PCI_DEVICE_ID_SI_730_VGA	0x7300
 #define PCI_DEVICE_ID_SI_735		0x0735
 #define PCI_DEVICE_ID_SI_740		0x0740
 #define PCI_DEVICE_ID_SI_745		0x0745
+#define PCI_DEVICE_ID_SI_746		0x0746
+#define PCI_DEVICE_ID_SI_748		0x0748
 #define PCI_DEVICE_ID_SI_750		0x0750
+#define PCI_DEVICE_ID_SI_751		0x0751
+#define PCI_DEVICE_ID_SI_752		0x0752
 #define PCI_DEVICE_ID_SI_900		0x0900
 #define PCI_DEVICE_ID_SI_5107		0x5107
 #define PCI_DEVICE_ID_SI_5300		0x5300
 #define PCI_DEVICE_ID_SI_5511		0x5511
 #define PCI_DEVICE_ID_SI_5513		0x5513
+#define PCI_DEVICE_ID_SI_5518		0x5518
 #define PCI_DEVICE_ID_SI_5571		0x5571
 #define PCI_DEVICE_ID_SI_5591		0x5591
 #define PCI_DEVICE_ID_SI_5597		0x5597
@@ -740,7 +765,9 @@
 #define PCI_DEVICE_ID_CMD_648		0x0648
 #define PCI_DEVICE_ID_CMD_649		0x0649
 #define PCI_DEVICE_ID_CMD_670		0x0670
-#define PCI_DEVICE_ID_CMD_680		0x0680
+
+#define PCI_DEVICE_ID_SII_680		0x0680
+#define PCI_DEVICE_ID_SII_3112		0x3112
 
 #define PCI_VENDOR_ID_VISION		0x1098
 #define PCI_DEVICE_ID_VISION_QD8500	0x0001
@@ -885,6 +912,7 @@
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA	0x0152
 #define PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO	0x0153
 #define PCI_DEVICE_ID_NVIDIA_IGEFORCE2		0x01a0
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE		0x01bc
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3		0x0200
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1		0x0201
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2		0x0202
@@ -986,6 +1014,9 @@
 #define PCI_DEVICE_ID_VIA_8233C_0	0x3109
 #define PCI_DEVICE_ID_VIA_8361		0x3112
 #define PCI_DEVICE_ID_VIA_8233A		0x3147
+#define PCI_DEVICE_ID_VIA_8235        0x3177
+#define PCI_DEVICE_ID_VIA_8377_0  0x3189
+#define PCI_DEVICE_ID_VIA_8377_0	0x3189
 #define PCI_DEVICE_ID_VIA_86C100A	0x6100
 #define PCI_DEVICE_ID_VIA_8231		0x8231
 #define PCI_DEVICE_ID_VIA_8231_4	0x8235
@@ -1124,6 +1155,7 @@
 #define PCI_DEVICE_ID_SERVERWORKS_OSB4IDE 0x0211
 #define PCI_DEVICE_ID_SERVERWORKS_CSB5IDE 0x0212
 #define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE 0x0213
+#define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2 0x0217
 #define PCI_DEVICE_ID_SERVERWORKS_OSB4USB 0x0220
 #define PCI_DEVICE_ID_SERVERWORKS_CSB5USB PCI_DEVICE_ID_SERVERWORKS_OSB4USB
 #define PCI_DEVICE_ID_SERVERWORKS_CSB6USB 0x0221
@@ -1568,6 +1600,9 @@
 #define PCI_VENDOR_ID_TEKRAM		0x1de1
 #define PCI_DEVICE_ID_TEKRAM_DC290	0xdc29
 
+#define PCI_VENDOR_ID_HINT		0x3388
+#define PCI_DEVICE_ID_HINT_VXPROII_IDE	0x8013
+
 #define PCI_VENDOR_ID_3DLABS		0x3d3d
 #define PCI_DEVICE_ID_3DLABS_300SX	0x0001
 #define PCI_DEVICE_ID_3DLABS_500TX	0x0002
@@ -1629,7 +1664,11 @@
 #define PCI_DEVICE_ID_INTEL_82430	0x0486
 #define PCI_DEVICE_ID_INTEL_82434	0x04a3
 #define PCI_DEVICE_ID_INTEL_I960	0x0960
+#define PCI_DEVICE_ID_INTEL_I960RM	0x0962
 #define PCI_DEVICE_ID_INTEL_82562ET	0x1031
+
+#define PCI_DEVICE_ID_INTEL_82815_MC	0x1130
+
 #define PCI_DEVICE_ID_INTEL_82559ER	0x1209
 #define PCI_DEVICE_ID_INTEL_82092AA_0	0x1221
 #define PCI_DEVICE_ID_INTEL_82092AA_1	0x1222
@@ -1685,9 +1724,9 @@
 #define PCI_DEVICE_ID_INTEL_82801E_2	0x2452
 #define PCI_DEVICE_ID_INTEL_82801E_3	0x2453
 #define PCI_DEVICE_ID_INTEL_82801E_9	0x2459
-#define PCI_DEVICE_ID_INTEL_82801E_11	0x245b
-#define PCI_DEVICE_ID_INTEL_82801E_13	0x245d
-#define PCI_DEVICE_ID_INTEL_82801E_14	0x245e
+#define PCI_DEVICE_ID_INTEL_82801E_11	0x245B
+#define PCI_DEVICE_ID_INTEL_82801E_14	0x245D
+#define PCI_DEVICE_ID_INTEL_82801E_15	0x245E
 #define PCI_DEVICE_ID_INTEL_82801CA_0	0x2480
 #define PCI_DEVICE_ID_INTEL_82801CA_2	0x2482
 #define PCI_DEVICE_ID_INTEL_82801CA_3	0x2483
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/raid/md_k.h linux-2.4.21/include/linux/raid/md_k.h
--- linux-2.4.20/include/linux/raid/md_k.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/include/linux/raid/md_k.h	2002-12-18 18:58:02.000000000 +0000
@@ -171,6 +171,7 @@
 	struct block_device *bdev;	/* block device handle */
 
 	mdp_super_t *sb;
+	struct page *sb_page;
 	unsigned long sb_offset;
 
 	int alias_device;		/* device alias to the same disk */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/reiserfs_fs_sb.h linux-2.4.21/include/linux/reiserfs_fs_sb.h
--- linux-2.4.20/include/linux/reiserfs_fs_sb.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/include/linux/reiserfs_fs_sb.h	2002-12-18 18:58:09.000000000 +0000
@@ -312,7 +312,7 @@
   int j_free_bitmap_nodes ;
   int j_used_bitmap_nodes ;
   struct list_head j_bitmap_nodes ;
-  struct inode j_dummy_inode ;
+  struct list_head j_dirty_buffers ;
   struct reiserfs_list_bitmap j_list_bitmap[JOURNAL_NUM_BITMAPS] ;	/* array of bitmaps to record the deleted blocks */
   struct reiserfs_journal_list j_journal_list[JOURNAL_LIST_COUNT] ;	    /* array of all the journal lists */
   struct reiserfs_journal_cnode *j_hash_table[JOURNAL_HASH_SIZE] ; 	    /* hash table for real buffer heads in current trans */ 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/scx200.h linux-2.4.21/include/linux/scx200.h
--- linux-2.4.20/include/linux/scx200.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/include/linux/scx200.h	2002-12-18 18:58:09.000000000 +0000
@@ -0,0 +1,56 @@
+/* linux/include/linux/scx200.h
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   Defines for the National Semiconductor SCx200 Processors
+*/
+
+/* Interesting stuff for the National Semiconductor SCx200 CPU */
+
+/* F0 PCI Header/Bridge Configuration Registers */
+#define SCx200_DOCCS_BASE 0x78	/* DOCCS Base Address Register */
+#define SCx200_DOCCS_CTRL 0x7c	/* DOCCS Control Register */
+
+/* GPIO Register Block */
+#define SCx200_GPIO_SIZE 0x2c	/* Size of GPIO register block */
+
+/* General Configuration Block */
+#define SCx200_CB_BASE 0x9000	/* Base fixed at 0x9000 according to errata */
+
+/* Watchdog Timer */
+#define SCx200_WDT_OFFSET 0x00	/* offset within configuration block */
+#define SCx200_WDT_SIZE 0x05	/* size */
+
+#define SCx200_WDT_WDTO 0x00	/* Time-Out Register */
+#define SCx200_WDT_WDCNFG 0x02	/* Configuration Register */
+#define SCx200_WDT_WDSTS 0x04	/* Status Register */
+#define SCx200_WDT_WDSTS_WDOVF (1<<0) /* Overflow bit */
+
+/* High Resolution Timer */
+#define SCx200_TIMER_OFFSET 0x08
+#define SCx200_TIMER_SIZE 0x05
+
+/* Clock Generators */
+#define SCx200_CLOCKGEN_OFFSET 0x10
+#define SCx200_CLOCKGEN_SIZE 0x10
+
+/* Pin Multiplexing and Miscellaneous Configuration Registers */
+#define SCx200_MISC_OFFSET 0x30
+#define SCx200_MISC_SIZE 0x10
+
+#define SCx200_PMR 0x30		/* Pin Multiplexing Register */
+#define SCx200_MCR 0x34		/* Miscellaneous Configuration Register */
+#define SCx200_INTSEL 0x38	/* Interrupt Selection Register */
+#define SCx200_IID 0x3c		/* IA On a Chip Identification Number Reg */
+#define SCx200_REV 0x3d		/* Revision Register */
+#define SCx200_CBA 0x3e		/* Configuration Base Address Register */
+
+/* Verify that the configuration block really is there */
+#define scx200_cb_probe(base) (inw((base) + SCx200_CBA) == (base))
+
+/*
+    Local variables:
+        compile-command: "make -C ../.. bzImage modules"
+        c-basic-offset: 8
+    End:
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/scx200_gpio.h linux-2.4.21/include/linux/scx200_gpio.h
--- linux-2.4.20/include/linux/scx200_gpio.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/include/linux/scx200_gpio.h	2002-12-18 18:58:05.000000000 +0000
@@ -0,0 +1,98 @@
+#include <linux/spinlock.h>
+
+u32 scx200_gpio_configure(int index, u32 set, u32 clear);
+void scx200_gpio_dump(unsigned index);
+
+extern unsigned scx200_gpio_base;
+extern spinlock_t scx200_gpio_lock;
+extern long scx200_gpio_shadow[2];
+
+#define scx200_gpio_present() (scx200_gpio_base!=0)
+
+/* Definitions to make sure I do the same thing in all functions */
+#define __SCx200_GPIO_BANK unsigned bank = index>>5
+#define __SCx200_GPIO_IOADDR unsigned short ioaddr = scx200_gpio_base+0x10*bank
+#define __SCx200_GPIO_SHADOW long *shadow = scx200_gpio_shadow+bank
+#define __SCx200_GPIO_INDEX index &= 31
+
+#define __SCx200_GPIO_OUT __asm__ __volatile__("outsl":"=mS" (shadow):"d" (ioaddr), "0" (shadow))
+
+/* returns the value of the GPIO pin */
+
+static inline int scx200_gpio_get(int index) {
+	__SCx200_GPIO_BANK;
+	__SCx200_GPIO_IOADDR + 0x04;
+	__SCx200_GPIO_INDEX;
+		
+	return (inl(ioaddr) & (1<<index)) ? 1 : 0;
+}
+
+/* return the value driven on the GPIO signal (the value that will be
+   driven if the GPIO is configured as an output, it might not be the
+   state of the GPIO right now if the GPIO is configured as an input) */
+
+static inline int scx200_gpio_current(int index) {
+        __SCx200_GPIO_BANK;
+	__SCx200_GPIO_INDEX;
+		
+	return (scx200_gpio_shadow[bank] & (1<<index)) ? 1 : 0;
+}
+
+/* drive the GPIO signal high */
+
+static inline void scx200_gpio_set_high(int index) {
+	__SCx200_GPIO_BANK;
+	__SCx200_GPIO_IOADDR;
+	__SCx200_GPIO_SHADOW;
+	__SCx200_GPIO_INDEX;
+	set_bit(index, shadow);
+	__SCx200_GPIO_OUT;
+}
+
+/* drive the GPIO signal low */
+
+static inline void scx200_gpio_set_low(int index) {
+	__SCx200_GPIO_BANK;
+	__SCx200_GPIO_IOADDR;
+	__SCx200_GPIO_SHADOW;
+	__SCx200_GPIO_INDEX;
+	clear_bit(index, shadow);
+	__SCx200_GPIO_OUT;
+}
+
+/* drive the GPIO signal to state */
+
+static inline void scx200_gpio_set(int index, int state) {
+	__SCx200_GPIO_BANK;
+	__SCx200_GPIO_IOADDR;
+	__SCx200_GPIO_SHADOW;
+	__SCx200_GPIO_INDEX;
+	if (state)
+		set_bit(index, shadow);
+	else
+		clear_bit(index, shadow);
+	__SCx200_GPIO_OUT;
+}
+
+/* toggle the GPIO signal */
+static inline void scx200_gpio_change(int index) {
+	__SCx200_GPIO_BANK;
+	__SCx200_GPIO_IOADDR;
+	__SCx200_GPIO_SHADOW;
+	__SCx200_GPIO_INDEX;
+	change_bit(index, shadow);
+	__SCx200_GPIO_OUT;
+}
+
+#undef __SCx200_GPIO_BANK
+#undef __SCx200_GPIO_IOADDR
+#undef __SCx200_GPIO_SHADOW
+#undef __SCx200_GPIO_INDEX
+#undef __SCx200_GPIO_OUT
+
+/*
+    Local variables:
+        compile-command: "make -C ../.. bzImage modules"
+        c-basic-offset: 8
+    End:
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/sonypi.h linux-2.4.21/include/linux/sonypi.h
--- linux-2.4.20/include/linux/sonypi.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/include/linux/sonypi.h	2002-12-18 18:58:07.000000000 +0000
@@ -1,7 +1,9 @@
 /* 
  * Sony Programmable I/O Control Device driver for VAIO
  *
- * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ * Copyright (C) 2001-2002 Stelian Pop <stelian@popies.net>
+ *
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
  *
  * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
  *
@@ -76,6 +78,21 @@
 #define SONYPI_EVENT_BLUETOOTH_ON		38
 #define SONYPI_EVENT_BLUETOOTH_OFF		39
 #define SONYPI_EVENT_HELP_PRESSED		40
+#define SONYPI_EVENT_FNKEY_ONLY			41
+#define SONYPI_EVENT_JOGDIAL_FAST_DOWN		42
+#define SONYPI_EVENT_JOGDIAL_FAST_UP		43
+#define SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED	44
+#define SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED	45
+#define SONYPI_EVENT_JOGDIAL_VFAST_DOWN		46
+#define SONYPI_EVENT_JOGDIAL_VFAST_UP		47
+#define SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED	48
+#define SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED	49
+#define SONYPI_EVENT_ZOOM_PRESSED		50
+#define SONYPI_EVENT_THUMBPHRASE_PRESSED	51
+#define SONYPI_EVENT_MEYE_FACE			52
+#define SONYPI_EVENT_MEYE_OPPOSITE		53
+#define SONYPI_EVENT_MEMORYSTICK_INSERT		54
+#define SONYPI_EVENT_MEMORYSTICK_EJECT		55
 
 /* get/set brightness */
 #define SONYPI_IOCGBRT		_IOR('v', 0, __u8)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/sysctl.h linux-2.4.21/include/linux/sysctl.h
--- linux-2.4.20/include/linux/sysctl.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/include/linux/sysctl.h	2002-12-18 18:58:01.000000000 +0000
@@ -124,6 +124,7 @@
 	KERN_CORE_USES_PID=52,		/* int: use core or core.%pid */
 	KERN_TAINTED=53,	/* int: various kernel tainted flags */
 	KERN_CADPID=54,		/* int: PID of the process to notify on CAD */
+ 	KERN_CORE_PATTERN=56,	/* string: pattern for core-files */
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/videodev.h linux-2.4.21/include/linux/videodev.h
--- linux-2.4.20/include/linux/videodev.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21/include/linux/videodev.h	2002-12-18 18:58:12.000000000 +0000
@@ -403,6 +403,8 @@
 #define VID_HARDWARE_PWC	31	/* Philips webcams */
 #define VID_HARDWARE_MEYE	32	/* Sony Vaio MotionEye cameras */
 #define VID_HARDWARE_CPIA2	33
+#define VID_HARDWARE_VICAM	34	/* ViCam, 3Com Homeconnect */
+#define VID_HARDWARE_SF16FMR2	35
 
 #endif /* __LINUX_VIDEODEV_H */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/wireless.h linux-2.4.21/include/linux/wireless.h
--- linux-2.4.20/include/linux/wireless.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/include/linux/wireless.h	2002-12-18 18:58:10.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * This file define a set of standard wireless extensions
  *
- * Version :	14	25.1.02
+ * Version :	15	12.7.02
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
  * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
@@ -80,7 +80,7 @@
  * (there is some stuff that will be added in the future...)
  * I just plan to increment with each new version.
  */
-#define WIRELESS_EXT	14
+#define WIRELESS_EXT	15
 
 /*
  * Changes :
@@ -153,17 +153,32 @@
  *	- Define additional specific event numbers
  *	- Add "addr" and "param" fields in union iwreq_data
  *	- AP scanning stuff (SIOCSIWSCAN and friends)
+ *
+ * V14 to V15
+ * ----------
+ *	- Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg
+ *	- Make struct iw_freq signed (both m & e), add explicit padding
+ *	- Add IWEVCUSTOM for driver specific event/scanning token
+ *	- Add IW_MAX_GET_SPY for driver returning a lot of addresses
+ *	- Add IW_TXPOW_RANGE for range of Tx Powers
+ *	- Add IWEVREGISTERED & IWEVEXPIRED events for Access Points
+ *	- Add IW_MODE_MONITOR for passive monitor
  */
 
 /**************************** CONSTANTS ****************************/
 
 /* -------------------------- IOCTL LIST -------------------------- */
 
-/* Basic operations */
+/* Wireless Identification */
 #define SIOCSIWCOMMIT	0x8B00		/* Commit pending changes to driver */
 #define SIOCGIWNAME	0x8B01		/* get name == wireless protocol */
-#define SIOCSIWNWID	0x8B02		/* set network id (the cell) */
-#define SIOCGIWNWID	0x8B03		/* get network id */
+/* SIOCGIWNAME is used to verify the presence of Wireless Extensions.
+ * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"...
+ * Don't put the name of your driver there, it's useless. */
+
+/* Basic operations */
+#define SIOCSIWNWID	0x8B02		/* set network id (pre-802.11) */
+#define SIOCGIWNWID	0x8B03		/* get network id (the cell) */
 #define SIOCSIWFREQ	0x8B04		/* set channel/frequency (Hz) */
 #define SIOCGIWFREQ	0x8B05		/* get channel/frequency (Hz) */
 #define SIOCSIWMODE	0x8B06		/* set operation mode */
@@ -178,16 +193,18 @@
 #define SIOCGIWPRIV	0x8B0D		/* get private ioctl interface info */
 #define SIOCSIWSTATS	0x8B0E		/* Unused */
 #define SIOCGIWSTATS	0x8B0F		/* Get /proc/net/wireless stats */
+/* SIOCGIWSTATS is strictly used between user space and the kernel, and
+ * is never passed to the driver (i.e. the driver will never see it). */
 
-/* Mobile IP support */
+/* Mobile IP support (statistics per MAC address) */
 #define SIOCSIWSPY	0x8B10		/* set spy addresses */
 #define SIOCGIWSPY	0x8B11		/* get spy info (quality of link) */
 
 /* Access Point manipulation */
 #define SIOCSIWAP	0x8B14		/* set access point MAC addresses */
 #define SIOCGIWAP	0x8B15		/* get access point MAC addresses */
-#define SIOCGIWAPLIST	0x8B17		/* get list of access point in range */
-#define SIOCSIWSCAN	0x8B18		/* trigger scanning */
+#define SIOCGIWAPLIST	0x8B17		/* Deprecated in favor of scanning */
+#define SIOCSIWSCAN	0x8B18		/* trigger scanning (list cells) */
 #define SIOCGIWSCAN	0x8B19		/* get scanning results */
 
 /* 802.11 specific support */
@@ -197,9 +214,7 @@
 #define SIOCGIWNICKN	0x8B1D		/* get node name/nickname */
 /* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit
  * within the 'iwreq' structure, so we need to use the 'data' member to
- * point to a string in user space, like it is done for RANGE...
- * The "flags" member indicate if the ESSID is active or not (promiscuous).
- */
+ * point to a string in user space, like it is done for RANGE... */
 
 /* Other parameters useful in 802.11 and some other devices */
 #define SIOCSIWRATE	0x8B20		/* set default bit rate (bps) */
@@ -257,7 +272,10 @@
 /* Most events use the same identifier as ioctl requests */
 
 #define IWEVTXDROP	0x8C00		/* Packet dropped to excessive retry */
-#define IWEVQUAL	0x8C01		/* Quality part of statistics */
+#define IWEVQUAL	0x8C01		/* Quality part of statistics (scan) */
+#define IWEVCUSTOM	0x8C02		/* Driver specific ascii string */
+#define IWEVREGISTERED	0x8C03		/* Discovered a new node (AP mode) */
+#define IWEVEXPIRED	0x8C04		/* Expired a node (AP mode) */
 
 #define IWEVFIRST	0x8C00
 
@@ -273,7 +291,8 @@
 #define IW_PRIV_TYPE_BYTE	0x1000	/* Char as number */
 #define IW_PRIV_TYPE_CHAR	0x2000	/* Char as character */
 #define IW_PRIV_TYPE_INT	0x4000	/* 32 bits int */
-#define IW_PRIV_TYPE_FLOAT	0x5000
+#define IW_PRIV_TYPE_FLOAT	0x5000	/* struct iw_freq */
+#define IW_PRIV_TYPE_ADDR	0x6000	/* struct sockaddr */
 
 #define IW_PRIV_SIZE_FIXED	0x0800	/* Variable or fixed nuber of args */
 
@@ -297,13 +316,16 @@
 
 /* Maximum tx powers in the range struct */
 #define IW_MAX_TXPOWER		8
+/* Note : if you more than 8 TXPowers, just set the max and min or
+ * a few of them in the struct iw_range. */
 
 /* Maximum of address that you may set with SPY */
-#define IW_MAX_SPY		8
+#define IW_MAX_SPY		8	/* set */
+#define IW_MAX_GET_SPY		64	/* get */
 
 /* Maximum of address that you may get in the
    list of access points in range */
-#define IW_MAX_AP		8
+#define IW_MAX_AP		64
 
 /* Maximum size of the ESSID and NICKN strings */
 #define IW_ESSID_MAX_SIZE	32
@@ -315,6 +337,7 @@
 #define IW_MODE_MASTER	3	/* Synchronisation master or Access Point */
 #define IW_MODE_REPEAT	4	/* Wireless Repeater (forwarder) */
 #define IW_MODE_SECOND	5	/* Secondary master/repeater (backup) */
+#define IW_MODE_MONITOR	6	/* Passive monitor (listen only) */
 
 /* Maximum number of size of encoding token available
  * they are listed in the range structure */
@@ -350,8 +373,10 @@
 #define IW_POWER_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
 
 /* Transmit Power flags available */
+#define IW_TXPOW_TYPE		0x00FF	/* Type of value */
 #define IW_TXPOW_DBM		0x0000	/* Value is in dBm */
 #define IW_TXPOW_MWATT		0x0001	/* Value is in mW */
+#define IW_TXPOW_RANGE		0x1000	/* Range of value between min/max */
 
 /* Retry limits and lifetime flags available */
 #define IW_RETRY_ON		0x0000	/* No details... */
@@ -376,6 +401,9 @@
 /* Maximum size of returned data */
 #define IW_SCAN_MAX_DATA	4096	/* In bytes */
 
+/* Max number of char in custom event - use multiple of them if needed */
+#define IW_CUSTOM_MAX		256	/* In bytes */
+
 /****************************** TYPES ******************************/
 
 /* --------------------------- SUBTYPES --------------------------- */
@@ -411,9 +439,10 @@
  */
 struct	iw_freq
 {
-	__u32		m;		/* Mantissa */
-	__u16		e;		/* Exponent */
+	__s32		m;		/* Mantissa */
+	__s16		e;		/* Exponent */
 	__u8		i;		/* List index (when in range struct) */
+	__u8		pad;		/* Unused - just for alignement */
 };
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/net/bluetooth/hci.h linux-2.4.21/include/net/bluetooth/hci.h
--- linux-2.4.20/include/net/bluetooth/hci.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/include/net/bluetooth/hci.h	2002-12-18 18:58:06.000000000 +0000
@@ -39,6 +39,8 @@
 #define HCI_DEV_UNREG   2
 #define HCI_DEV_UP	3
 #define HCI_DEV_DOWN	4
+#define HCI_DEV_SUSPEND	5
+#define HCI_DEV_RESUME	6
 
 /* HCI device types */
 #define HCI_VHCI	0
@@ -46,6 +48,7 @@
 #define HCI_PCCARD	2
 #define HCI_UART 	3
 #define HCI_RS232 	4
+#define HCI_PCI		5
 
 /* HCI device flags */
 enum {
@@ -542,7 +545,7 @@
 	bdaddr_t bdaddr;
 	__u8     role;
 } __attribute__ ((packed)) evt_role_change;
-#define EVT_ROLE_CHANGE_SIZE 1
+#define EVT_ROLE_CHANGE_SIZE 8
 
 #define EVT_PIN_CODE_REQ        0x16
 typedef struct {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/net/bluetooth/hci_core.h linux-2.4.21/include/net/bluetooth/hci_core.h
--- linux-2.4.20/include/net/bluetooth/hci_core.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/include/net/bluetooth/hci_core.h	2002-12-18 18:58:09.000000000 +0000
@@ -302,6 +302,8 @@
 struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
 int hci_register_dev(struct hci_dev *hdev);
 int hci_unregister_dev(struct hci_dev *hdev);
+int hci_suspend_dev(struct hci_dev *hdev);
+int hci_resume_dev(struct hci_dev *hdev);
 int hci_dev_open(__u16 dev);
 int hci_dev_close(__u16 dev);
 int hci_dev_reset(__u16 dev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/net/bluetooth/rfcomm.h linux-2.4.21/include/net/bluetooth/rfcomm.h
--- linux-2.4.20/include/net/bluetooth/rfcomm.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/include/net/bluetooth/rfcomm.h	2002-12-18 18:58:02.000000000 +0000
@@ -0,0 +1,346 @@
+/* 
+   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
+   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
+   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/* 
+   RPN support    -    Dirk Husemann <hud@zurich.ibm.com>
+*/
+
+/*
+ * $Id: rfcomm.h,v 1.31 2002/10/18 20:12:11 maxk Exp $
+ */
+
+#ifndef __RFCOMM_H
+#define __RFCOMM_H
+
+#define RFCOMM_PSM 3
+
+#define RFCOMM_CONN_TIMEOUT (HZ * 30)
+#define RFCOMM_DISC_TIMEOUT (HZ * 20)
+
+#define RFCOMM_DEFAULT_MTU	127
+#define RFCOMM_DEFAULT_CREDITS	7
+
+#define RFCOMM_MAX_L2CAP_MTU	1024
+#define RFCOMM_MAX_CREDITS	40
+
+#define RFCOMM_SKB_HEAD_RESERVE	8
+#define RFCOMM_SKB_TAIL_RESERVE	2
+#define RFCOMM_SKB_RESERVE	(RFCOMM_SKB_HEAD_RESERVE + RFCOMM_SKB_TAIL_RESERVE)
+
+#define RFCOMM_SABM	0x2f
+#define RFCOMM_DISC	0x43
+#define RFCOMM_UA	0x63
+#define RFCOMM_DM	0x0f
+#define RFCOMM_UIH	0xef
+
+#define RFCOMM_TEST	0x08
+#define RFCOMM_FCON	0x28
+#define RFCOMM_FCOFF	0x18
+#define RFCOMM_MSC	0x38
+#define RFCOMM_RPN	0x24
+#define RFCOMM_RLS	0x14
+#define RFCOMM_PN	0x20
+#define RFCOMM_NSC	0x04
+
+#define RFCOMM_V24_FC	0x02
+#define RFCOMM_V24_RTC	0x04
+#define RFCOMM_V24_RTR	0x08
+#define RFCOMM_V24_IC	0x40
+#define RFCOMM_V24_DV	0x80
+
+#define RFCOMM_RPN_BR_2400	0x0
+#define RFCOMM_RPN_BR_4800	0x1
+#define RFCOMM_RPN_BR_7200	0x2
+#define RFCOMM_RPN_BR_9600	0x3
+#define RFCOMM_RPN_BR_19200	0x4
+#define RFCOMM_RPN_BR_38400	0x5
+#define RFCOMM_RPN_BR_57600	0x6
+#define RFCOMM_RPN_BR_115200	0x7
+#define RFCOMM_RPN_BR_230400	0x8
+
+#define RFCOMM_RPN_DATA_5	0x0
+#define RFCOMM_RPN_DATA_6	0x1
+#define RFCOMM_RPN_DATA_7	0x2
+#define RFCOMM_RPN_DATA_8	0x3
+
+#define RFCOMM_RPN_STOP_1	0
+#define RFCOMM_RPN_STOP_15	1
+
+#define RFCOMM_RPN_PARITY_NONE	0x0
+#define RFCOMM_RPN_PARITY_ODD	0x4
+#define RFCOMM_RPN_PARITY_EVEN	0x5
+#define RFCOMM_RPN_PARITY_MARK	0x6
+#define RFCOMM_RPN_PARITY_SPACE	0x7
+
+#define RFCOMM_RPN_FLOW_NONE	0x00
+
+#define RFCOMM_RPN_XON_CHAR	0x11
+#define RFCOMM_RPN_XOFF_CHAR	0x13
+
+#define RFCOMM_RPN_PM_BITRATE		0x0001
+#define RFCOMM_RPN_PM_DATA		0x0002
+#define RFCOMM_RPN_PM_STOP		0x0004
+#define RFCOMM_RPN_PM_PARITY		0x0008
+#define RFCOMM_RPN_PM_PARITY_TYPE	0x0010
+#define RFCOMM_RPN_PM_XON		0x0020
+#define RFCOMM_RPN_PM_XOFF		0x0040
+#define RFCOMM_RPN_PM_FLOW		0x3F00
+
+#define RFCOMM_RPN_PM_ALL		0x3F7F
+
+struct rfcomm_hdr {
+	u8 addr;
+	u8 ctrl;
+	u8 len;    // Actual size can be 2 bytes
+} __attribute__ ((packed));
+
+struct rfcomm_cmd {
+	u8 addr;
+	u8 ctrl;
+	u8 len;
+	u8 fcs;
+} __attribute__ ((packed));
+
+struct rfcomm_mcc {
+	u8 type;
+	u8 len;
+} __attribute__ ((packed));
+
+struct rfcomm_pn {
+	u8  dlci;
+	u8  flow_ctrl;
+	u8  priority;
+	u8  ack_timer;
+	u16 mtu;
+	u8  max_retrans;
+	u8  credits;
+} __attribute__ ((packed));
+
+struct rfcomm_rpn {
+	u8  dlci;
+	u8  bit_rate;
+	u8  line_settings;
+	u8  flow_ctrl;
+	u8  xon_char;
+	u8  xoff_char;
+	u16 param_mask;
+} __attribute__ ((packed));
+
+struct rfcomm_msc {
+	u8  dlci;
+	u8  v24_sig;
+} __attribute__ ((packed));
+
+/* ---- Core structures, flags etc ---- */
+
+struct rfcomm_session {
+	struct list_head list;
+	struct socket   *sock;
+	unsigned long    state;
+	unsigned long    flags;
+	atomic_t         refcnt;
+	int              initiator;
+
+	/* Default DLC parameters */
+	uint   mtu;
+	uint   credits;
+
+	struct list_head dlcs;
+};
+
+struct rfcomm_dlc {
+	struct list_head      list;
+	struct rfcomm_session *session;
+	struct sk_buff_head   tx_queue;
+	struct timer_list     timer;
+
+	spinlock_t    lock;
+	unsigned long state;
+	unsigned long flags;
+	atomic_t      refcnt;
+	u8            dlci;
+	u8            addr;
+
+	uint          mtu;
+	u8            v24_sig;
+
+	uint          credits;
+	uint          rx_credits;
+	uint          tx_credits;
+
+	void          *owner;
+
+	void (*data_ready)(struct rfcomm_dlc *d, struct sk_buff *skb);
+	void (*state_change)(struct rfcomm_dlc *d, int err);
+	void (*modem_status)(struct rfcomm_dlc *d, u8 v24_sig);
+};
+
+/* DLC and session flags */
+#define RFCOMM_RX_THROTTLED 0
+#define RFCOMM_TX_THROTTLED 1
+#define RFCOMM_MSC_PENDING  2
+#define RFCOMM_TIMED_OUT    3
+
+/* Scheduling flags and events */
+#define RFCOMM_SCHED_STATE  0
+#define RFCOMM_SCHED_RX     1
+#define RFCOMM_SCHED_TX     2
+#define RFCOMM_SCHED_TIMEO  3
+#define RFCOMM_SCHED_WAKEUP 31
+
+extern struct task_struct *rfcomm_thread;
+extern unsigned long rfcomm_event;
+
+static inline void rfcomm_schedule(uint event)
+{
+	if (!rfcomm_thread)
+		return;
+
+	if (!test_and_set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event))
+		wake_up_process(rfcomm_thread);
+}
+
+extern struct semaphore rfcomm_sem;
+#define rfcomm_lock()	down(&rfcomm_sem);
+#define rfcomm_unlock()	up(&rfcomm_sem);
+
+/* ---- RFCOMM DLCs (channels) ---- */
+struct rfcomm_dlc *rfcomm_dlc_alloc(int prio);
+void rfcomm_dlc_free(struct rfcomm_dlc *d);
+int  rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel);
+int  rfcomm_dlc_close(struct rfcomm_dlc *d, int reason);
+int  rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb);
+int  rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig);
+int  rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig);
+
+#define rfcomm_dlc_lock(d)	spin_lock(&d->lock)
+#define rfcomm_dlc_unlock(d)	spin_unlock(&d->lock)
+
+static inline void rfcomm_dlc_hold(struct rfcomm_dlc *d)
+{
+	atomic_inc(&d->refcnt);
+}
+
+static inline void rfcomm_dlc_put(struct rfcomm_dlc *d)
+{
+	if (atomic_dec_and_test(&d->refcnt))
+		rfcomm_dlc_free(d);
+}
+
+extern void FASTCALL(__rfcomm_dlc_throttle(struct rfcomm_dlc *d));
+extern void FASTCALL(__rfcomm_dlc_unthrottle(struct rfcomm_dlc *d));
+
+static inline void rfcomm_dlc_throttle(struct rfcomm_dlc *d)
+{
+	if (!test_and_set_bit(RFCOMM_RX_THROTTLED, &d->flags))
+		__rfcomm_dlc_throttle(d);
+}
+
+static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
+{
+	if (test_and_clear_bit(RFCOMM_RX_THROTTLED, &d->flags))
+		__rfcomm_dlc_unthrottle(d);
+}
+
+/* ---- RFCOMM sessions ---- */
+struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state);
+struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst);
+struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err);
+void   rfcomm_session_del(struct rfcomm_session *s);
+void   rfcomm_session_close(struct rfcomm_session *s, int err);
+void   rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst);
+
+static inline void rfcomm_session_hold(struct rfcomm_session *s)
+{
+	atomic_inc(&s->refcnt);
+}
+
+static inline void rfcomm_session_put(struct rfcomm_session *s)
+{
+	if (atomic_dec_and_test(&s->refcnt))
+		rfcomm_session_del(s);
+}
+
+/* ---- RFCOMM chechsum ---- */
+extern u8 rfcomm_crc_table[];
+
+/* ---- RFCOMM sockets ---- */
+struct sockaddr_rc {
+	sa_family_t rc_family;
+	bdaddr_t    rc_bdaddr;
+	u8          rc_channel;
+};
+
+#define rfcomm_pi(sk)	((struct rfcomm_pinfo *) &sk->tp_pinfo)
+
+struct rfcomm_pinfo {
+	struct rfcomm_dlc *dlc;
+	u8 channel;
+};
+
+int  rfcomm_init_sockets(void);
+void rfcomm_cleanup_sockets(void);
+
+int  rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d);
+
+/* ---- RFCOMM TTY ---- */
+#define RFCOMM_MAX_DEV  256
+
+#define RFCOMMCREATEDEV		_IOW('R', 200, int)
+#define RFCOMMRELEASEDEV	_IOW('R', 201, int)
+#define RFCOMMGETDEVLIST	_IOR('R', 210, int)
+#define RFCOMMGETDEVINFO	_IOR('R', 211, int)
+#define RFCOMMSTEALDLC		_IOW('R', 220, int)
+
+#define RFCOMM_REUSE_DLC	0
+#define RFCOMM_RELEASE_ONHUP	1
+#define RFCOMM_HANGUP_NOW	2
+#define RFCOMM_TTY_ATTACHED	3
+
+struct rfcomm_dev_req {
+	s16      dev_id;
+	u32      flags;
+	bdaddr_t src;
+	bdaddr_t dst;
+	u8       channel;
+};
+
+struct rfcomm_dev_info {
+	s16      id;
+	u32      flags;
+	u16      state;
+	bdaddr_t src;
+	bdaddr_t dst;
+	u8       channel;
+};
+
+struct rfcomm_dev_list_req {
+	u16      dev_num;
+	struct   rfcomm_dev_info dev_info[0];
+};
+
+int  rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg);
+int  rfcomm_init_ttys(void);
+void rfcomm_cleanup_ttys(void);
+
+#endif /* __RFCOMM_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/net/irda/irlap.h linux-2.4.21/include/net/irda/irlap.h
--- linux-2.4.20/include/net/irda/irlap.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21/include/net/irda/irlap.h	2002-12-18 18:58:07.000000000 +0000
@@ -31,8 +31,6 @@
 #include <linux/types.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/ppp_defs.h>
-#include <linux/ppp-comp.h>
 #include <linux/timer.h>
 
 #include <net/irda/irlap_event.h>
@@ -216,4 +214,24 @@
 #define IRLAP_GET_HEADER_SIZE(self) (LAP_MAX_HEADER)
 #define IRLAP_GET_TX_QUEUE_LEN(self) skb_queue_len(&self->txq)
 
+/* Return TRUE if the node is in primary mode (i.e. master)
+ * - Jean II */
+static inline int irlap_is_primary(struct irlap_cb *self)
+{
+	int ret;
+	switch(self->state) {
+	case LAP_XMIT_P:
+	case LAP_NRM_P:
+		ret = 1;
+		break;
+	case LAP_XMIT_S:
+	case LAP_NRM_S:
+		ret = 0;
+		break;
+	default:
+		ret = -1;
+	}
+	return(ret);
+}
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/net/irda/irlmp.h linux-2.4.21/include/net/irda/irlmp.h
--- linux-2.4.20/include/net/irda/irlmp.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/include/net/irda/irlmp.h	2002-12-18 18:58:01.000000000 +0000
@@ -274,6 +274,8 @@
 	self->dlsap_sel = LSAP_ANY;
 	self->lap = NULL;
 	self->lsap_state = LSAP_DISCONNECTED;
+	/* Started when we received the LM_CONNECT_INDICATION */
+	del_timer(&self->watchdog_timer);
 }
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/net/irda/irttp.h linux-2.4.21/include/net/irda/irttp.h
--- linux-2.4.20/include/net/irda/irttp.h	2001-12-21 17:42:04.000000000 +0000
+++ linux-2.4.21/include/net/irda/irttp.h	2002-12-18 18:58:05.000000000 +0000
@@ -42,11 +42,48 @@
 #define TTP_PARAMETERS         0x80
 #define TTP_MORE               0x80
 
-#define DEFAULT_INITIAL_CREDIT 14
+/* Transmission queue sizes */
+/* Worst case scenario, two window of data - Jean II */
+#define TTP_TX_MAX_QUEUE	14
+/* We need to keep at least 5 frames to make sure that we can refill
+ * appropriately the LAP layer. LAP keeps only two buffers, and we need
+ * to have 7 to make a full window - Jean II */
+#define TTP_TX_LOW_THRESHOLD	5
+/* Most clients are synchronous with respect to flow control, so we can
+ * keep a low number of Tx buffers in TTP - Jean II */
+#define TTP_TX_HIGH_THRESHOLD	7
+
+/* Receive queue sizes */
+/* Minimum of credit that the peer should hold.
+ * If the peer has less credits than 9 frames, we will explicitely send
+ * him some credits (through irttp_give_credit() and a specific frame).
+ * Note that when we give credits it's likely that it won't be sent in
+ * this LAP window, but in the next one. So, we make sure that the peer
+ * has something to send while waiting for credits (one LAP window == 7
+ * + 1 frames while he process the credits). - Jean II */
+#define TTP_RX_MIN_CREDIT	8
+/* This is the default maximum number of credits held by the peer, so the
+ * default maximum number of frames he can send us before needing flow
+ * control answer from us (this may be negociated differently at TSAP setup).
+ * We want to minimise the number of times we have to explicitely send some
+ * credit to the peer, hoping we can piggyback it on the return data. In
+ * particular, it doesn't make sense for us to send credit more than once
+ * per LAP window.
+ * Moreover, giving credits has some latency, so we need strictly more than
+ * a LAP window, otherwise we may already have credits in our Tx queue.
+ * But on the other hand, we don't want to keep too many Rx buffer here
+ * before starting to flow control the other end, so make it exactly one
+ * LAP window + 1 + MIN_CREDITS. - Jean II */
+#define TTP_RX_DEFAULT_CREDIT	16
+/* Maximum number of credits we can allow the peer to have, and therefore
+ * maximum Rx queue size.
+ * Note that we try to deliver packets to the higher layer every time we
+ * receive something, so in normal mode the Rx queue will never contains
+ * more than one or two packets. - Jean II */
+#define TTP_RX_MAX_CREDIT	21
 
-#define TTP_LOW_THRESHOLD       4
-#define TTP_HIGH_THRESHOLD     10
-#define TTP_MAX_QUEUE          14
+/* What clients should use when calling ttp_open_tsap() */
+#define DEFAULT_INITIAL_CREDIT	TTP_RX_DEFAULT_CREDIT
 
 /* Some priorities for disconnect requests */
 #define P_NORMAL    0
@@ -90,7 +127,7 @@
 
 	struct net_device_stats stats;
 	struct timer_list todo_timer; 
-	
+
 	__u32 max_seg_size;     /* Max data that fit into an IrLAP frame */
 	__u8  max_header_size;
 
@@ -131,6 +168,7 @@
 void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow);
 void irttp_status_indication(void *instance,
 			     LINK_STATUS link, LOCK_STATUS lock);
+void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow);
 struct tsap_cb *irttp_dup(struct tsap_cb *self, void *instance);
 
 static __inline __u32 irttp_get_saddr(struct tsap_cb *self)
@@ -159,6 +197,18 @@
 	self->dtsap_sel = LSAP_ANY;
 }
 
+/* Return TRUE if the node is in primary mode (i.e. master)
+ * - Jean II */
+static inline int irttp_is_primary(struct tsap_cb *self)
+{
+	if ((self == NULL) ||
+	    (self->lsap == NULL) ||
+	    (self->lsap->lap == NULL) ||
+	    (self->lsap->lap->irlap == NULL))
+		return -2;
+	return(irlap_is_primary(self->lsap->lap->irlap));
+}
+
 extern struct irttp_cb *irttp;
 
 #endif /* IRTTP_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/net/iw_handler.h linux-2.4.21/include/net/iw_handler.h
--- linux-2.4.20/include/net/iw_handler.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/include/net/iw_handler.h	2002-12-18 18:58:07.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * This file define the new driver API for Wireless Extensions
  *
- * Version :	3	17.1.02
+ * Version :	4	21.6.02
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
  * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
@@ -206,7 +206,7 @@
  * will be needed...
  * I just plan to increment with each new version.
  */
-#define IW_HANDLER_VERSION	3
+#define IW_HANDLER_VERSION	4
 
 /*
  * Changes :
@@ -217,6 +217,9 @@
  *	- Add Wireless Event support :
  *		o wireless_send_event() prototype
  *		o iwe_stream_add_event/point() inline functions
+ * V3 to V4
+ * --------
+ *	- Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
  */
 
 /**************************** CONSTANTS ****************************/
@@ -233,10 +236,10 @@
 #define IW_HEADER_TYPE_CHAR	2	/* char [IFNAMSIZ] */
 #define IW_HEADER_TYPE_UINT	4	/* __u32 */
 #define IW_HEADER_TYPE_FREQ	5	/* struct iw_freq */
-#define IW_HEADER_TYPE_POINT	6	/* struct iw_point */
-#define IW_HEADER_TYPE_PARAM	7	/* struct iw_param */
-#define IW_HEADER_TYPE_ADDR	8	/* struct sockaddr */
-#define IW_HEADER_TYPE_QUAL	9	/* struct iw_quality */
+#define IW_HEADER_TYPE_ADDR	6	/* struct sockaddr */
+#define IW_HEADER_TYPE_POINT	8	/* struct iw_point */
+#define IW_HEADER_TYPE_PARAM	9	/* struct iw_param */
+#define IW_HEADER_TYPE_QUAL	10	/* struct iw_quality */
 
 /* Handling flags */
 /* Most are not implemented. I just use them as a reminder of some
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/pcmcia/ciscode.h linux-2.4.21/include/pcmcia/ciscode.h
--- linux-2.4.20/include/pcmcia/ciscode.h	2001-12-21 17:42:04.000000000 +0000
+++ linux-2.4.21/include/pcmcia/ciscode.h	2002-12-18 18:58:10.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * ciscode.h 1.48 2001/08/24 12:16:12
+ * ciscode.h 1.57 2002/11/03 20:38:14
  *
  * The contents of this file are subject to the Mozilla Public License
  * Version 1.1 (the "License"); you may not use this file except in
@@ -60,6 +60,10 @@
 #define PRODID_INTEL_DUAL_RS232		0x0301
 #define PRODID_INTEL_2PLUS		0x8422
 
+#define MANFID_KME			0x0032
+#define PRODID_KME_KXLC005_A		0x0704
+#define PRODID_KME_KXLC005_B		0x2904
+
 #define MANFID_LINKSYS			0x0143
 #define PRODID_LINKSYS_PCMLM28		0xc0ab
 #define PRODID_LINKSYS_3400		0x3341
@@ -94,6 +98,8 @@
 #define PRODID_OSITECH_JACK_336		0x0007
 #define PRODID_OSITECH_SEVEN		0x0008
 
+#define MANFID_OXSEMI			0x0279
+
 #define MANFID_PIONEER			0x000b
 
 #define MANFID_PSION			0x016c
@@ -103,6 +109,7 @@
 #define PRODID_QUATECH_SPP100		0x0003
 #define PRODID_QUATECH_DUAL_RS232	0x0012
 #define PRODID_QUATECH_DUAL_RS232_D1	0x0007
+#define PRODID_QUATECH_DUAL_RS232_D2	0x0052
 #define PRODID_QUATECH_QUAD_RS232	0x001b
 #define PRODID_QUATECH_DUAL_RS422	0x000e
 #define PRODID_QUATECH_QUAD_RS422	0x0045
@@ -120,9 +127,12 @@
 
 #define MANFID_TDK			0x0105
 #define PRODID_TDK_CF010		0x0900
+#define PRODID_TDK_GN3410		0x4815
 
 #define MANFID_TOSHIBA			0x0098
 
+#define MANFID_UNGERMANN		0x02c0
+
 #define MANFID_XIRCOM			0x0105
 
 #endif /* _LINUX_CISCODE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/kernel/ksyms.c linux-2.4.21/kernel/ksyms.c
--- linux-2.4.20/kernel/ksyms.c	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/kernel/ksyms.c	2002-12-18 18:58:01.000000000 +0000
@@ -142,6 +142,7 @@
 EXPORT_SYMBOL(iunique);
 EXPORT_SYMBOL(iget4);
 EXPORT_SYMBOL(iput);
+EXPORT_SYMBOL(inode_init_once);
 EXPORT_SYMBOL(force_delete);
 EXPORT_SYMBOL(follow_up);
 EXPORT_SYMBOL(follow_down);
@@ -523,11 +524,10 @@
 EXPORT_SYMBOL(init_special_inode);
 EXPORT_SYMBOL(read_ahead);
 EXPORT_SYMBOL(get_hash_table);
-EXPORT_SYMBOL(get_empty_inode);
+EXPORT_SYMBOL(new_inode);
 EXPORT_SYMBOL(insert_inode_hash);
 EXPORT_SYMBOL(remove_inode_hash);
-EXPORT_SYMBOL(buffer_insert_inode_queue);
-EXPORT_SYMBOL(buffer_insert_inode_data_queue);
+EXPORT_SYMBOL(buffer_insert_list);
 EXPORT_SYMBOL(make_bad_inode);
 EXPORT_SYMBOL(is_bad_inode);
 EXPORT_SYMBOL(event);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/kernel/module.c linux-2.4.21/kernel/module.c
--- linux-2.4.20/kernel/module.c	2001-11-11 19:23:14.000000000 +0000
+++ linux-2.4.21/kernel/module.c	2002-12-18 18:58:04.000000000 +0000
@@ -303,7 +303,7 @@
 		error = namelen;
 		goto err0;
 	}
-	if (size < sizeof(struct module)+namelen) {
+	if (size < sizeof(struct module)+namelen+1) {
 		error = -EINVAL;
 		goto err1;
 	}
@@ -482,10 +482,10 @@
 		error = n_namelen;
 		goto err2;
 	}
-	if (namelen != n_namelen || strcmp(n_name, mod_tmp.name) != 0) {
+	if (namelen != n_namelen || strcmp(n_name, name_tmp) != 0) {
 		printk(KERN_ERR "init_module: changed module name to "
 				"`%s' from `%s'\n",
-		       n_name, mod_tmp.name);
+		       n_name, name_tmp);
 		goto err3;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/kernel/signal.c linux-2.4.21/kernel/signal.c
--- linux-2.4.20/kernel/signal.c	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/kernel/signal.c	2002-12-18 18:58:07.000000000 +0000
@@ -20,6 +20,14 @@
  * SLAB caches for signal bits.
  */
 
+#define DEBUG_SIG 0
+
+#if DEBUG_SIG
+#define SIG_SLAB_DEBUG	(SLAB_DEBUG_FREE | SLAB_RED_ZONE /* | SLAB_POISON */)
+#else
+#define SIG_SLAB_DEBUG	0
+#endif
+
 static kmem_cache_t *sigqueue_cachep;
 
 atomic_t nr_queued_signals;
@@ -31,7 +39,7 @@
 		kmem_cache_create("sigqueue",
 				  sizeof(struct sigqueue),
 				  __alignof__(struct sigqueue),
-				  0, NULL, NULL);
+				  SIG_SLAB_DEBUG, NULL, NULL);
 	if (!sigqueue_cachep)
 		panic("signals_init(): cannot create sigqueue SLAB cache");
 }
@@ -257,6 +265,11 @@
 {
 	int sig = 0;
 
+#if DEBUG_SIG
+printk("SIG dequeue (%s:%d): %d ", current->comm, current->pid,
+	signal_pending(current));
+#endif
+
 	sig = next_signal(current, mask);
 	if (sig) {
 		if (current->notifier) {
@@ -276,6 +289,10 @@
 	}
 	recalc_sigpending(current);
 
+#if DEBUG_SIG
+printk(" %d -> %d\n", signal_pending(current), sig);
+#endif
+
 	return sig;
 }
 
@@ -518,6 +535,11 @@
 	unsigned long flags;
 	int ret;
 
+
+#if DEBUG_SIG
+printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
+#endif
+
 	ret = -EINVAL;
 	if (sig < 0 || sig > _NSIG)
 		goto out_nolock;
@@ -552,6 +574,9 @@
 out:
 	spin_unlock_irqrestore(&t->sigmask_lock, flags);
 out_nolock:
+#if DEBUG_SIG
+printk(" %d -> %d\n", signal_pending(t), ret);
+#endif
 
 	return ret;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/mm/slab.c linux-2.4.21/mm/slab.c
--- linux-2.4.20/mm/slab.c	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/mm/slab.c	2002-12-18 18:58:05.000000000 +0000
@@ -989,6 +989,8 @@
  * cache being allocated each time a module is loaded and unloaded, if the
  * module doesn't have persistent in-kernel storage across loads and unloads.
  *
+ * The cache must be empty before calling this function.
+ *
  * The caller must guarantee that noone will allocate memory from the cache
  * during the kmem_cache_destroy().
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/802/tr.c linux-2.4.21/net/802/tr.c
--- linux-2.4.20/net/802/tr.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21/net/802/tr.c	2002-12-18 18:58:03.000000000 +0000
@@ -93,10 +93,10 @@
 	int hdr_len;
 
 	/* 
-	 * Add the 802.2 SNAP header if IP as the IPv4 code calls  
+	 * Add the 802.2 SNAP header if IP as the IPv4/IPv6 code calls  
 	 * dev->hard_header directly.
 	 */
-	if (type == ETH_P_IP || type == ETH_P_ARP)
+	if (type == ETH_P_IP || type == ETH_P_IPV6 || type == ETH_P_ARP)
 	{
 		struct trllc *trllc=(struct trllc *)(trh+1);
 
@@ -218,6 +218,7 @@
 
 	if (trllc->dsap == EXTENDED_SAP &&
 	    (trllc->ethertype == ntohs(ETH_P_IP) ||
+	     trllc->ethertype == ntohs(ETH_P_IPV6) ||
 	     trllc->ethertype == ntohs(ETH_P_ARP)))
 	{
 		skb_pull(skb, sizeof(struct trllc));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/Config.in linux-2.4.21/net/bluetooth/Config.in
--- linux-2.4.20/net/bluetooth/Config.in	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/bluetooth/Config.in	2002-12-18 18:58:10.000000000 +0000
@@ -1,8 +1,9 @@
 #
-# Bluetooth configuration
+# Bluetooth subsystem configuration
 #
 
 if [ "$CONFIG_NET" != "n" ]; then
+
    mainmenu_option next_comment
    comment 'Bluetooth support'
    dep_tristate 'Bluetooth subsystem support' CONFIG_BLUEZ $CONFIG_NET
@@ -10,9 +11,11 @@
    if [ "$CONFIG_BLUEZ" != "n" ]; then
       dep_tristate 'L2CAP protocol support' CONFIG_BLUEZ_L2CAP $CONFIG_BLUEZ
       dep_tristate 'SCO links support' CONFIG_BLUEZ_SCO $CONFIG_BLUEZ
+      source net/bluetooth/rfcomm/Config.in
       source net/bluetooth/bnep/Config.in
       source drivers/bluetooth/Config.in
    fi
+
    endmenu
 fi
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/Makefile linux-2.4.21/net/bluetooth/Makefile
--- linux-2.4.20/net/bluetooth/Makefile	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/bluetooth/Makefile	2002-12-18 18:58:04.000000000 +0000
@@ -1,6 +1,7 @@
 #
-# Makefile for the Bluetooth subsystem
+# Makefile for the Linux Bluetooth subsystem
 #
+
 O_TARGET    := bluetooth.o
 
 list-multi  := bluez.o
@@ -12,8 +13,13 @@
 obj-$(CONFIG_BLUEZ_L2CAP) += l2cap.o
 obj-$(CONFIG_BLUEZ_SCO) += sco.o
 
+subdir-$(CONFIG_BLUEZ_RFCOMM) += rfcomm
 subdir-$(CONFIG_BLUEZ_BNEP) += bnep
 
+ifeq ($(CONFIG_BLUEZ_RFCOMM),y)
+obj-y += rfcomm/rfcomm.o
+endif
+
 ifeq ($(CONFIG_BLUEZ_BNEP),y)
 obj-y += bnep/bnep.o
 endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/bnep/Config.in linux-2.4.21/net/bluetooth/bnep/Config.in
--- linux-2.4.20/net/bluetooth/bnep/Config.in	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/bluetooth/bnep/Config.in	2002-12-18 18:58:11.000000000 +0000
@@ -1,6 +1,11 @@
+#
+# Bluetooth BNEP layer configuration
+#
 
 dep_tristate 'BNEP protocol support' CONFIG_BLUEZ_BNEP $CONFIG_BLUEZ_L2CAP
+
 if [ "$CONFIG_BLUEZ_BNEP" != "n" ]; then
-   bool '  Multicast filter support' CONFIG_BNEP_MC_FILTER
-   bool '  Protocol filter support'  CONFIG_BNEP_PROTO_FILTER
+   bool '  Multicast filter support' CONFIG_BLUEZ_BNEP_MC_FILTER
+   bool '  Protocol filter support'  CONFIG_BLUEZ_BNEP_PROTO_FILTER
 fi
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/bnep/Makefile linux-2.4.21/net/bluetooth/bnep/Makefile
--- linux-2.4.20/net/bluetooth/bnep/Makefile	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/bluetooth/bnep/Makefile	2002-12-18 18:58:10.000000000 +0000
@@ -1,5 +1,5 @@
 #
-# Makefile for BNEP protocol
+# Makefile for the Linux Bluetooth BNEP layer
 #
 
 O_TARGET := bnep.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/bnep/core.c linux-2.4.21/net/bluetooth/bnep/core.c
--- linux-2.4.20/net/bluetooth/bnep/core.c	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/bluetooth/bnep/core.c	2002-12-18 18:58:12.000000000 +0000
@@ -58,17 +58,17 @@
 
 #include "bnep.h"
 
-#ifndef CONFIG_BNEP_DEBUG
+#ifndef CONFIG_BLUEZ_BNEP_DEBUG
 #undef  BT_DBG
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "1.0"
+#define VERSION "1.1"
 
 static LIST_HEAD(bnep_session_list);
 static DECLARE_RWSEM(bnep_session_sem);
 
-static struct bnep_session *__bnep_get_session(__u8 *dst)
+static struct bnep_session *__bnep_get_session(u8 *dst)
 {
 	struct bnep_session *s;
 	struct list_head *p;
@@ -104,7 +104,7 @@
 	return sock->ops->sendmsg(sock, &s->msg, len, NULL);
 }
 
-static int bnep_send_rsp(struct bnep_session *s, __u8 ctrl, __u16 resp)
+static int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp)
 {
 	struct bnep_control_rsp rsp;
 	rsp.type = BNEP_CONTROL;
@@ -113,23 +113,22 @@
 	return bnep_send(s, &rsp, sizeof(rsp));
 }
 
-static int bnep_ctrl_set_netfilter(struct bnep_session *s, struct sk_buff *skb)
+static int bnep_ctrl_set_netfilter(struct bnep_session *s, u16 *data, int len)
 {
-	__u16 *data;
 	int n;
-	
-	data = (void *) skb->data;
-	if (!skb_pull(skb, 2))
+
+	if (len < 2)
 		return -EILSEQ;
+	
 	n = ntohs(get_unaligned(data));
+	data++; len -= 2;
 
-	data = (void *) skb->data;
-	if (!skb_pull(skb, n))
+	if (len < n)
 		return -EILSEQ;
 
 	BT_DBG("filter len %d", n);
 
-#ifdef CONFIG_BNEP_PROTO_FILTER
+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
 	n /= 4;
 	if (n <= BNEP_MAX_PROTO_FILTERS) {
 		struct bnep_proto_filter *f = s->proto_filter;
@@ -155,23 +154,22 @@
 	return 0;
 }
 
-static int bnep_ctrl_set_mcfilter(struct bnep_session *s, struct sk_buff *skb)
+static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
 {
-	u8 *data;
 	int n;
-	
-	data = (void *) skb->data;
-	if (!skb_pull(skb, 2))
+
+	if (len < 2)
 		return -EILSEQ;
-	n = ntohs(get_unaligned((u16 *) data));
+	
+	n = ntohs(get_unaligned((u16 *) data)); 
+	data += 2; len -= 2;
 
-	data = (void *) skb->data;
-	if (!skb_pull(skb, n))
+	if (len < n)
 		return -EILSEQ;
 
 	BT_DBG("filter len %d", n);
 
-#ifdef CONFIG_BNEP_MC_FILTER
+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
 	n /= (ETH_ALEN * 2);
 
 	if (n > 0) {
@@ -210,11 +208,12 @@
 	return 0;
 }
 
-static int bnep_rx_control(struct bnep_session *s, struct sk_buff *skb)
+static int bnep_rx_control(struct bnep_session *s, void *data, int len)
 {
+	u8  cmd = *(u8 *)data;
 	int err = 0;
-	__u8 cmd = *(__u8 *) skb->data;
-	skb_pull(skb, 1);
+
+	data++; len--;
 	
 	switch (cmd) {
 	case BNEP_CMD_NOT_UNDERSTOOD:
@@ -226,15 +225,15 @@
 		break;
 		
 	case BNEP_FILTER_NET_TYPE_SET:
-		err = bnep_ctrl_set_netfilter(s, skb);
+		err = bnep_ctrl_set_netfilter(s, data, len);
 		break;
 
 	case BNEP_FILTER_MULTI_ADDR_SET:
-		err = bnep_ctrl_set_mcfilter(s, skb);
+		err = bnep_ctrl_set_mcfilter(s, data, len);
 		break;
 
 	default: {
-			__u8 pkt[3];
+			u8 pkt[3];
 			pkt[0] = BNEP_CONTROL;
 			pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
 			pkt[2] = cmd;
@@ -262,13 +261,16 @@
 		
 		switch (h->type & BNEP_TYPE_MASK) {
 		case BNEP_EXT_CONTROL:
-			err = bnep_rx_control(s, skb);
+			bnep_rx_control(s, skb->data, skb->len);
 			break;
 
 		default:
-			/* Unknown extension */
-			if (!skb_pull(skb, h->len))
-				err = -EILSEQ;
+			/* Unknown extension, skip it. */
+			break;
+		}
+	
+		if (!skb_pull(skb, h->len)) {
+			err = -EILSEQ;
 			break;
 		}
 	} while (!err && (h->type & BNEP_EXT_HEADER));
@@ -276,7 +278,7 @@
 	return err;
 }
 
-static __u8 __bnep_rx_hlen[] = {
+static u8 __bnep_rx_hlen[] = {
 	ETH_HLEN,     /* BNEP_GENERAL */
 	0,            /* BNEP_CONTROL */
 	2,            /* BNEP_COMPRESSED */
@@ -289,18 +291,18 @@
 {
 	struct net_device *dev = &s->dev;
 	struct sk_buff *nskb;
-	__u8 type;
+	u8 type;
 
 	dev->last_rx = jiffies;
 	s->stats.rx_bytes += skb->len;
 
-	type = *(__u8 *) skb->data; skb_pull(skb, 1);
+	type = *(u8 *) skb->data; skb_pull(skb, 1);
 
 	if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES)
 		goto badframe;
 	
 	if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
-		bnep_rx_control(s, skb);
+		bnep_rx_control(s, skb->data, skb->len);
 		kfree_skb(skb);
 		return 0;
 	}
@@ -311,7 +313,7 @@
 	if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
 		goto badframe;
 
-	s->eh.h_proto = get_unaligned((__u16 *) (skb->data - 2));
+	s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2));
 
 	if (type & BNEP_EXT_HEADER) {
 		if (bnep_rx_extension(s, skb) < 0)
@@ -322,7 +324,7 @@
 	if (ntohs(s->eh.h_proto) == 0x8100) {
 		if (!skb_pull(skb, 4))
 			goto badframe;
-		s->eh.h_proto = get_unaligned((__u16 *) (skb->data - 2));
+		s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2));
 	}
 	
 	/* We have to alloc new skb and copy data here :(. Because original skb
@@ -344,7 +346,7 @@
 	case BNEP_COMPRESSED_SRC_ONLY:
 		memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
 		memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN);
-		put_unaligned(s->eh.h_proto, (__u16 *) __skb_put(nskb, 2));
+		put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2));
 		break;
 
 	case BNEP_COMPRESSED_DST_ONLY:
@@ -354,7 +356,7 @@
 
 	case BNEP_GENERAL:
 		memcpy(__skb_put(nskb, ETH_ALEN * 2), skb->mac.raw, ETH_ALEN * 2);
-		put_unaligned(s->eh.h_proto, (__u16 *) __skb_put(nskb, 2));
+		put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2));
 		break;
 	}
 
@@ -374,7 +376,7 @@
 	return 0;
 }
 
-static __u8 __bnep_tx_types[] = {
+static u8 __bnep_tx_types[] = {
 	BNEP_GENERAL,
 	BNEP_COMPRESSED_SRC_ONLY,
 	BNEP_COMPRESSED_DST_ONLY,
@@ -387,7 +389,7 @@
 	struct socket *sock = s->sock;
 	struct iovec iv[3];
 	int len = 0, il = 0;
-	__u8 type = 0;
+	u8 type = 0;
 
 	BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type);
 
@@ -507,7 +509,7 @@
 {
 	struct net_device *dev;
 	struct bnep_session *s, *ss;
-	__u8 dst[ETH_ALEN], src[ETH_ALEN];
+	u8 dst[ETH_ALEN], src[ETH_ALEN];
 	int err;
 
 	BT_DBG("");
@@ -535,6 +537,8 @@
 	else
 		strcpy(dev->name, "bnep%d");
 
+	memset(dev->broadcast, 0xff, ETH_ALEN);
+
 	/* This is rx header therefor addresses are swaped.
 	 * ie eh.h_dest is our local address. */
 	memcpy(s->eh.h_dest,   &src, ETH_ALEN);
@@ -546,12 +550,12 @@
 	
 	s->msg.msg_flags = MSG_NOSIGNAL;
 
-#ifdef CONFIG_BNEP_MC_FILTER
+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
 	/* Set default mc filter */
 	set_bit(bnep_mc_hash(dev->broadcast), &s->mc_filter);
 #endif
 	
-#ifdef CONFIG_BNEP_PROTO_FILTER
+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
 	/* Set default protocol filter */
 
 	/* (IPv4, ARP)  */
@@ -676,17 +680,14 @@
 
 static int __init bnep_init_module(void)
 {
-	BT_INFO("BNEP: BNEP2 ver %s\n"
-		"BNEP: Copyright (C) 2002 Inventel\n"
-		"BNEP: Written 2001,2002 by\n"
-		"BNEP: \tClement Moreau <clement.moreau@inventel.fr> "
-			"David Libault <david.libault@inventel.fr>\n"
-		"BNEP: Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>",
-			VERSION);
-
+	bnep_crc32_init();
 	bnep_sock_init();
 
-	bnep_crc32_init();
+	BT_INFO("BlueZ BNEP ver %s", VERSION);
+	BT_INFO("Copyright (C) 2001,2002 Inventel Systemes");
+	BT_INFO("Written 2001,2002 by Clement Moreau <clement.moreau@inventel.fr>");
+	BT_INFO("Written 2001,2002 by David Libault <david.libault@inventel.fr>");
+	BT_INFO("Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>");
 
 	return 0;
 }
@@ -694,13 +695,12 @@
 static void __exit bnep_cleanup_module(void)
 {
 	bnep_sock_cleanup();
-
 	bnep_crc32_cleanup();
 }
 
 module_init(bnep_init_module);
 module_exit(bnep_cleanup_module);
 
-MODULE_DESCRIPTION("BNEP2 ver " VERSION);
-MODULE_AUTHOR("David Libault <david.libault@inventel.fr> Maxim Krasnyanskiy <maxk@qualcomm.com>");
+MODULE_DESCRIPTION("BlueZ BNEP ver " VERSION);
+MODULE_AUTHOR("David Libault <david.libault@inventel.fr>, Maxim Krasnyanskiy <maxk@qualcomm.com>");
 MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/bnep/netdev.c linux-2.4.21/net/bluetooth/bnep/netdev.c
--- linux-2.4.20/net/bluetooth/bnep/netdev.c	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/bluetooth/bnep/netdev.c	2002-12-18 18:58:10.000000000 +0000
@@ -46,7 +46,7 @@
 
 #include "bnep.h"
 
-#ifndef CONFIG_BNEP_DEBUG
+#ifndef CONFIG_BLUEZ_BNEP_DEBUG
 #undef  BT_DBG
 #define BT_DBG( A... )
 #endif
@@ -73,7 +73,7 @@
 
 static void bnep_net_set_mc_list(struct net_device *dev)
 {
-#ifdef CONFIG_BNEP_MC_FILTER
+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
 	struct bnep_session *s = dev->priv;
 	struct sock *sk = s->sock->sk;
 	struct bnep_set_filter_req *r;
@@ -143,27 +143,31 @@
 	return -EINVAL;
 }
 
-#ifdef CONFIG_BNEP_MC_FILTER
+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
 static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
 {
 	struct ethhdr *eh = (void *) skb->data;
 
-	if ((eh->h_dest[0] & 1) && !test_bit(bnep_mc_hash(eh->h_dest), &s->mc_filter))
+	if ((eh->h_dest[0] & 1) && !test_bit(bnep_mc_hash(eh->h_dest), &s->mc_filter)) {
+		BT_DBG("BNEP: filtered skb %p, dst %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", skb, 
+				eh->h_dest[0], eh->h_dest[1], eh->h_dest[2],
+				eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]);
 		return 1;
+	}
 	return 0;
 }
 #endif
 
-#ifdef CONFIG_BNEP_PROTO_FILTER
+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
 /* Determine ether protocol. Based on eth_type_trans. */
-static inline __u16 bnep_net_eth_proto(struct sk_buff *skb)
+static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
 {
 	struct ethhdr *eh = (void *) skb->data;
 	
 	if (ntohs(eh->h_proto) >= 1536)
 		return eh->h_proto;
 		
-	if (get_unaligned((__u16 *) skb->data) == 0xFFFF)
+	if (get_unaligned((u16 *) skb->data) == 0xFFFF)
 		return htons(ETH_P_802_3);
 		
 	return htons(ETH_P_802_2);
@@ -171,7 +175,7 @@
 
 static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
 {
-	__u16 proto = bnep_net_eth_proto(skb);
+	u16 proto = bnep_net_eth_proto(skb);
 	struct bnep_proto_filter *f = s->proto_filter;
 	int i;
 	
@@ -192,14 +196,14 @@
 
 	BT_DBG("skb %p, dev %p", skb, dev);
 
-#ifdef CONFIG_BNEP_MC_FILTER
+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
 	if (bnep_net_mc_filter(skb, s)) {
 		kfree_skb(skb);
 		return 0;
 	}
 #endif
 	
-#ifdef CONFIG_BNEP_PROTO_FILTER
+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
 	if (bnep_net_proto_filter(skb, s)) {
 		kfree_skb(skb);
 		return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/bnep/sock.c linux-2.4.21/net/bluetooth/bnep/sock.c
--- linux-2.4.20/net/bluetooth/bnep/sock.c	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/bluetooth/bnep/sock.c	2002-12-18 18:58:02.000000000 +0000
@@ -50,7 +50,7 @@
 
 #include "bnep.h"
 
-#ifndef CONFIG_BNEP_DEBUG
+#ifndef CONFIG_BLUEZ_BNEP_DEBUG
 #undef  BT_DBG
 #define BT_DBG( A... )
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/hci_core.c linux-2.4.21/net/bluetooth/hci_core.c
--- linux-2.4.20/net/bluetooth/hci_core.c	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/bluetooth/hci_core.c	2002-12-18 18:58:05.000000000 +0000
@@ -717,7 +717,7 @@
 	if (!dev_num)
 		return -EINVAL;
 	
-	size = dev_num * sizeof(struct hci_dev_req) + sizeof(__u16);
+	size = dev_num * sizeof(*dr) + sizeof(*dl);
 
 	if (verify_area(VERIFY_WRITE, (void *) arg, size))
 		return -EFAULT;
@@ -738,7 +738,7 @@
 	read_unlock_bh(&hdev_list_lock);
 
 	dl->dev_num = n;
-	size = n * sizeof(struct hci_dev_req) + sizeof(__u16);
+	size = n * sizeof(*dr) + sizeof(*dl);
 
 	copy_to_user((void *) arg, dl, size);
 	kfree(dl);
@@ -864,6 +864,22 @@
 	return 0;
 }
 
+/* Suspend HCI device */
+int hci_suspend_dev(struct hci_dev *hdev)
+{
+	hci_notify(hdev, HCI_DEV_SUSPEND);
+	hci_run_hotplug(hdev->name, "suspend");
+	return 0;
+}
+
+/* Resume HCI device */
+int hci_resume_dev(struct hci_dev *hdev)
+{
+	hci_notify(hdev, HCI_DEV_RESUME);
+	hci_run_hotplug(hdev->name, "resume");
+	return 0;
+}       
+
 /* Receive frame from HCI drivers */
 int hci_recv_frame(struct sk_buff *skb)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/l2cap.c linux-2.4.21/net/bluetooth/l2cap.c
--- linux-2.4.20/net/bluetooth/l2cap.c	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/bluetooth/l2cap.c	2002-12-18 18:58:08.000000000 +0000
@@ -178,69 +178,12 @@
 	return 0;
 }
 
-int l2cap_connect(struct sock *sk)
-{
-	bdaddr_t *src = &bluez_pi(sk)->src;
-	bdaddr_t *dst = &bluez_pi(sk)->dst;
-	struct l2cap_conn *conn;
-	struct hci_conn   *hcon;
-	struct hci_dev    *hdev;
-	int err = 0;
-
-	BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
-
-	if (!(hdev = hci_get_route(dst, src)))
-		return -EHOSTUNREACH;
-
-	hci_dev_lock_bh(hdev);
-
-	err = -ENOMEM;
-
-	hcon = hci_connect(hdev, ACL_LINK, dst);
-	if (!hcon)
-		goto done;
-
-	conn = l2cap_conn_add(hcon, 0);
-	if (!conn) {
-		hci_conn_put(hcon);
-		goto done;
-	}
-
-	err = 0;
-
-	/* Update source addr of the socket */
-	bacpy(src, conn->src);
-
-	l2cap_chan_add(conn, sk, NULL);
-
-	sk->state = BT_CONNECT;
-	l2cap_sock_set_timer(sk, sk->sndtimeo);
-
-	if (hcon->state == BT_CONNECTED) {
-		if (sk->type == SOCK_SEQPACKET) {
-			l2cap_conn_req req;
-			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-			req.psm  = l2cap_pi(sk)->psm;
-			l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
-		} else {
-			l2cap_sock_clear_timer(sk);
-			sk->state = BT_CONNECTED;
-		}
-	}
-
-done:
-	hci_dev_unlock_bh(hdev);
-	hci_dev_put(hdev);
-	return err;
-}
-
 /* -------- Socket interface ---------- */
 static struct sock *__l2cap_get_sock_by_addr(__u16 psm, bdaddr_t *src)
 {
 	struct sock *sk;
 	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
-		if (l2cap_pi(sk)->psm == psm &&
-				!bacmp(&bluez_pi(sk)->src, src))
+		if (sk->sport == psm && !bacmp(&bluez_pi(sk)->src, src))
 			break;
 	}
 	return sk;
@@ -432,6 +375,9 @@
 	if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
 		return -ESOCKTNOSUPPORT;
 
+	if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW))
+		return -EPERM;
+	
 	sock->ops = &l2cap_sock_ops;
 
 	if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL)))
@@ -466,9 +412,9 @@
 		/* Save source address */
 		bacpy(&bluez_pi(sk)->src, &la->l2_bdaddr);
 		l2cap_pi(sk)->psm = la->l2_psm;
+		sk->sport = la->l2_psm;
 		sk->state = BT_BOUND;
 	}
-
 	write_unlock_bh(&l2cap_sk_list.lock);
 
 done:
@@ -476,6 +422,62 @@
 	return err;
 }
 
+static int l2cap_do_connect(struct sock *sk)
+{
+	bdaddr_t *src = &bluez_pi(sk)->src;
+	bdaddr_t *dst = &bluez_pi(sk)->dst;
+	struct l2cap_conn *conn;
+	struct hci_conn   *hcon;
+	struct hci_dev    *hdev;
+	int err = 0;
+
+	BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
+
+	if (!(hdev = hci_get_route(dst, src)))
+		return -EHOSTUNREACH;
+
+	hci_dev_lock_bh(hdev);
+
+	err = -ENOMEM;
+
+	hcon = hci_connect(hdev, ACL_LINK, dst);
+	if (!hcon)
+		goto done;
+
+	conn = l2cap_conn_add(hcon, 0);
+	if (!conn) {
+		hci_conn_put(hcon);
+		goto done;
+	}
+
+	err = 0;
+
+	/* Update source addr of the socket */
+	bacpy(src, conn->src);
+
+	l2cap_chan_add(conn, sk, NULL);
+
+	sk->state = BT_CONNECT;
+	l2cap_sock_set_timer(sk, sk->sndtimeo);
+
+	if (hcon->state == BT_CONNECTED) {
+		if (sk->type == SOCK_SEQPACKET) {
+			l2cap_conn_req req;
+			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+			req.psm  = l2cap_pi(sk)->psm;
+			l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
+		} else {
+			l2cap_sock_clear_timer(sk);
+			sk->state = BT_CONNECTED;
+		}
+	}
+
+done:
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+	return err;
+}
+
 static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
 {
 	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
@@ -521,7 +523,7 @@
 	bacpy(&bluez_pi(sk)->dst, &la->l2_bdaddr);
 	l2cap_pi(sk)->psm = la->l2_psm;
 
-	if ((err = l2cap_connect(sk)))
+	if ((err = l2cap_do_connect(sk)))
 		goto done;
 
 wait:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/rfcomm/Config.in linux-2.4.21/net/bluetooth/rfcomm/Config.in
--- linux-2.4.20/net/bluetooth/rfcomm/Config.in	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/net/bluetooth/rfcomm/Config.in	2002-12-18 18:58:04.000000000 +0000
@@ -0,0 +1,10 @@
+#
+# Bluetooth RFCOMM layer configuration
+#
+
+dep_tristate 'RFCOMM protocol support' CONFIG_BLUEZ_RFCOMM $CONFIG_BLUEZ_L2CAP
+
+if [ "$CONFIG_BLUEZ_RFCOMM" != "n" ]; then
+   bool '  RFCOMM TTY support' CONFIG_BLUEZ_RFCOMM_TTY
+fi
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/rfcomm/Makefile linux-2.4.21/net/bluetooth/rfcomm/Makefile
--- linux-2.4.20/net/bluetooth/rfcomm/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/net/bluetooth/rfcomm/Makefile	2002-12-18 18:58:06.000000000 +0000
@@ -0,0 +1,11 @@
+#
+# Makefile for the Linux Bluetooth RFCOMM layer
+#
+
+O_TARGET := rfcomm.o
+
+obj-y				:= core.o sock.o crc.o
+obj-$(CONFIG_BLUEZ_RFCOMM_TTY)	+= tty.o
+obj-m				+= $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/rfcomm/core.c linux-2.4.21/net/bluetooth/rfcomm/core.c
--- linux-2.4.20/net/bluetooth/rfcomm/core.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/net/bluetooth/rfcomm/core.c	2002-12-18 18:58:10.000000000 +0000
@@ -0,0 +1,1805 @@
+/* 
+   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
+   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
+   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/* 
+   RPN support    -    Dirk Husemann <hud@zurich.ibm.com>
+*/
+
+/*
+ * RFCOMM core.
+ *
+ * $Id: core.c,v 1.46 2002/10/18 20:12:12 maxk Exp $
+ */
+
+#define __KERNEL_SYSCALLS__
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/net.h>
+#include <linux/proc_fs.h>
+#include <net/sock.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/l2cap.h>
+#include <net/bluetooth/rfcomm.h>
+
+#define VERSION "0.4"
+
+#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
+#undef  BT_DBG
+#define BT_DBG(D...)
+#endif
+
+struct task_struct *rfcomm_thread;
+DECLARE_MUTEX(rfcomm_sem);
+unsigned long rfcomm_event;
+
+static LIST_HEAD(session_list);
+static atomic_t terminate, running;
+
+static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len);
+static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci);
+static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci);
+static int rfcomm_queue_disc(struct rfcomm_dlc *d);
+static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type);
+static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d);
+static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig);
+static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len);
+static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits);
+static void rfcomm_make_uih(struct sk_buff *skb, u8 addr);
+
+static void rfcomm_process_connect(struct rfcomm_session *s);
+
+/* ---- RFCOMM frame parsing macros ---- */
+#define __get_dlci(b)     ((b & 0xfc) >> 2)
+#define __get_channel(b)  ((b & 0xf8) >> 3)
+#define __get_dir(b)      ((b & 0x04) >> 2)
+#define __get_type(b)     ((b & 0xef))
+
+#define __test_ea(b)      ((b & 0x01))
+#define __test_cr(b)      ((b & 0x02))
+#define __test_pf(b)      ((b & 0x10))
+
+#define __addr(cr, dlci)       (((dlci & 0x3f) << 2) | (cr << 1) | 0x01)
+#define __ctrl(type, pf)       (((type & 0xef) | (pf << 4)))
+#define __dlci(dir, chn)       (((chn & 0x1f) << 1) | dir)
+#define __srv_channel(dlci)    (dlci >> 1)
+#define __dir(dlci)            (dlci & 0x01)
+
+#define __len8(len)       (((len) << 1) | 1)
+#define __len16(len)      ((len) << 1)
+
+/* MCC macros */
+#define __mcc_type(cr, type)   (((type << 2) | (cr << 1) | 0x01))
+#define __get_mcc_type(b) ((b & 0xfc) >> 2)
+#define __get_mcc_len(b)  ((b & 0xfe) >> 1)
+
+/* RPN macros */
+#define __rpn_line_settings(data, stop, parity)  ((data & 0x3) | ((stop & 0x1) << 2) | ((parity & 0x3) << 3))
+#define __get_rpn_data_bits(line) ((line) & 0x3)
+#define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1)
+#define __get_rpn_parity(line)    (((line) >> 3) & 0x3)
+
+/* ---- RFCOMM FCS computation ---- */
+
+/* CRC on 2 bytes */
+#define __crc(data) (rfcomm_crc_table[rfcomm_crc_table[0xff ^ data[0]] ^ data[1]])
+
+/* FCS on 2 bytes */ 
+static inline u8 __fcs(u8 *data)
+{
+	return (0xff - __crc(data));
+}
+
+/* FCS on 3 bytes */ 
+static inline u8 __fcs2(u8 *data)
+{
+	return (0xff - rfcomm_crc_table[__crc(data) ^ data[2]]);
+}
+
+/* Check FCS */
+static inline int __check_fcs(u8 *data, int type, u8 fcs)
+{
+	u8 f = __crc(data);
+
+	if (type != RFCOMM_UIH)
+		f = rfcomm_crc_table[f ^ data[2]];
+
+	return rfcomm_crc_table[f ^ fcs] != 0xcf;
+}
+
+/* ---- L2CAP callbacks ---- */
+static void rfcomm_l2state_change(struct sock *sk)
+{
+	BT_DBG("%p state %d", sk, sk->state);
+	rfcomm_schedule(RFCOMM_SCHED_STATE);
+}
+
+static void rfcomm_l2data_ready(struct sock *sk, int bytes)
+{
+	BT_DBG("%p bytes %d", sk, bytes);
+	rfcomm_schedule(RFCOMM_SCHED_RX);
+}
+
+static int rfcomm_l2sock_create(struct socket **sock)
+{
+	int err;
+
+	BT_DBG("");
+
+	err = sock_create(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP, sock);
+	if (!err) {
+		struct sock *sk = (*sock)->sk;
+		sk->data_ready   = rfcomm_l2data_ready;
+		sk->state_change = rfcomm_l2state_change;
+	}
+	return err;
+}
+
+/* ---- RFCOMM DLCs ---- */
+static void rfcomm_dlc_timeout(unsigned long arg)
+{
+	struct rfcomm_dlc *d = (void *) arg;
+
+	BT_DBG("dlc %p state %ld", d, d->state);
+
+	set_bit(RFCOMM_TIMED_OUT, &d->flags);
+	rfcomm_dlc_put(d);
+	rfcomm_schedule(RFCOMM_SCHED_TIMEO);
+}
+
+static void rfcomm_dlc_set_timer(struct rfcomm_dlc *d, long timeout)
+{
+	BT_DBG("dlc %p state %ld timeout %ld", d, d->state, timeout);
+
+	if (!mod_timer(&d->timer, jiffies + timeout))
+		rfcomm_dlc_hold(d);
+}
+
+static void rfcomm_dlc_clear_timer(struct rfcomm_dlc *d)
+{
+	BT_DBG("dlc %p state %ld", d, d->state);
+
+	if (timer_pending(&d->timer) && del_timer(&d->timer))
+		rfcomm_dlc_put(d);
+}
+
+static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d)
+{
+	BT_DBG("%p", d);
+
+	d->state      = BT_OPEN;
+	d->flags      = 0;
+	d->mtu        = RFCOMM_DEFAULT_MTU;
+	d->v24_sig    = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV;
+
+	d->credits    = RFCOMM_MAX_CREDITS;
+	d->rx_credits = RFCOMM_DEFAULT_CREDITS;
+}
+
+struct rfcomm_dlc *rfcomm_dlc_alloc(int prio)
+{
+	struct rfcomm_dlc *d = kmalloc(sizeof(*d), prio);
+	if (!d)
+		return NULL;
+	memset(d, 0, sizeof(*d));
+
+	init_timer(&d->timer);
+	d->timer.function = rfcomm_dlc_timeout;
+	d->timer.data = (unsigned long) d;
+
+	skb_queue_head_init(&d->tx_queue);
+	spin_lock_init(&d->lock);
+	atomic_set(&d->refcnt, 1);
+
+	rfcomm_dlc_clear_state(d);
+	
+	BT_DBG("%p", d);
+	return d;
+}
+
+void rfcomm_dlc_free(struct rfcomm_dlc *d)
+{
+	BT_DBG("%p", d);
+
+	skb_queue_purge(&d->tx_queue);
+	kfree(d);
+}
+
+static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d)
+{
+	BT_DBG("dlc %p session %p", d, s);
+
+	rfcomm_session_hold(s);
+
+	rfcomm_dlc_hold(d);
+	list_add(&d->list, &s->dlcs);
+	d->session = s;
+}
+
+static void rfcomm_dlc_unlink(struct rfcomm_dlc *d)
+{
+	struct rfcomm_session *s = d->session;
+
+	BT_DBG("dlc %p refcnt %d session %p", d, atomic_read(&d->refcnt), s);
+
+	list_del(&d->list);
+	d->session = NULL;
+	rfcomm_dlc_put(d);
+
+	rfcomm_session_put(s);
+}
+
+static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, int dlci)
+{
+	struct rfcomm_dlc *d;
+	struct list_head *p;
+
+	list_for_each(p, &s->dlcs) {
+		d = list_entry(p, struct rfcomm_dlc, list);
+		if (d->dlci == dlci)
+			return d;
+	}
+	return NULL;
+}
+
+static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
+{
+	struct rfcomm_session *s;
+	int err = 0, dlci = __dlci(0, channel);
+
+	BT_DBG("dlc %p state %ld %s %s channel %d dlci %d", 
+			d, d->state, batostr(src), batostr(dst), channel, dlci);
+
+	if (dlci < 1 || dlci > 62)
+		return -EINVAL;
+
+	if (d->state != BT_OPEN && d->state != BT_CLOSED)
+		return 0;
+
+	s = rfcomm_session_get(src, dst);
+	if (!s) {
+		s = rfcomm_session_create(src, dst, &err);
+		if (!s)
+			return err;
+	}
+
+	/* Check if DLCI already exists */
+	if (rfcomm_dlc_get(s, dlci))
+		return -EBUSY;
+
+	rfcomm_dlc_clear_state(d);
+
+	d->dlci    = dlci;
+	d->addr    = __addr(s->initiator, dlci);
+
+	d->state   = BT_CONFIG;
+	rfcomm_dlc_link(s, d);
+
+	d->mtu     = s->mtu;
+	d->credits = s->credits;
+
+	if (s->state == BT_CONNECTED)
+		rfcomm_send_pn(s, 1, d);
+	rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
+	return 0;
+}
+
+int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
+{
+	mm_segment_t fs;
+	int r;
+
+	rfcomm_lock();
+
+	fs = get_fs(); set_fs(KERNEL_DS);
+	r = __rfcomm_dlc_open(d, src, dst, channel);
+	set_fs(fs);
+
+	rfcomm_unlock();
+	return r;
+}
+
+static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
+{
+	struct rfcomm_session *s = d->session;
+	if (!s)
+		return 0;
+
+	BT_DBG("dlc %p state %ld dlci %d err %d session %p",
+			d, d->state, d->dlci, err, s);
+
+	switch (d->state) {
+	case BT_CONNECTED:
+	case BT_CONFIG:
+	case BT_CONNECT:
+		d->state = BT_DISCONN;
+		if (skb_queue_empty(&d->tx_queue)) {
+			rfcomm_send_disc(s, d->dlci);
+			rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT);
+		} else {
+			rfcomm_queue_disc(d);
+			rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT * 2);
+		}
+		break;
+
+	default:
+		rfcomm_dlc_clear_timer(d);
+
+		rfcomm_dlc_lock(d);
+		d->state = BT_CLOSED;
+		d->state_change(d, err);
+		rfcomm_dlc_unlock(d);
+
+		skb_queue_purge(&d->tx_queue);
+		rfcomm_dlc_unlink(d);
+	}
+
+	return 0;
+}
+
+int rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
+{
+	mm_segment_t fs;
+	int r;
+
+	rfcomm_lock();
+
+	fs = get_fs(); set_fs(KERNEL_DS);
+	r = __rfcomm_dlc_close(d, err);
+	set_fs(fs);
+
+	rfcomm_unlock();
+	return r;
+}
+
+int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb)
+{
+	int len = skb->len;
+
+	if (d->state != BT_CONNECTED)
+		return -ENOTCONN;
+
+	BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len);
+
+	if (len > d->mtu)
+		return -EINVAL;
+
+	rfcomm_make_uih(skb, d->addr);
+	skb_queue_tail(&d->tx_queue, skb);
+
+	if (!test_bit(RFCOMM_TX_THROTTLED, &d->flags))
+		rfcomm_schedule(RFCOMM_SCHED_TX);
+	return len;
+}
+
+void __rfcomm_dlc_throttle(struct rfcomm_dlc *d)
+{
+	BT_DBG("dlc %p state %ld", d, d->state);
+
+	if (!d->credits) {
+		d->v24_sig |= RFCOMM_V24_FC;
+		set_bit(RFCOMM_MSC_PENDING, &d->flags);
+	}
+	rfcomm_schedule(RFCOMM_SCHED_TX);
+}
+
+void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
+{
+	BT_DBG("dlc %p state %ld", d, d->state);
+
+	if (!d->credits) {
+		d->v24_sig &= ~RFCOMM_V24_FC;
+		set_bit(RFCOMM_MSC_PENDING, &d->flags);
+	}
+	rfcomm_schedule(RFCOMM_SCHED_TX);
+}
+
+/* 
+   Set/get modem status functions use _local_ status i.e. what we report
+   to the other side.
+   Remote status is provided by dlc->modem_status() callback.
+ */
+int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig)
+{
+	BT_DBG("dlc %p state %ld v24_sig 0x%x", 
+			d, d->state, v24_sig);
+
+	if (test_bit(RFCOMM_RX_THROTTLED, &d->flags))
+		v24_sig |= RFCOMM_V24_FC;
+	else
+		v24_sig &= ~RFCOMM_V24_FC;
+	
+	d->v24_sig = v24_sig;
+
+	if (!test_and_set_bit(RFCOMM_MSC_PENDING, &d->flags))
+		rfcomm_schedule(RFCOMM_SCHED_TX);
+
+	return 0;
+}
+
+int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig)
+{
+	BT_DBG("dlc %p state %ld v24_sig 0x%x", 
+			d, d->state, d->v24_sig);
+
+	*v24_sig = d->v24_sig;
+	return 0;
+}
+
+/* ---- RFCOMM sessions ---- */
+struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
+{
+	struct rfcomm_session *s = kmalloc(sizeof(*s), GFP_KERNEL);
+	if (!s)
+		return NULL;
+	memset(s, 0, sizeof(*s));
+	
+	BT_DBG("session %p sock %p", s, sock);
+
+	INIT_LIST_HEAD(&s->dlcs);
+	s->state = state;
+	s->sock  = sock;
+
+	s->mtu     = RFCOMM_DEFAULT_MTU;
+	s->credits = RFCOMM_MAX_CREDITS;
+	
+	list_add(&s->list, &session_list);
+
+	/* Do not increment module usage count for listeting sessions.
+	 * Otherwise we won't be able to unload the module. */
+	if (state != BT_LISTEN)
+		MOD_INC_USE_COUNT;
+	return s;
+}
+
+void rfcomm_session_del(struct rfcomm_session *s)
+{
+	int state = s->state;
+	
+	BT_DBG("session %p state %ld", s, s->state);
+
+	list_del(&s->list);
+
+	if (state == BT_CONNECTED)
+		rfcomm_send_disc(s, 0);
+
+	sock_release(s->sock);
+	kfree(s);
+
+	if (state != BT_LISTEN)
+		MOD_DEC_USE_COUNT;
+}
+
+struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst)
+{
+	struct rfcomm_session *s;
+	struct list_head *p, *n;
+	struct bluez_pinfo *pi;
+	list_for_each_safe(p, n, &session_list) {
+		s = list_entry(p, struct rfcomm_session, list);
+		pi = bluez_pi(s->sock->sk); 
+
+		if ((!bacmp(src, BDADDR_ANY) || !bacmp(&pi->src, src)) &&
+				!bacmp(&pi->dst, dst))
+			return s;
+	}
+	return NULL;
+}
+
+void rfcomm_session_close(struct rfcomm_session *s, int err)
+{
+	struct rfcomm_dlc *d;
+	struct list_head *p, *n;
+
+	BT_DBG("session %p state %ld err %d", s, s->state, err);
+
+	rfcomm_session_hold(s);
+
+	s->state = BT_CLOSED;
+
+	/* Close all dlcs */
+	list_for_each_safe(p, n, &s->dlcs) {
+		d = list_entry(p, struct rfcomm_dlc, list);
+		d->state = BT_CLOSED;
+		__rfcomm_dlc_close(d, err);
+	}
+
+	rfcomm_session_put(s);
+}
+
+struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err)
+{
+	struct rfcomm_session *s = NULL;
+	struct sockaddr_l2 addr;
+	struct l2cap_options opts;
+	struct socket *sock;
+	int    size;
+
+	BT_DBG("%s %s", batostr(src), batostr(dst));
+
+	*err = rfcomm_l2sock_create(&sock);
+	if (*err < 0)
+		return NULL;
+
+	bacpy(&addr.l2_bdaddr, src);
+	addr.l2_family = AF_BLUETOOTH;
+	addr.l2_psm    = 0;
+	*err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+	if (*err < 0)
+		goto failed;
+
+	/* Set L2CAP options */
+	size = sizeof(opts);
+	sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size);
+	
+	opts.imtu = RFCOMM_MAX_L2CAP_MTU;
+	sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size);
+
+	s = rfcomm_session_add(sock, BT_BOUND);
+	if (!s) {
+		*err = -ENOMEM;
+		goto failed;
+	}
+
+	s->initiator = 1;
+
+	bacpy(&addr.l2_bdaddr, dst);
+	addr.l2_family = AF_BLUETOOTH;
+	addr.l2_psm    = htobs(RFCOMM_PSM);
+	*err = sock->ops->connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
+	if (*err == 0 || *err == -EAGAIN)
+		return s;
+
+	rfcomm_session_del(s);
+	return NULL;
+
+failed:
+	sock_release(sock);
+	return NULL;
+}
+
+void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst)
+{
+	struct sock *sk = s->sock->sk;
+	if (src)
+		bacpy(src, &bluez_pi(sk)->src);
+	if (dst)
+		bacpy(dst, &bluez_pi(sk)->dst);
+}
+
+/* ---- RFCOMM frame sending ---- */
+static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len)
+{
+	struct socket *sock = s->sock;
+	struct iovec iv = { data, len };
+	struct msghdr msg;
+	int err;
+
+	BT_DBG("session %p len %d", s, len);
+
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_iovlen = 1;
+	msg.msg_iov = &iv;
+
+	err = sock->ops->sendmsg(sock, &msg, len, 0);
+	return err;
+}
+
+static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
+{
+	struct rfcomm_cmd cmd;
+
+	BT_DBG("%p dlci %d", s, dlci);
+
+	cmd.addr = __addr(s->initiator, dlci);
+	cmd.ctrl = __ctrl(RFCOMM_SABM, 1);
+	cmd.len  = __len8(0);
+	cmd.fcs  = __fcs2((u8 *) &cmd);
+
+	return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+}
+
+static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci)
+{
+	struct rfcomm_cmd cmd;
+
+	BT_DBG("%p dlci %d", s, dlci);
+
+	cmd.addr = __addr(!s->initiator, dlci);
+	cmd.ctrl = __ctrl(RFCOMM_UA, 1);
+	cmd.len  = __len8(0);
+	cmd.fcs  = __fcs2((u8 *) &cmd);
+
+	return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+}
+
+static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci)
+{
+	struct rfcomm_cmd cmd;
+
+	BT_DBG("%p dlci %d", s, dlci);
+
+	cmd.addr = __addr(s->initiator, dlci);
+	cmd.ctrl = __ctrl(RFCOMM_DISC, 1);
+	cmd.len  = __len8(0);
+	cmd.fcs  = __fcs2((u8 *) &cmd);
+
+	return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+}
+
+static int rfcomm_queue_disc(struct rfcomm_dlc *d)
+{
+	struct rfcomm_cmd *cmd;
+	struct sk_buff *skb;
+
+	BT_DBG("dlc %p dlci %d", d, d->dlci);
+
+	skb = alloc_skb(sizeof(*cmd), GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (void *) __skb_put(skb, sizeof(*cmd));
+	cmd->addr = d->addr;
+	cmd->ctrl = __ctrl(RFCOMM_DISC, 1);
+	cmd->len  = __len8(0);
+	cmd->fcs  = __fcs2((u8 *) cmd);
+
+	skb_queue_tail(&d->tx_queue, skb);
+	rfcomm_schedule(RFCOMM_SCHED_TX);
+	return 0;
+}
+
+static int rfcomm_send_dm(struct rfcomm_session *s, u8 dlci)
+{
+	struct rfcomm_cmd cmd;
+
+	BT_DBG("%p dlci %d", s, dlci);
+
+	cmd.addr = __addr(!s->initiator, dlci);
+	cmd.ctrl = __ctrl(RFCOMM_DM, 1);
+	cmd.len  = __len8(0);
+	cmd.fcs  = __fcs2((u8 *) &cmd);
+
+	return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+}
+
+static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
+{
+	struct rfcomm_hdr *hdr;
+	struct rfcomm_mcc *mcc;
+	u8 buf[16], *ptr = buf;
+
+	BT_DBG("%p cr %d type %d", s, cr, type);
+
+	hdr = (void *) ptr; ptr += sizeof(*hdr);
+	hdr->addr = __addr(s->initiator, 0);
+	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
+	hdr->len  = __len8(sizeof(*mcc) + 1);
+
+	mcc = (void *) ptr; ptr += sizeof(*mcc);
+	mcc->type = __mcc_type(s->initiator, RFCOMM_NSC);
+	mcc->len  = __len8(1);
+
+	/* Type that we didn't like */
+	*ptr = __mcc_type(cr, type); ptr++;
+
+	*ptr = __fcs(buf); ptr++;
+
+	return rfcomm_send_frame(s, buf, ptr - buf);
+}
+
+static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d)
+{
+	struct rfcomm_hdr *hdr;
+	struct rfcomm_mcc *mcc;
+	struct rfcomm_pn  *pn;
+	u8 buf[16], *ptr = buf;
+
+	BT_DBG("%p cr %d dlci %d mtu %d", s, cr, d->dlci, d->mtu);
+
+	hdr = (void *) ptr; ptr += sizeof(*hdr);
+	hdr->addr = __addr(s->initiator, 0);
+	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
+	hdr->len  = __len8(sizeof(*mcc) + sizeof(*pn));
+
+	mcc = (void *) ptr; ptr += sizeof(*mcc);
+	mcc->type = __mcc_type(s->initiator, RFCOMM_PN);
+	mcc->len  = __len8(sizeof(*pn));
+
+	pn = (void *) ptr; ptr += sizeof(*pn);
+	pn->dlci        = d->dlci;
+	pn->priority    = 0;
+	pn->ack_timer   = 0;
+	pn->max_retrans = 0;
+
+	if (d->credits) {
+		pn->flow_ctrl = cr ? 0xf0 : 0xe0;
+		pn->credits = RFCOMM_DEFAULT_CREDITS;
+	} else {
+		pn->flow_ctrl = 0;
+		pn->credits   = 0;
+	}
+
+	pn->mtu = htobs(d->mtu);
+
+	*ptr = __fcs(buf); ptr++;
+
+	return rfcomm_send_frame(s, buf, ptr - buf);
+}
+
+static int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
+			   u8 bit_rate, u8 data_bits, u8 stop_bits,
+			   u8 parity, u8 flow_ctrl_settings, 
+			   u8 xon_char, u8 xoff_char, u16 param_mask)
+{
+	struct rfcomm_hdr *hdr;
+	struct rfcomm_mcc *mcc;
+	struct rfcomm_rpn *rpn;
+	u8 buf[16], *ptr = buf;
+
+	BT_DBG("%p cr %d dlci %d bit_r 0x%x data_b 0x%x stop_b 0x%x parity 0x%x"
+	       "flwc_s 0x%x xon_c 0x%x xoff_c 0x%x p_mask 0x%x", 
+			s, cr, dlci, bit_rate, data_bits, stop_bits, parity, 
+			flow_ctrl_settings, xon_char, xoff_char, param_mask);
+
+	hdr = (void *) ptr; ptr += sizeof(*hdr);
+	hdr->addr = __addr(s->initiator, 0);
+	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
+	hdr->len  = __len8(sizeof(*mcc) + sizeof(*rpn));
+
+	mcc = (void *) ptr; ptr += sizeof(*mcc);
+	mcc->type = __mcc_type(cr, RFCOMM_RPN);
+	mcc->len  = __len8(sizeof(*rpn));
+
+	rpn = (void *) ptr; ptr += sizeof(*rpn);
+	rpn->dlci          = __addr(1, dlci);
+	rpn->bit_rate      = bit_rate;
+	rpn->line_settings = __rpn_line_settings(data_bits, stop_bits, parity);
+	rpn->flow_ctrl     = flow_ctrl_settings;
+	rpn->xon_char      = xon_char;
+	rpn->xoff_char     = xoff_char;
+	rpn->param_mask    = param_mask;
+
+	*ptr = __fcs(buf); ptr++;
+
+	return rfcomm_send_frame(s, buf, ptr - buf);
+}
+
+static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig)
+{
+	struct rfcomm_hdr *hdr;
+	struct rfcomm_mcc *mcc;
+	struct rfcomm_msc *msc;
+	u8 buf[16], *ptr = buf;
+
+	BT_DBG("%p cr %d v24 0x%x", s, cr, v24_sig);
+
+	hdr = (void *) ptr; ptr += sizeof(*hdr);
+	hdr->addr = __addr(s->initiator, 0);
+	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
+	hdr->len  = __len8(sizeof(*mcc) + sizeof(*msc));
+
+	mcc = (void *) ptr; ptr += sizeof(*mcc);
+	mcc->type = __mcc_type(cr, RFCOMM_MSC);
+	mcc->len  = __len8(sizeof(*msc));
+
+	msc = (void *) ptr; ptr += sizeof(*msc);
+	msc->dlci    = __addr(1, dlci);
+	msc->v24_sig = v24_sig;
+
+	*ptr = __fcs(buf); ptr++;
+
+	return rfcomm_send_frame(s, buf, ptr - buf);
+}
+
+static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len)
+{
+	struct socket *sock = s->sock;
+	struct iovec iv[3];
+	struct msghdr msg;
+	unsigned char hdr[5], crc[1];
+
+	if (len > 125)
+		return -EINVAL;
+
+	BT_DBG("%p cr %d", s, cr);
+
+	hdr[0] = __addr(s->initiator, 0);
+	hdr[1] = __ctrl(RFCOMM_UIH, 0);
+	hdr[2] = 0x01 | ((len + 2) << 1);
+	hdr[3] = 0x01 | ((cr & 0x01) << 1) | (RFCOMM_TEST << 2);
+	hdr[4] = 0x01 | (len << 1);
+
+	crc[0] = __fcs(hdr);
+
+	iv[0].iov_base = hdr;
+	iv[0].iov_len  = 5;
+	iv[1].iov_base = pattern;
+	iv[1].iov_len  = len;
+	iv[2].iov_base = crc;
+	iv[2].iov_len  = 1;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_iovlen = 3;
+	msg.msg_iov = iv;
+	return sock->ops->sendmsg(sock, &msg, 6 + len, 0);
+}
+
+static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits)
+{
+	struct rfcomm_hdr *hdr;
+	u8 buf[16], *ptr = buf;
+
+	BT_DBG("%p addr %d credits %d", s, addr, credits);
+
+	hdr = (void *) ptr; ptr += sizeof(*hdr);
+	hdr->addr = addr;
+	hdr->ctrl = __ctrl(RFCOMM_UIH, 1);
+	hdr->len  = __len8(0);
+
+	*ptr = credits; ptr++;
+
+	*ptr = __fcs(buf); ptr++;
+
+	return rfcomm_send_frame(s, buf, ptr - buf);
+}
+
+static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
+{
+	struct rfcomm_hdr *hdr;
+	int len = skb->len;
+	u8 *crc;
+
+	if (len > 127) {
+		hdr = (void *) skb_push(skb, 4);
+		put_unaligned(htobs(__len16(len)), (u16 *) &hdr->len);
+	} else {
+		hdr = (void *) skb_push(skb, 3);
+		hdr->len = __len8(len);
+	}
+	hdr->addr = addr;
+	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
+
+	crc = skb_put(skb, 1);
+	*crc = __fcs((void *) hdr);
+}
+
+/* ---- RFCOMM frame reception ---- */
+static int rfcomm_recv_ua(struct rfcomm_session *s, int dlci)
+{
+	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
+
+	if (dlci) {
+		/* Data channel */
+		struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
+		if (!d) {
+			rfcomm_send_dm(s, dlci);
+			return 0;
+		}
+
+		switch (d->state) {
+		case BT_CONNECT:
+			rfcomm_dlc_clear_timer(d);
+
+			rfcomm_dlc_lock(d);
+			d->state = BT_CONNECTED;
+			d->state_change(d, 0);
+			rfcomm_dlc_unlock(d);
+
+			rfcomm_send_msc(s, 1, dlci, d->v24_sig);
+			break;
+
+		case BT_DISCONN:
+			d->state = BT_CLOSED;
+			__rfcomm_dlc_close(d, 0);
+			break;
+		}
+	} else {
+		/* Control channel */
+		switch (s->state) {
+		case BT_CONNECT:
+			s->state = BT_CONNECTED;
+			rfcomm_process_connect(s);
+			break;
+		}
+	}
+	return 0;
+}
+
+static int rfcomm_recv_dm(struct rfcomm_session *s, int dlci)
+{
+	int err = 0;
+
+	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
+
+	if (dlci) {
+		/* Data DLC */
+		struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
+		if (d) {
+			if (d->state == BT_CONNECT || d->state == BT_CONFIG)
+				err = ECONNREFUSED;
+			else
+				err = ECONNRESET;
+
+			d->state = BT_CLOSED;
+			__rfcomm_dlc_close(d, err);
+		}
+	} else {
+		if (s->state == BT_CONNECT)
+			err = ECONNREFUSED;
+		else
+			err = ECONNRESET;
+
+		s->state = BT_CLOSED;
+		rfcomm_session_close(s, err);
+	}
+	return 0;
+}
+
+static int rfcomm_recv_disc(struct rfcomm_session *s, int dlci)
+{
+	int err = 0;
+
+	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
+
+	if (dlci) {
+		struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
+		if (d) {
+			rfcomm_send_ua(s, dlci);
+
+			if (d->state == BT_CONNECT || d->state == BT_CONFIG)
+				err = ECONNREFUSED;
+			else
+				err = ECONNRESET;
+
+			d->state = BT_CLOSED;
+			__rfcomm_dlc_close(d, err);
+		} else 
+			rfcomm_send_dm(s, dlci);
+			
+	} else {
+		rfcomm_send_ua(s, 0);
+
+		if (s->state == BT_CONNECT)
+			err = ECONNREFUSED;
+		else
+			err = ECONNRESET;
+
+		s->state = BT_CLOSED;
+		rfcomm_session_close(s, err);
+	}
+
+	return 0;
+}
+
+static int rfcomm_recv_sabm(struct rfcomm_session *s, int dlci)
+{
+	struct rfcomm_dlc *d;
+	int channel;
+
+	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
+
+	if (!dlci) {
+		rfcomm_send_ua(s, 0);
+
+		if (s->state == BT_OPEN) {
+			s->state = BT_CONNECTED;
+			rfcomm_process_connect(s);
+		}
+		return 0;
+	}
+
+	/* Check if DLC exists */
+	d = rfcomm_dlc_get(s, dlci);
+	if (d) {
+		if (d->state == BT_OPEN) {
+			/* DLC was previously opened by PN request */
+			rfcomm_send_ua(s, dlci);
+
+			rfcomm_dlc_lock(d);
+			d->state = BT_CONNECTED;
+			d->state_change(d, 0);
+			rfcomm_dlc_unlock(d);
+
+			rfcomm_send_msc(s, 1, dlci, d->v24_sig);
+		}
+		return 0;
+	}
+
+	/* Notify socket layer about incomming connection */
+	channel = __srv_channel(dlci);
+	if (rfcomm_connect_ind(s, channel, &d)) {
+		d->dlci = dlci;
+		d->addr = __addr(s->initiator, dlci);
+		rfcomm_dlc_link(s, d);
+
+		rfcomm_send_ua(s, dlci);
+
+		rfcomm_dlc_lock(d);
+		d->state = BT_CONNECTED;
+		d->state_change(d, 0);
+		rfcomm_dlc_unlock(d);
+	} else {
+		rfcomm_send_dm(s, dlci);
+	}
+
+	return 0;
+}
+
+static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn)
+{
+	BT_DBG("dlc %p state %ld dlci %d mtu %d fc 0x%x credits %d", 
+			d, d->state, d->dlci, pn->mtu, pn->flow_ctrl, pn->credits);
+
+	if (cr) {
+		if (pn->flow_ctrl == 0xf0) {
+			d->tx_credits = pn->credits;
+		} else {
+			set_bit(RFCOMM_TX_THROTTLED, &d->flags);
+			d->credits = 0;
+		}
+
+		d->mtu = btohs(pn->mtu);
+	} else {
+		if (pn->flow_ctrl == 0xe0) {
+			d->tx_credits = pn->credits;
+		} else {
+			set_bit(RFCOMM_TX_THROTTLED, &d->flags);
+			d->credits = 0;
+		}
+
+		d->mtu = btohs(pn->mtu);
+	}
+
+	return 0;
+}
+
+static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb)
+{
+	struct rfcomm_pn *pn = (void *) skb->data;
+	struct rfcomm_dlc *d;
+	int dlci = pn->dlci;
+
+	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
+
+	if (!dlci)
+		return 0;
+
+	d = rfcomm_dlc_get(s, dlci);
+	if (d) {
+		if (cr) {
+			/* PN request */
+			rfcomm_apply_pn(d, cr, pn);
+			rfcomm_send_pn(s, 0, d);
+		} else {
+			/* PN response */
+			switch (d->state) {
+			case BT_CONFIG:
+				rfcomm_apply_pn(d, cr, pn);
+				
+				d->state = BT_CONNECT;
+				rfcomm_send_sabm(s, d->dlci);
+				break;
+			}
+		}
+	} else {
+		int channel = __srv_channel(dlci);
+
+		if (!cr)
+			return 0;
+		
+		/* PN request for non existing DLC.
+		 * Assume incomming connection. */
+		if (rfcomm_connect_ind(s, channel, &d)) {
+			d->dlci = dlci;
+			d->addr = __addr(s->initiator, dlci);
+			rfcomm_dlc_link(s, d);
+
+			rfcomm_apply_pn(d, cr, pn);
+			
+			d->state = BT_OPEN;
+			rfcomm_send_pn(s, 0, d);
+		} else {
+			rfcomm_send_dm(s, dlci);
+		}
+	}
+	return 0;
+}
+
+static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb)
+{
+	struct rfcomm_rpn *rpn = (void *) skb->data;
+	int dlci = __get_dlci(rpn->dlci);
+
+	u8 bit_rate  = 0;
+	u8 data_bits = 0;
+	u8 stop_bits = 0;
+	u8 parity    = 0;
+	u8 flow_ctrl = 0;
+	u8 xon_char  = 0;
+	u8 xoff_char = 0;
+	u16 rpn_mask = RFCOMM_RPN_PM_ALL;
+	
+	BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", 
+	       dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl,
+	       rpn->xon_char, rpn->xoff_char, rpn->param_mask);
+	
+	if (!cr) 
+		return 0;
+	
+	if (len == 1) {
+		/* request: return default setting */
+		bit_rate  = RFCOMM_RPN_BR_115200;
+		data_bits = RFCOMM_RPN_DATA_8;
+		stop_bits = RFCOMM_RPN_STOP_1;
+		parity    = RFCOMM_RPN_PARITY_NONE;
+		flow_ctrl = RFCOMM_RPN_FLOW_NONE;
+		xon_char  = RFCOMM_RPN_XON_CHAR;
+		xoff_char = RFCOMM_RPN_XOFF_CHAR;
+
+		goto rpn_out;
+	}
+	/* check for sane values: ignore/accept bit_rate, 8 bits, 1 stop bit, no parity,
+	                          no flow control lines, normal XON/XOFF chars */
+	if (rpn->param_mask & RFCOMM_RPN_PM_DATA) {
+		data_bits = __get_rpn_data_bits(rpn->line_settings);
+		if (data_bits != RFCOMM_RPN_DATA_8) {
+			BT_DBG("RPN data bits mismatch 0x%x", data_bits);
+			data_bits = RFCOMM_RPN_DATA_8;
+			rpn_mask ^= RFCOMM_RPN_PM_DATA;
+		}
+	}
+	if (rpn->param_mask & RFCOMM_RPN_PM_STOP) {
+		stop_bits = __get_rpn_stop_bits(rpn->line_settings);
+		if (stop_bits != RFCOMM_RPN_STOP_1) {
+			BT_DBG("RPN stop bits mismatch 0x%x", stop_bits);
+			stop_bits = RFCOMM_RPN_STOP_1;
+			rpn_mask ^= RFCOMM_RPN_PM_STOP;
+		}
+	}
+	if (rpn->param_mask & RFCOMM_RPN_PM_PARITY) {
+		parity = __get_rpn_parity(rpn->line_settings);
+		if (parity != RFCOMM_RPN_PARITY_NONE) {
+			BT_DBG("RPN parity mismatch 0x%x", parity);
+			parity = RFCOMM_RPN_PARITY_NONE;
+			rpn_mask ^= RFCOMM_RPN_PM_PARITY;
+		}
+	}
+	if (rpn->param_mask & RFCOMM_RPN_PM_FLOW) {
+		if (rpn->flow_ctrl != RFCOMM_RPN_FLOW_NONE) {
+			BT_DBG("RPN flow ctrl mismatch 0x%x", rpn->flow_ctrl);
+			rpn->flow_ctrl = RFCOMM_RPN_FLOW_NONE;
+			rpn_mask ^= RFCOMM_RPN_PM_FLOW;
+		}
+	}
+	if (rpn->param_mask & RFCOMM_RPN_PM_XON) {
+		if (rpn->xon_char != RFCOMM_RPN_XON_CHAR) {
+			BT_DBG("RPN XON char mismatch 0x%x", rpn->xon_char);
+			rpn->xon_char = RFCOMM_RPN_XON_CHAR;
+			rpn_mask ^= RFCOMM_RPN_PM_XON;
+		}
+	}
+	if (rpn->param_mask & RFCOMM_RPN_PM_XOFF) {
+		if (rpn->xoff_char != RFCOMM_RPN_XOFF_CHAR) {
+			BT_DBG("RPN XOFF char mismatch 0x%x", rpn->xoff_char);
+			rpn->xoff_char = RFCOMM_RPN_XOFF_CHAR;
+			rpn_mask ^= RFCOMM_RPN_PM_XOFF;
+		}
+	}
+
+rpn_out:
+	rfcomm_send_rpn(s, 0, dlci, 
+			bit_rate, data_bits, stop_bits, parity, flow_ctrl,
+			xon_char, xoff_char, rpn_mask);
+
+	return 0;
+}
+
+static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb)
+{
+	struct rfcomm_msc *msc = (void *) skb->data;
+	struct rfcomm_dlc *d;
+	int dlci = __get_dlci(msc->dlci);
+
+	BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig);
+
+	if (!cr)
+		return 0;
+
+	d = rfcomm_dlc_get(s, dlci);
+	if (d) {
+		if (msc->v24_sig & RFCOMM_V24_FC && !d->credits)
+			set_bit(RFCOMM_TX_THROTTLED, &d->flags);
+		else
+			clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
+		
+		rfcomm_dlc_lock(d);
+		if (d->modem_status)
+			d->modem_status(d, msc->v24_sig);
+		rfcomm_dlc_unlock(d);
+		
+		rfcomm_send_msc(s, 0, dlci, msc->v24_sig);
+	}
+	return 0;
+}
+
+static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb)
+{
+	struct rfcomm_mcc *mcc = (void *) skb->data;
+	u8 type, cr, len;
+
+	cr   = __test_cr(mcc->type);
+	type = __get_mcc_type(mcc->type);
+	len  = __get_mcc_len(mcc->len);
+
+	BT_DBG("%p type 0x%x cr %d", s, type, cr);
+
+	skb_pull(skb, 2);
+
+	switch (type) {
+	case RFCOMM_PN:
+		rfcomm_recv_pn(s, cr, skb);
+		break;
+
+	case RFCOMM_RPN:
+		rfcomm_recv_rpn(s, cr, len, skb);
+		break;
+
+	case RFCOMM_MSC:
+		rfcomm_recv_msc(s, cr, skb);
+		break;
+
+	case RFCOMM_TEST:
+		if (cr)
+			rfcomm_send_test(s, 0, skb->data, skb->len);
+		break;
+
+	case RFCOMM_NSC:
+		break;
+
+	default:
+		BT_ERR("Unknown control type 0x%02x", type);
+		rfcomm_send_nsc(s, cr, type);
+		break;
+	}
+	return 0;
+}
+
+static int rfcomm_recv_data(struct rfcomm_session *s, int dlci, int pf, struct sk_buff *skb)
+{
+	struct rfcomm_dlc *d;
+
+	BT_DBG("session %p state %ld dlci %d pf %d", s, s->state, dlci, pf);
+
+	d = rfcomm_dlc_get(s, dlci);
+	if (!d) {
+		rfcomm_send_dm(s, dlci);
+		goto drop;
+	}
+
+	if (pf && d->credits) {
+		u8 credits = *(u8 *) skb->data; skb_pull(skb, 1);
+
+		d->tx_credits += credits;
+		if (d->tx_credits)
+			clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
+	}
+
+	if (skb->len && d->state == BT_CONNECTED) {
+		rfcomm_dlc_lock(d);
+		d->rx_credits--;
+		d->data_ready(d, skb);
+		rfcomm_dlc_unlock(d);
+		return 0;
+	}
+
+drop:
+	kfree_skb(skb);
+	return 0;
+}
+
+static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
+{
+	struct rfcomm_hdr *hdr = (void *) skb->data;
+	u8 type, dlci, fcs;
+
+	dlci = __get_dlci(hdr->addr);
+	type = __get_type(hdr->ctrl);
+
+	/* Trim FCS */
+	skb->len--; skb->tail--;
+	fcs = *(u8 *) skb->tail;
+	
+	if (__check_fcs(skb->data, type, fcs)) {
+		BT_ERR("bad checksum in packet");
+		kfree_skb(skb);
+		return -EILSEQ;
+	}
+
+	if (__test_ea(hdr->len))
+		skb_pull(skb, 3);
+	else
+		skb_pull(skb, 4);
+	
+	switch (type) {
+	case RFCOMM_SABM:
+		if (__test_pf(hdr->ctrl))
+			rfcomm_recv_sabm(s, dlci);
+		break;
+
+	case RFCOMM_DISC:
+		if (__test_pf(hdr->ctrl))
+			rfcomm_recv_disc(s, dlci);
+		break;
+
+	case RFCOMM_UA:
+		if (__test_pf(hdr->ctrl))
+			rfcomm_recv_ua(s, dlci);
+		break;
+
+	case RFCOMM_DM:
+		rfcomm_recv_dm(s, dlci);
+		break;
+
+	case RFCOMM_UIH:
+		if (dlci)
+			return rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb);
+
+		rfcomm_recv_mcc(s, skb);
+		break;
+
+	default:
+		BT_ERR("Unknown packet type 0x%02x\n", type);
+		break;
+	}
+	kfree_skb(skb);
+	return 0;
+}
+
+/* ---- Connection and data processing ---- */
+
+static void rfcomm_process_connect(struct rfcomm_session *s)
+{
+	struct rfcomm_dlc *d;
+	struct list_head *p, *n;
+
+	BT_DBG("session %p state %ld", s, s->state);
+
+	list_for_each_safe(p, n, &s->dlcs) {
+		d = list_entry(p, struct rfcomm_dlc, list);
+		if (d->state == BT_CONFIG) {
+			d->mtu = s->mtu;
+			rfcomm_send_pn(s, 1, d);
+		}
+	}
+}
+
+/* Send data queued for the DLC.
+ * Return number of frames left in the queue.
+ */
+static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
+{
+	struct sk_buff *skb;
+	int err;
+
+	BT_DBG("dlc %p state %ld credits %d rx_credits %d tx_credits %d", 
+			d, d->state, d->credits, d->rx_credits, d->tx_credits);
+
+	/* Send pending MSC */
+	if (test_and_clear_bit(RFCOMM_MSC_PENDING, &d->flags))
+		rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
+	
+	if (d->credits) {
+		/* CFC enabled. 
+		 * Give them some credits */
+		if (!test_bit(RFCOMM_RX_THROTTLED, &d->flags) &&
+			       	d->rx_credits <= (d->credits >> 2)) {
+			rfcomm_send_credits(d->session, d->addr, d->credits - d->rx_credits);
+			d->rx_credits = d->credits;
+		}
+	} else {
+		/* CFC disabled. 
+		 * Give ourselves some credits */
+		d->tx_credits = RFCOMM_MAX_CREDITS;
+	}
+
+	if (test_bit(RFCOMM_TX_THROTTLED, &d->flags))
+		return skb_queue_len(&d->tx_queue);
+
+	while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) {
+		err = rfcomm_send_frame(d->session, skb->data, skb->len);
+		if (err < 0) {
+			skb_queue_head(&d->tx_queue, skb);
+			break;
+		}
+		kfree_skb(skb);
+		d->tx_credits--;
+	}
+
+	if (d->credits && !d->tx_credits) {
+		/* We're out of TX credits.
+		 * Set TX_THROTTLED flag to avoid unnesary wakeups by dlc_send. */
+		set_bit(RFCOMM_TX_THROTTLED, &d->flags);
+	}
+
+	return skb_queue_len(&d->tx_queue);
+}
+
+static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
+{
+	struct rfcomm_dlc *d;
+	struct list_head *p, *n;
+
+	BT_DBG("session %p state %ld", s, s->state);
+
+	list_for_each_safe(p, n, &s->dlcs) {
+		d = list_entry(p, struct rfcomm_dlc, list);
+		if (test_bit(RFCOMM_TIMED_OUT, &d->flags)) {
+			__rfcomm_dlc_close(d, ETIMEDOUT);
+			continue;
+		}
+
+		if (d->state == BT_CONNECTED || d->state == BT_DISCONN)
+			rfcomm_process_tx(d);
+	}
+}
+
+static inline void rfcomm_process_rx(struct rfcomm_session *s)
+{
+	struct socket *sock = s->sock;
+	struct sock *sk = sock->sk;
+	struct sk_buff *skb;
+
+	BT_DBG("session %p state %ld qlen %d", s, s->state, skb_queue_len(&sk->receive_queue));
+
+	/* Get data directly from socket receive queue without copying it. */
+	while ((skb = skb_dequeue(&sk->receive_queue))) {
+		skb_orphan(skb);
+		rfcomm_recv_frame(s, skb);
+	}
+
+	if (sk->state == BT_CLOSED) {
+		if (!s->initiator)
+			rfcomm_session_put(s);
+
+		rfcomm_session_close(s, sk->err);
+	}
+}
+
+static inline void rfcomm_accept_connection(struct rfcomm_session *s)
+{
+	struct socket *sock = s->sock, *nsock;
+	int err;
+
+	/* Fast check for a new connection.
+	 * Avoids unnesesary socket allocations. */
+	if (list_empty(&bluez_pi(sock->sk)->accept_q))
+		return;
+
+	BT_DBG("session %p", s);
+
+	nsock = sock_alloc();
+	if (!nsock)
+		return;
+
+	nsock->type = sock->type;
+	nsock->ops  = sock->ops;
+	
+	err = sock->ops->accept(sock, nsock, O_NONBLOCK);
+	if (err < 0) {
+		sock_release(nsock);
+		return;
+	}
+
+	/* Set our callbacks */
+	nsock->sk->data_ready   = rfcomm_l2data_ready;
+	nsock->sk->state_change = rfcomm_l2state_change;
+
+	s = rfcomm_session_add(nsock, BT_OPEN);
+	if (s)
+		rfcomm_session_hold(s);
+	else
+		sock_release(nsock);
+}
+
+static inline void rfcomm_check_connection(struct rfcomm_session *s)
+{
+	struct sock *sk = s->sock->sk;
+
+	BT_DBG("%p state %ld", s, s->state);
+
+	switch(sk->state) {
+	case BT_CONNECTED:
+		s->state = BT_CONNECT;
+
+		/* We can adjust MTU on outgoing sessions.
+		 * L2CAP MTU minus UIH header and FCS. */
+		s->mtu = min(l2cap_pi(sk)->omtu, l2cap_pi(sk)->imtu) - 5;
+
+		rfcomm_send_sabm(s, 0);
+		break;
+
+	case BT_CLOSED:
+		s->state = BT_CLOSED;
+		rfcomm_session_close(s, sk->err);
+		break;
+	}
+}
+
+static inline void rfcomm_process_sessions(void)
+{
+	struct list_head *p, *n;
+
+	rfcomm_lock();
+
+	list_for_each_safe(p, n, &session_list) {
+		struct rfcomm_session *s;
+		s = list_entry(p, struct rfcomm_session, list);
+
+		if (s->state == BT_LISTEN) {
+			rfcomm_accept_connection(s);
+			continue;
+		}
+
+		rfcomm_session_hold(s);
+
+		switch (s->state) {
+		case BT_BOUND:
+			rfcomm_check_connection(s);
+			break;
+
+		default:
+			rfcomm_process_rx(s);
+			break;
+		}
+
+		rfcomm_process_dlcs(s);
+
+		rfcomm_session_put(s);
+	}
+	
+	rfcomm_unlock();
+}
+
+static void rfcomm_worker(void)
+{
+	BT_DBG("");
+
+	daemonize(); reparent_to_init();
+	set_fs(KERNEL_DS);
+
+	while (!atomic_read(&terminate)) {
+		if (!test_and_clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
+			/* No pending events. Let's sleep.
+			 * Incomming connections and data will wake us up. */
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+		}
+
+		/* Process stuff */
+		rfcomm_process_sessions();
+	}
+	set_current_state(TASK_RUNNING);
+	return;
+}
+
+static int rfcomm_add_listener(bdaddr_t *ba)
+{
+	struct sockaddr_l2 addr;
+	struct l2cap_options opts;
+	struct socket *sock;
+	struct rfcomm_session *s;
+	int    size, err = 0;
+
+	/* Create socket */
+	err = rfcomm_l2sock_create(&sock);
+	if (err < 0) { 
+		BT_ERR("Create socket failed %d", err);
+		return err;
+	}
+
+	/* Bind socket */
+	bacpy(&addr.l2_bdaddr, ba);
+	addr.l2_family = AF_BLUETOOTH;
+	addr.l2_psm    = htobs(RFCOMM_PSM);
+	err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+	if (err < 0) {
+		BT_ERR("Bind failed %d", err);
+		goto failed;
+	}
+
+	/* Set L2CAP options */
+	size = sizeof(opts);
+	sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size);
+
+	opts.imtu = RFCOMM_MAX_L2CAP_MTU;
+	sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size);
+
+	/* Start listening on the socket */
+	err = sock->ops->listen(sock, 10);
+	if (err) {
+		BT_ERR("Listen failed %d", err);
+		goto failed;
+	}
+
+	/* Add listening session */
+	s = rfcomm_session_add(sock, BT_LISTEN);
+	if (!s)
+		goto failed;
+
+	rfcomm_session_hold(s);
+	return 0;
+failed:
+	sock_release(sock);
+	return err;
+}
+
+static void rfcomm_kill_listener(void)
+{
+	struct rfcomm_session *s;
+	struct list_head *p, *n;
+
+	BT_DBG("");
+
+	list_for_each_safe(p, n, &session_list) {
+		s = list_entry(p, struct rfcomm_session, list);
+		rfcomm_session_del(s);
+	}
+}
+
+static int rfcomm_run(void *unused)
+{
+	rfcomm_thread = current;
+
+	atomic_inc(&running);
+
+	daemonize(); reparent_to_init();
+
+	sigfillset(&current->blocked);
+	set_fs(KERNEL_DS);
+
+	sprintf(current->comm, "krfcommd");
+
+	BT_DBG("");
+
+	rfcomm_add_listener(BDADDR_ANY);
+
+	rfcomm_worker();
+
+	rfcomm_kill_listener();
+
+	atomic_dec(&running);
+	return 0;
+}
+
+/* ---- Proc fs support ---- */
+static int rfcomm_dlc_dump(char *buf)
+{
+	struct rfcomm_session *s;
+	struct sock *sk;
+	struct list_head *p, *pp;
+	char *ptr = buf;
+
+	rfcomm_lock();
+
+	list_for_each(p, &session_list) {
+		s = list_entry(p, struct rfcomm_session, list);
+		sk = s->sock->sk;
+
+		list_for_each(pp, &s->dlcs) {
+		struct rfcomm_dlc *d;
+			d = list_entry(pp, struct rfcomm_dlc, list);
+
+			ptr += sprintf(ptr, "dlc %s %s %ld %d %d %d %d\n",
+				batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
+				d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits);
+		}
+	}
+	
+	rfcomm_unlock();
+
+	return ptr - buf;
+}
+
+extern int rfcomm_sock_dump(char *buf);
+
+static int rfcomm_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
+{
+	char *ptr = buf;
+	int len;
+
+	BT_DBG("count %d, offset %ld", count, offset);
+
+	ptr += rfcomm_dlc_dump(ptr);
+	ptr += rfcomm_sock_dump(ptr);
+	len  = ptr - buf;
+
+	if (len <= count + offset)
+		*eof = 1;
+
+	*start = buf + offset;
+	len -= offset;
+
+	if (len > count)
+		len = count;
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+
+/* ---- Initialization ---- */
+int __init rfcomm_init(void)
+{
+	kernel_thread(rfcomm_run, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+
+	rfcomm_init_sockets();
+
+#ifdef CONFIG_BLUEZ_RFCOMM_TTY
+	rfcomm_init_ttys();
+#endif
+
+	create_proc_read_entry("bluetooth/rfcomm", 0, 0, rfcomm_read_proc, NULL);
+
+	BT_INFO("BlueZ RFCOMM ver %s", VERSION);
+	BT_INFO("Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>");
+	BT_INFO("Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>");
+	return 0;
+}
+
+void rfcomm_cleanup(void)
+{
+	/* Terminate working thread.
+	 * ie. Set terminate flag and wake it up */
+	atomic_inc(&terminate);
+	rfcomm_schedule(RFCOMM_SCHED_STATE);
+
+	/* Wait until thread is running */
+	while (atomic_read(&running))
+		schedule();
+
+	remove_proc_entry("bluetooth/rfcomm", NULL);
+
+#ifdef CONFIG_BLUEZ_RFCOMM_TTY
+	rfcomm_cleanup_ttys();
+#endif
+
+	rfcomm_cleanup_sockets();
+	return;
+}
+
+module_init(rfcomm_init);
+module_exit(rfcomm_cleanup);
+
+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
+MODULE_DESCRIPTION("BlueZ RFCOMM ver " VERSION);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/rfcomm/crc.c linux-2.4.21/net/bluetooth/rfcomm/crc.c
--- linux-2.4.20/net/bluetooth/rfcomm/crc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/net/bluetooth/rfcomm/crc.c	2002-12-18 18:58:05.000000000 +0000
@@ -0,0 +1,71 @@
+/* 
+   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
+   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
+   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * RFCOMM FCS calculation.
+ *
+ * $Id: crc.c,v 1.2 2002/09/21 09:54:32 holtmann Exp $
+ */
+
+/* reversed, 8-bit, poly=0x07 */
+unsigned char rfcomm_crc_table[256] = { 
+	0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75,
+	0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b,
+	0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69,
+	0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67,
+
+	0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d,
+	0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43,
+	0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51,
+	0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f,
+
+	0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05,
+	0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b,
+	0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19,
+	0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17,
+
+	0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d,
+	0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33,
+	0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21,
+	0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f,
+
+	0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95,
+	0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b,
+	0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89,
+	0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87,
+
+	0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad,
+	0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3,
+	0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1,
+	0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf,
+
+	0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5,
+	0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb,
+	0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9,
+	0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7,
+
+	0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd,
+	0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3,
+	0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1,
+	0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/rfcomm/sock.c linux-2.4.21/net/bluetooth/rfcomm/sock.c
--- linux-2.4.20/net/bluetooth/rfcomm/sock.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/net/bluetooth/rfcomm/sock.c	2002-12-18 18:58:10.000000000 +0000
@@ -0,0 +1,840 @@
+/* 
+   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
+   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
+   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * RFCOMM sockets.
+ *
+ * $Id: sock.c,v 1.30 2002/10/18 20:12:12 maxk Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/list.h>
+#include <net/sock.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/rfcomm.h>
+
+#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
+#undef  BT_DBG
+#define BT_DBG(D...)
+#endif
+
+static struct proto_ops rfcomm_sock_ops;
+
+static struct bluez_sock_list rfcomm_sk_list = {
+	lock: RW_LOCK_UNLOCKED
+};
+
+static void rfcomm_sock_close(struct sock *sk);
+static void rfcomm_sock_kill(struct sock *sk);
+
+/* ---- DLC callbacks ----
+ *
+ * called under rfcomm_dlc_lock()
+ */
+static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb)
+{
+	struct sock *sk = d->owner;
+	if (!sk)
+		return;
+
+	atomic_add(skb->len, &sk->rmem_alloc);
+	skb_queue_tail(&sk->receive_queue, skb);
+	sk->data_ready(sk, skb->len);
+
+	if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf)
+		rfcomm_dlc_throttle(d);
+}
+
+static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
+{
+	struct sock *sk = d->owner, *parent;
+	if (!sk)
+		return;
+
+	BT_DBG("dlc %p state %ld err %d", d, d->state, err);
+
+	bh_lock_sock(sk);
+
+	if (err)
+		sk->err = err;
+	sk->state = d->state;
+
+	parent = bluez_pi(sk)->parent;
+	if (!parent) {
+		if (d->state == BT_CONNECTED)
+			rfcomm_session_getaddr(d->session, &bluez_pi(sk)->src, NULL);
+		sk->state_change(sk);
+	} else
+		parent->data_ready(parent, 0);
+
+	bh_unlock_sock(sk);
+}
+
+/* ---- Socket functions ---- */
+static struct sock *__rfcomm_get_sock_by_addr(int channel, bdaddr_t *src)
+{
+	struct sock *sk;
+
+	for (sk = rfcomm_sk_list.head; sk; sk = sk->next) {
+		if (rfcomm_pi(sk)->channel == channel && 
+				!bacmp(&bluez_pi(sk)->src, src))
+			break;
+	}
+
+	return sk;
+}
+
+/* Find socket with channel and source bdaddr.
+ * Returns closest match.
+ */
+static struct sock *__rfcomm_get_sock_by_channel(int state, __u16 channel, bdaddr_t *src)
+{
+	struct sock *sk, *sk1 = NULL;
+
+	for (sk = rfcomm_sk_list.head; sk; sk = sk->next) {
+		if (state && sk->state != state)
+			continue;
+
+		if (rfcomm_pi(sk)->channel == channel) {
+			/* Exact match. */
+			if (!bacmp(&bluez_pi(sk)->src, src))
+				break;
+
+			/* Closest match */
+			if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
+				sk1 = sk;
+		}
+	}
+	return sk ? sk : sk1;
+}
+
+/* Find socket with given address (channel, src).
+ * Returns locked socket */
+static inline struct sock *rfcomm_get_sock_by_channel(int state, __u16 channel, bdaddr_t *src)
+{
+	struct sock *s;
+	read_lock(&rfcomm_sk_list.lock);
+	s = __rfcomm_get_sock_by_channel(state, channel, src);
+	if (s) bh_lock_sock(s);
+	read_unlock(&rfcomm_sk_list.lock);
+	return s;
+}
+
+static void rfcomm_sock_destruct(struct sock *sk)
+{
+	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
+
+	BT_DBG("sk %p dlc %p", sk, d);
+
+	skb_queue_purge(&sk->receive_queue);
+	skb_queue_purge(&sk->write_queue);
+
+	rfcomm_dlc_lock(d);
+	rfcomm_pi(sk)->dlc = NULL;
+	
+	/* Detach DLC if it's owned by this socket */
+	if (d->owner == sk)
+		d->owner = NULL;
+	rfcomm_dlc_unlock(d);
+
+	rfcomm_dlc_put(d);
+
+	MOD_DEC_USE_COUNT;
+}
+
+static void rfcomm_sock_cleanup_listen(struct sock *parent)
+{
+	struct sock *sk;
+
+	BT_DBG("parent %p", parent);
+
+	/* Close not yet accepted dlcs */
+	while ((sk = bluez_accept_dequeue(parent, NULL)))
+		rfcomm_sock_close(sk);
+
+	parent->state  = BT_CLOSED;
+	parent->zapped = 1;
+}
+
+/* Kill socket (only if zapped and orphan)
+ * Must be called on unlocked socket.
+ */
+static void rfcomm_sock_kill(struct sock *sk)
+{
+	if (!sk->zapped || sk->socket)
+		return;
+
+	BT_DBG("sk %p state %d refcnt %d", sk, sk->state, atomic_read(&sk->refcnt));
+
+	/* Kill poor orphan */
+	bluez_sock_unlink(&rfcomm_sk_list, sk);
+	sk->dead = 1;
+	sock_put(sk);
+}
+
+/* Close socket.
+ * Must be called on unlocked socket.
+ */
+static void rfcomm_sock_close(struct sock *sk)
+{
+	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
+
+	lock_sock(sk);
+
+	BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket);
+
+	switch (sk->state) {
+	case BT_LISTEN:
+		rfcomm_sock_cleanup_listen(sk);
+		break;
+
+	case BT_CONNECT:
+	case BT_CONNECT2:
+	case BT_CONFIG:
+	case BT_CONNECTED:
+		rfcomm_dlc_close(d, 0);
+
+	default:
+		sk->zapped = 1;
+		break;
+	};
+
+	release_sock(sk);
+
+	rfcomm_sock_kill(sk);
+}
+
+static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
+{
+	BT_DBG("sk %p", sk);
+
+	if (parent) 
+		sk->type = parent->type;
+}
+
+static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, int prio)
+{
+	struct rfcomm_dlc *d;
+	struct sock *sk;
+
+	sk = sk_alloc(PF_BLUETOOTH, prio, 1);
+	if (!sk)
+		return NULL;
+
+	d = rfcomm_dlc_alloc(prio);
+	if (!d) {
+		sk_free(sk);
+		return NULL;
+	}
+	d->data_ready   = rfcomm_sk_data_ready;
+	d->state_change = rfcomm_sk_state_change;
+
+	rfcomm_pi(sk)->dlc = d;
+	d->owner = sk;
+
+	bluez_sock_init(sock, sk);
+
+	sk->zapped   = 0;
+
+	sk->destruct = rfcomm_sock_destruct;
+	sk->sndtimeo = RFCOMM_CONN_TIMEOUT;
+
+	sk->sndbuf   = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
+	sk->rcvbuf   = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
+
+	sk->protocol = proto;
+	sk->state    = BT_OPEN;
+
+	bluez_sock_link(&rfcomm_sk_list, sk);
+
+	BT_DBG("sk %p", sk);
+
+	MOD_INC_USE_COUNT;
+	return sk;
+}
+
+static int rfcomm_sock_create(struct socket *sock, int protocol)
+{
+	struct sock *sk;
+
+	BT_DBG("sock %p", sock);
+
+	sock->state = SS_UNCONNECTED;
+
+	if (sock->type != SOCK_STREAM && sock->type != SOCK_RAW)
+		return -ESOCKTNOSUPPORT;
+
+	sock->ops = &rfcomm_sock_ops;
+
+	if (!(sk = rfcomm_sock_alloc(sock, protocol, GFP_KERNEL)))
+		return -ENOMEM;
+
+	rfcomm_sock_init(sk, NULL);
+	return 0;
+}
+
+static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
+{
+	struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
+	struct sock *sk = sock->sk;
+	int err = 0;
+
+	BT_DBG("sk %p %s", sk, batostr(&sa->rc_bdaddr));
+
+	if (!addr || addr->sa_family != AF_BLUETOOTH)
+		return -EINVAL;
+
+	lock_sock(sk);
+
+	if (sk->state != BT_OPEN) {
+		err = -EBADFD;
+		goto done;
+	}
+
+	write_lock_bh(&rfcomm_sk_list.lock);
+
+	if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) {
+		err = -EADDRINUSE;
+	} else {
+		/* Save source address */
+		bacpy(&bluez_pi(sk)->src, &sa->rc_bdaddr);
+		rfcomm_pi(sk)->channel = sa->rc_channel;
+		sk->state = BT_BOUND;
+	}
+
+	write_unlock_bh(&rfcomm_sk_list.lock);
+
+done:
+	release_sock(sk);
+	return err;
+}
+
+static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
+{
+	struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
+	struct sock *sk = sock->sk;
+	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
+	int err = 0;
+
+	BT_DBG("sk %p", sk);
+
+	if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_rc))
+		return -EINVAL;
+
+	if (sk->state != BT_OPEN && sk->state != BT_BOUND)
+		return -EBADFD;
+
+	if (sk->type != SOCK_STREAM)
+		return -EINVAL;
+
+	lock_sock(sk);
+
+	sk->state = BT_CONNECT;
+	bacpy(&bluez_pi(sk)->dst, &sa->rc_bdaddr);
+	rfcomm_pi(sk)->channel = sa->rc_channel;
+	
+	err = rfcomm_dlc_open(d, &bluez_pi(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
+	if (!err)
+		err = bluez_sock_w4_connect(sk, flags);
+
+	release_sock(sk);
+	return err;
+}
+
+int rfcomm_sock_listen(struct socket *sock, int backlog)
+{
+	struct sock *sk = sock->sk;
+	int err = 0;
+
+	BT_DBG("sk %p backlog %d", sk, backlog);
+
+	lock_sock(sk);
+
+	if (sk->state != BT_BOUND) {
+		err = -EBADFD;
+		goto done;
+	}
+
+	sk->max_ack_backlog = backlog;
+	sk->ack_backlog = 0;
+	sk->state = BT_LISTEN;
+
+done:
+	release_sock(sk);
+	return err;
+}
+
+int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct sock *sk = sock->sk, *nsk;
+	long timeo;
+	int err = 0;
+
+	lock_sock(sk);
+
+	if (sk->state != BT_LISTEN) {
+		err = -EBADFD;
+		goto done;
+	}
+
+	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
+
+	BT_DBG("sk %p timeo %ld", sk, timeo);
+
+	/* Wait for an incoming connection. (wake-one). */
+	add_wait_queue_exclusive(sk->sleep, &wait);
+	while (!(nsk = bluez_accept_dequeue(sk, newsock))) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (!timeo) {
+			err = -EAGAIN;
+			break;
+		}
+
+		release_sock(sk);
+		timeo = schedule_timeout(timeo);
+		lock_sock(sk);
+
+		if (sk->state != BT_LISTEN) {
+			err = -EBADFD;
+			break;
+		}
+
+		if (signal_pending(current)) {
+			err = sock_intr_errno(timeo);
+			break;
+		}
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(sk->sleep, &wait);
+
+	if (err)
+		goto done;
+
+	newsock->state = SS_CONNECTED;
+
+	BT_DBG("new socket %p", nsk);
+
+done:
+	release_sock(sk);
+	return err;
+}
+
+static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
+{
+	struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
+	struct sock *sk = sock->sk;
+
+	BT_DBG("sock %p, sk %p", sock, sk);
+
+	sa->rc_family  = AF_BLUETOOTH;
+	sa->rc_channel = rfcomm_pi(sk)->channel;
+	if (peer)
+		bacpy(&sa->rc_bdaddr, &bluez_pi(sk)->dst);
+	else
+		bacpy(&sa->rc_bdaddr, &bluez_pi(sk)->src);
+
+	*len = sizeof(struct sockaddr_rc);
+	return 0;
+}
+
+static int rfcomm_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+			       struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
+	struct sk_buff *skb;
+	int err, size;
+	int sent = 0;
+
+	if (msg->msg_flags & MSG_OOB)
+		return -EOPNOTSUPP;
+
+	if (sk->shutdown & SEND_SHUTDOWN)
+		return -EPIPE;
+
+	BT_DBG("sock %p, sk %p", sock, sk);
+
+	lock_sock(sk);
+
+	while (len) {
+		size = min_t(uint, len, d->mtu);
+		
+		skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE,
+				msg->msg_flags & MSG_DONTWAIT, &err);
+		if (!skb)
+			break;
+		skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
+
+		err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
+		if (err) {
+			kfree_skb(skb);
+			sent = err;
+			break;
+		}
+
+		err = rfcomm_dlc_send(d, skb);
+		if (err < 0) {
+			kfree_skb(skb);
+			break;
+		}
+
+		sent += size;
+		len  -= size;
+	}
+
+	release_sock(sk);
+
+	return sent ? sent : err;
+}
+
+static long rfcomm_sock_data_wait(struct sock *sk, long timeo)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	add_wait_queue(sk->sleep, &wait);
+	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		if (skb_queue_len(&sk->receive_queue) || sk->err || (sk->shutdown & RCV_SHUTDOWN) ||
+				signal_pending(current) || !timeo)
+			break;
+
+		set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
+		release_sock(sk);
+		timeo = schedule_timeout(timeo);
+		lock_sock(sk);
+		clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
+	}
+
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(sk->sleep, &wait);
+	return timeo;
+}
+
+static int rfcomm_sock_recvmsg(struct socket *sock, struct msghdr *msg, int size,
+			       int flags, struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	int target, err = 0, copied = 0;
+	long timeo;
+
+	if (sk->state != BT_CONNECTED)
+		return -EINVAL;
+
+	if (flags & MSG_OOB)
+		return -EOPNOTSUPP;
+
+	msg->msg_namelen = 0;
+
+	BT_DBG("sk %p size %d", sk, size);
+
+	lock_sock(sk);
+
+	target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
+	timeo  = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
+
+	do {
+		struct sk_buff *skb;
+		int chunk;
+
+		skb = skb_dequeue(&sk->receive_queue);
+		if (!skb) {
+			if (copied >= target)
+				break;
+
+			if ((err = sock_error(sk)) != 0)
+				break;
+			if (sk->shutdown & RCV_SHUTDOWN)
+				break;
+
+			err = -EAGAIN;
+			if (!timeo)
+				break;
+
+			timeo = rfcomm_sock_data_wait(sk, timeo);
+
+			if (signal_pending(current)) {
+				err = sock_intr_errno(timeo);
+				goto out;
+			}
+			continue;
+		}
+
+		chunk = min_t(unsigned int, skb->len, size);
+		if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
+			skb_queue_head(&sk->receive_queue, skb);
+			if (!copied)
+				copied = -EFAULT;
+			break;
+		}
+		copied += chunk;
+		size   -= chunk;
+
+		if (!(flags & MSG_PEEK)) {
+			atomic_sub(chunk, &sk->rmem_alloc);
+
+			skb_pull(skb, chunk);
+			if (skb->len) {
+				skb_queue_head(&sk->receive_queue, skb);
+				break;
+			}
+			kfree_skb(skb);
+
+		} else {
+			/* put message back and return */
+			skb_queue_head(&sk->receive_queue, skb);
+			break;
+		}
+	} while (size);
+
+out:
+	if (atomic_read(&sk->rmem_alloc) <= (sk->rcvbuf >> 2))
+		rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc);
+
+	release_sock(sk);
+	return copied ? : err;
+}
+
+static int rfcomm_sock_shutdown(struct socket *sock, int how)
+{
+	struct sock *sk = sock->sk;
+
+	BT_DBG("sock %p, sk %p", sock, sk);
+
+	if (!sk) return 0;
+
+	lock_sock(sk);
+	sk->shutdown = SHUTDOWN_MASK;
+	if (sk->state == BT_CONNECTED)
+		rfcomm_dlc_close(rfcomm_pi(sk)->dlc, 0);
+	release_sock(sk);
+
+	return 0;
+}
+
+static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
+{
+	struct sock *sk = sock->sk;
+	int err = 0;
+
+	BT_DBG("sk %p", sk);
+
+	lock_sock(sk);
+
+	switch (optname) {
+	default:
+		err = -ENOPROTOOPT;
+		break;
+	};
+
+	release_sock(sk);
+	return err;
+}
+
+static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
+{
+	struct sock *sk = sock->sk;
+	int len, err = 0; 
+
+	BT_DBG("sk %p", sk);
+
+	if (get_user(len, optlen))
+		return -EFAULT;
+
+	lock_sock(sk);
+
+	switch (optname) {
+	default:
+		err = -ENOPROTOOPT;
+		break;
+	};
+
+	release_sock(sk);
+	return err;
+}
+
+static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+	struct sock *sk = sock->sk;
+	int err;
+
+	lock_sock(sk);
+
+#ifdef CONFIG_BLUEZ_RFCOMM_TTY
+	err = rfcomm_dev_ioctl(sk, cmd, arg);
+#else
+	err = -EOPNOTSUPP;
+#endif
+
+	release_sock(sk);
+
+	return err;
+}
+
+static int rfcomm_sock_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+
+	BT_DBG("sock %p, sk %p", sock, sk);
+
+	if (!sk)
+		return 0;
+
+	sock_orphan(sk);
+	rfcomm_sock_close(sk);
+
+	return 0;
+}
+
+/* ---- RFCOMM core layer callbacks ---- 
+ *
+ * called under rfcomm_lock()
+ */
+int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d)
+{
+	struct sock *sk, *parent;
+	bdaddr_t src, dst;
+	int result = 0;
+
+	BT_DBG("session %p channel %d", s, channel);
+
+	rfcomm_session_getaddr(s, &src, &dst);
+
+	/* Check if we have socket listening on this channel */
+	parent = rfcomm_get_sock_by_channel(BT_LISTEN, channel, &src);
+	if (!parent)
+		return 0;
+
+	/* Check for backlog size */
+	if (parent->ack_backlog > parent->max_ack_backlog) {
+		BT_DBG("backlog full %d", parent->ack_backlog); 
+		goto done;
+	}
+
+	sk = rfcomm_sock_alloc(NULL, BTPROTO_RFCOMM, GFP_ATOMIC);
+	if (!sk)
+		goto done;
+
+	rfcomm_sock_init(sk, parent);
+	bacpy(&bluez_pi(sk)->src, &src);
+	bacpy(&bluez_pi(sk)->dst, &dst);
+	rfcomm_pi(sk)->channel = channel;
+
+	sk->state = BT_CONFIG;
+	bluez_accept_enqueue(parent, sk);
+
+	/* Accept connection and return socket DLC */
+	*d = rfcomm_pi(sk)->dlc;
+	result = 1;
+
+done:
+	bh_unlock_sock(parent);
+	return result;
+}
+
+/* ---- Proc fs support ---- */
+int rfcomm_sock_dump(char *buf)
+{
+	struct bluez_sock_list *list = &rfcomm_sk_list;
+	struct rfcomm_pinfo *pi;
+	struct sock *sk;
+	char *ptr = buf;
+
+	write_lock_bh(&list->lock);
+
+	for (sk = list->head; sk; sk = sk->next) {
+		pi = rfcomm_pi(sk);
+		ptr += sprintf(ptr, "sk  %s %s %d %d\n",
+				batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
+				sk->state, rfcomm_pi(sk)->channel);
+	}
+
+	write_unlock_bh(&list->lock);
+
+	return ptr - buf;
+}
+
+static struct proto_ops rfcomm_sock_ops = {
+	family:		PF_BLUETOOTH,
+	release:	rfcomm_sock_release,
+	bind:		rfcomm_sock_bind,
+	connect:	rfcomm_sock_connect,
+	listen:		rfcomm_sock_listen,
+	accept:		rfcomm_sock_accept,
+	getname:	rfcomm_sock_getname,
+	sendmsg:	rfcomm_sock_sendmsg,
+	recvmsg:	rfcomm_sock_recvmsg,
+	shutdown:	rfcomm_sock_shutdown,
+	setsockopt:	rfcomm_sock_setsockopt,
+	getsockopt:	rfcomm_sock_getsockopt,
+	ioctl:		rfcomm_sock_ioctl,
+	poll:		bluez_sock_poll,
+	socketpair:	sock_no_socketpair,
+	mmap:		sock_no_mmap
+};
+
+static struct net_proto_family rfcomm_sock_family_ops = {
+	family:		PF_BLUETOOTH,
+	create:		rfcomm_sock_create
+};
+
+int rfcomm_init_sockets(void)
+{
+	int err;
+
+	if ((err = bluez_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops))) {
+		BT_ERR("Can't register RFCOMM socket layer");
+		return err;
+	}
+
+	return 0;
+}
+
+void rfcomm_cleanup_sockets(void)
+{
+	int err;
+
+	/* Unregister socket, protocol and notifier */
+	if ((err = bluez_sock_unregister(BTPROTO_RFCOMM)))
+		BT_ERR("Can't unregister RFCOMM socket layer %d", err);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/rfcomm/tty.c linux-2.4.21/net/bluetooth/rfcomm/tty.c
--- linux-2.4.20/net/bluetooth/rfcomm/tty.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21/net/bluetooth/rfcomm/tty.c	2002-12-18 18:58:05.000000000 +0000
@@ -0,0 +1,914 @@
+/* 
+   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
+   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
+   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * RFCOMM TTY.
+ *
+ * $Id: tty.c,v 1.26 2002/10/18 20:12:12 maxk Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/rfcomm.h>
+
+#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
+#undef  BT_DBG
+#define BT_DBG(D...)
+#endif
+
+#define RFCOMM_TTY_MAGIC 0x6d02		/* magic number for rfcomm struct */
+#define RFCOMM_TTY_PORTS RFCOMM_MAX_DEV	/* whole lotta rfcomm devices */
+#define RFCOMM_TTY_MAJOR 216		/* device node major id of the usb/bluetooth.c driver */
+#define RFCOMM_TTY_MINOR 0
+
+struct rfcomm_dev {
+	struct list_head	list;
+	atomic_t		refcnt;
+
+	char			name[12];
+	int			id;
+	unsigned long		flags;
+	int			opened;
+	int			err;
+
+	bdaddr_t		src;
+	bdaddr_t		dst;
+	u8 			channel;
+
+	uint 			modem_status;
+
+	struct rfcomm_dlc	*dlc;
+	struct tty_struct	*tty;
+	wait_queue_head_t       wait;
+	struct tasklet_struct   wakeup_task;
+
+	atomic_t 		wmem_alloc;
+	unsigned int 		sndbuf;
+};
+
+static LIST_HEAD(rfcomm_dev_list);
+static rwlock_t rfcomm_dev_lock = RW_LOCK_UNLOCKED;
+
+static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb);
+static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
+static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
+
+static void rfcomm_tty_wakeup(unsigned long arg);
+
+/* ---- Device functions ---- */
+static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
+{
+	struct rfcomm_dlc *dlc = dev->dlc;
+
+	BT_DBG("dev %p dlc %p", dev, dlc);
+
+	rfcomm_dlc_lock(dlc);
+	/* Detach DLC if it's owned by this dev */
+	if (dlc->owner == dev)
+		dlc->owner = NULL;
+	rfcomm_dlc_unlock(dlc);
+
+	rfcomm_dlc_put(dlc);
+	kfree(dev);
+
+	MOD_DEC_USE_COUNT;
+}
+
+static inline void rfcomm_dev_hold(struct rfcomm_dev *dev)
+{
+	atomic_inc(&dev->refcnt);
+}
+
+static inline void rfcomm_dev_put(struct rfcomm_dev *dev)
+{
+	if (atomic_dec_and_test(&dev->refcnt))
+		rfcomm_dev_destruct(dev);
+}
+
+static struct rfcomm_dev *__rfcomm_dev_get(int id)
+{
+	struct rfcomm_dev *dev;
+	struct list_head  *p;
+
+	list_for_each(p, &rfcomm_dev_list) {
+		dev = list_entry(p, struct rfcomm_dev, list);
+		if (dev->id == id)
+			return dev;
+	}
+
+	return NULL;
+}
+
+static inline struct rfcomm_dev *rfcomm_dev_get(int id)
+{
+	struct rfcomm_dev *dev;
+
+	read_lock(&rfcomm_dev_lock);
+	dev = __rfcomm_dev_get(id);
+	read_unlock(&rfcomm_dev_lock);
+
+	if (dev) rfcomm_dev_hold(dev);
+	return dev;
+}
+
+static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
+{
+	struct rfcomm_dev *dev;
+	struct list_head *head = &rfcomm_dev_list, *p;
+	int err = 0;
+
+	BT_DBG("id %d channel %d", req->dev_id, req->channel);
+	
+	dev = kmalloc(sizeof(struct rfcomm_dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+	memset(dev, 0, sizeof(struct rfcomm_dev));
+
+	write_lock_bh(&rfcomm_dev_lock);
+
+	if (req->dev_id < 0) {
+		dev->id = 0;
+
+		list_for_each(p, &rfcomm_dev_list) {
+			if (list_entry(p, struct rfcomm_dev, list)->id != dev->id)
+				break;
+
+			dev->id++;
+			head = p;
+		}
+	} else {
+		dev->id = req->dev_id;
+
+		list_for_each(p, &rfcomm_dev_list) {
+			struct rfcomm_dev *entry = list_entry(p, struct rfcomm_dev, list);
+
+			if (entry->id == dev->id) {
+				err = -EADDRINUSE;
+				goto out;
+			}
+
+			if (entry->id > dev->id - 1)
+				break;
+
+			head = p;
+		}
+	}
+
+	if ((dev->id < 0) || (dev->id > RFCOMM_MAX_DEV - 1)) {
+		err = -ENFILE;
+		goto out;
+	}
+
+	sprintf(dev->name, "rfcomm%d", dev->id);
+
+	list_add(&dev->list, head);
+	atomic_set(&dev->refcnt, 1);
+
+	bacpy(&dev->src, &req->src);
+	bacpy(&dev->dst, &req->dst);
+	dev->channel = req->channel;
+
+	dev->flags = req->flags & 
+		((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC));
+
+	dev->sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
+
+	init_waitqueue_head(&dev->wait);
+	tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev);
+
+	rfcomm_dlc_lock(dlc);
+	dlc->data_ready   = rfcomm_dev_data_ready;
+	dlc->state_change = rfcomm_dev_state_change;
+	dlc->modem_status = rfcomm_dev_modem_status;
+
+	dlc->owner = dev;
+	dev->dlc   = dlc;
+	rfcomm_dlc_unlock(dlc);
+
+	MOD_INC_USE_COUNT;
+	
+out:
+	write_unlock_bh(&rfcomm_dev_lock);
+
+	if (err) {
+		kfree(dev);
+		return err;
+	} else
+		return dev->id;
+}
+
+static void rfcomm_dev_del(struct rfcomm_dev *dev)
+{
+	BT_DBG("dev %p", dev);
+
+	write_lock_bh(&rfcomm_dev_lock);
+	list_del_init(&dev->list);
+	write_unlock_bh(&rfcomm_dev_lock);
+
+	rfcomm_dev_put(dev);
+}
+
+/* ---- Send buffer ---- */
+static void rfcomm_wfree(struct sk_buff *skb)
+{
+	struct rfcomm_dev *dev = (void *) skb->sk;
+	atomic_sub(skb->truesize, &dev->wmem_alloc);
+	if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
+		tasklet_schedule(&dev->wakeup_task);
+	rfcomm_dev_put(dev);
+}
+
+static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
+{
+	rfcomm_dev_hold(dev);
+	atomic_add(skb->truesize, &dev->wmem_alloc);
+	skb->sk = (void *) dev;
+	skb->destructor = rfcomm_wfree;
+}
+
+static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, int priority)
+{
+	if (size || atomic_read(&dev->wmem_alloc) < dev->sndbuf) {
+		struct sk_buff *skb = alloc_skb(size, priority);
+		if (skb) {
+			rfcomm_set_owner_w(skb, dev);
+			return skb;
+		}
+	}
+	return NULL;
+}
+
+/* ---- Device IOCTLs ---- */
+
+#define NOCAP_FLAGS ((1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP))
+
+static int rfcomm_create_dev(struct sock *sk, unsigned long arg)
+{
+	struct rfcomm_dev_req req;
+	struct rfcomm_dlc *dlc;
+	int id;
+
+	if (copy_from_user(&req, (void *) arg, sizeof(req)))
+		return -EFAULT;
+
+	BT_DBG("sk %p dev_id %id flags 0x%x", sk, req.dev_id, req.flags);
+
+	if (req.flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (req.flags & (1 << RFCOMM_REUSE_DLC)) {
+		/* Socket must be connected */
+		if (sk->state != BT_CONNECTED)
+			return -EBADFD;
+
+		dlc = rfcomm_pi(sk)->dlc;
+		rfcomm_dlc_hold(dlc);
+	} else {
+		dlc = rfcomm_dlc_alloc(GFP_KERNEL);
+		if (!dlc)
+			return -ENOMEM;
+	}
+
+	id = rfcomm_dev_add(&req, dlc);
+	if (id < 0) {
+		rfcomm_dlc_put(dlc);
+		return id;
+	}
+
+	if (req.flags & (1 << RFCOMM_REUSE_DLC)) {
+		/* DLC is now used by device.
+		 * Socket must be disconnected */
+		sk->state = BT_CLOSED;
+	}
+
+	return id;
+}
+
+static int rfcomm_release_dev(unsigned long arg)
+{
+	struct rfcomm_dev_req req;
+	struct rfcomm_dev *dev;
+
+	if (copy_from_user(&req, (void *) arg, sizeof(req)))
+		return -EFAULT;
+
+	BT_DBG("dev_id %id flags 0x%x", req.dev_id, req.flags);
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (!(dev = rfcomm_dev_get(req.dev_id)))
+		return -ENODEV;
+
+	if (req.flags & (1 << RFCOMM_HANGUP_NOW))
+		rfcomm_dlc_close(dev->dlc, 0);
+
+	rfcomm_dev_del(dev);
+	rfcomm_dev_put(dev);
+	return 0;
+}
+
+static int rfcomm_get_dev_list(unsigned long arg)
+{
+	struct rfcomm_dev_list_req *dl;
+	struct rfcomm_dev_info *di;
+	struct list_head *p;
+	int n = 0, size;
+	u16 dev_num;
+
+	BT_DBG("");
+
+	if (get_user(dev_num, (u16 *) arg))
+		return -EFAULT;
+
+	if (!dev_num)
+		return -EINVAL;
+
+	size = sizeof(*dl) + dev_num * sizeof(*di);
+
+	if (verify_area(VERIFY_WRITE, (void *)arg, size))
+		return -EFAULT;
+
+	if (!(dl = kmalloc(size, GFP_KERNEL)))
+		return -ENOMEM;
+
+	di = dl->dev_info;
+
+	read_lock_bh(&rfcomm_dev_lock);
+
+	list_for_each(p, &rfcomm_dev_list) {
+		struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list);
+		(di + n)->id      = dev->id;
+		(di + n)->flags   = dev->flags;
+		(di + n)->state   = dev->dlc->state;
+		(di + n)->channel = dev->channel;
+		bacpy(&(di + n)->src, &dev->src);
+		bacpy(&(di + n)->dst, &dev->dst);
+		if (++n >= dev_num)
+			break;
+	}
+
+	read_unlock_bh(&rfcomm_dev_lock);
+
+	dl->dev_num = n;
+	size = sizeof(*dl) + n * sizeof(*di);
+
+	copy_to_user((void *) arg, dl, size);
+	kfree(dl);
+	return 0;
+}
+
+static int rfcomm_get_dev_info(unsigned long arg)
+{
+	struct rfcomm_dev *dev;
+	struct rfcomm_dev_info di;
+	int err = 0;
+
+	BT_DBG("");
+
+	if (copy_from_user(&di, (void *)arg, sizeof(di)))
+		return -EFAULT;
+
+	if (!(dev = rfcomm_dev_get(di.id)))
+		return -ENODEV;
+
+	di.flags   = dev->flags;
+	di.channel = dev->channel;
+	di.state   = dev->dlc->state;
+	bacpy(&di.src, &dev->src);
+	bacpy(&di.dst, &dev->dst);
+
+	if (copy_to_user((void *)arg, &di, sizeof(di)))
+		err = -EFAULT;
+
+	rfcomm_dev_put(dev);
+	return err;
+}
+
+int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
+{
+	BT_DBG("cmd %d arg %ld", cmd, arg);
+
+	switch (cmd) {
+	case RFCOMMCREATEDEV:
+		return rfcomm_create_dev(sk, arg);
+
+	case RFCOMMRELEASEDEV:
+		return rfcomm_release_dev(arg);
+
+	case RFCOMMGETDEVLIST:
+		return rfcomm_get_dev_list(arg);
+
+	case RFCOMMGETDEVINFO:
+		return rfcomm_get_dev_info(arg);
+	}
+
+	return -EINVAL;
+}
+
+/* ---- DLC callbacks ---- */
+static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
+{
+	struct rfcomm_dev *dev = dlc->owner;
+	struct tty_struct *tty;
+       
+	if (!dev || !(tty = dev->tty)) {
+		kfree_skb(skb);
+		return;
+	}
+
+	BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len);
+
+	if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
+		register int i;
+		for (i = 0; i < skb->len; i++) {
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+				tty_flip_buffer_push(tty);
+
+			tty_insert_flip_char(tty, skb->data[i], 0);
+		}
+		tty_flip_buffer_push(tty);
+	} else
+		tty->ldisc.receive_buf(tty, skb->data, NULL, skb->len);
+
+	kfree_skb(skb);
+}
+
+static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
+{
+	struct rfcomm_dev *dev = dlc->owner;
+	if (!dev)
+		return;
+	
+	BT_DBG("dlc %p dev %p err %d", dlc, dev, err);
+
+	dev->err = err;
+	wake_up_interruptible(&dev->wait);
+
+	if (dlc->state == BT_CLOSED) {
+		if (!dev->tty) {
+			if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
+				rfcomm_dev_hold(dev);
+				rfcomm_dev_del(dev);
+
+				/* We have to drop DLC lock here, otherwise
+				 * rfcomm_dev_put() will dead lock if it's the last refference */
+				rfcomm_dlc_unlock(dlc);
+				rfcomm_dev_put(dev);
+				rfcomm_dlc_lock(dlc);
+			}
+		} else 
+			tty_hangup(dev->tty);
+	}
+}
+
+static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
+{
+	struct rfcomm_dev *dev = dlc->owner;
+	if (!dev)
+		return;
+	
+	BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig);
+
+	dev->modem_status = 
+		((v24_sig & RFCOMM_V24_RTC) ? (TIOCM_DSR | TIOCM_DTR) : 0) |
+		((v24_sig & RFCOMM_V24_RTR) ? (TIOCM_RTS | TIOCM_CTS) : 0) |
+		((v24_sig & RFCOMM_V24_IC)  ? TIOCM_RI : 0) |
+		((v24_sig & RFCOMM_V24_DV)  ? TIOCM_CD : 0);
+}
+
+/* ---- TTY functions ---- */
+static void rfcomm_tty_wakeup(unsigned long arg)
+{
+	struct rfcomm_dev *dev = (void *) arg;
+	struct tty_struct *tty = dev->tty;
+	if (!tty)
+		return;
+
+	BT_DBG("dev %p tty %p", dev, tty);
+
+	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
+                (tty->ldisc.write_wakeup)(tty);
+
+	wake_up_interruptible(&tty->write_wait);
+#ifdef SERIAL_HAVE_POLL_WAIT
+	wake_up_interruptible(&tty->poll_wait);
+#endif
+}
+
+static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct rfcomm_dev *dev;
+	struct rfcomm_dlc *dlc;
+	int err, id;
+
+	id = MINOR(tty->device) - tty->driver.minor_start;
+
+	BT_DBG("tty %p id %d", tty, id);
+
+	dev = rfcomm_dev_get(id);
+	if (!dev)
+		return -ENODEV;
+
+	BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst), dev->channel, dev->opened);
+
+	if (dev->opened++ != 0)
+		return 0;
+
+	dlc = dev->dlc;
+
+	/* Attach TTY and open DLC */
+
+	rfcomm_dlc_lock(dlc);
+	tty->driver_data = dev;
+	dev->tty = tty;
+	rfcomm_dlc_unlock(dlc);
+	set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
+
+	err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel);
+	if (err < 0)
+		return err;
+
+	/* Wait for DLC to connect */
+	add_wait_queue(&dev->wait, &wait);
+	while (1) {
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		if (dlc->state == BT_CLOSED) {
+			err = -dev->err;
+			break;
+		}
+
+		if (dlc->state == BT_CONNECTED)
+			break;
+
+		if (signal_pending(current)) {
+			err = -EINTR;
+			break;
+		}
+
+		schedule();
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&dev->wait, &wait);
+
+	return err;
+}
+
+static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
+{
+	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+	if (!dev)
+		return;
+
+	BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, dev->opened);
+
+	if (--dev->opened == 0) {
+		/* Close DLC and dettach TTY */
+		rfcomm_dlc_close(dev->dlc, 0);
+
+		clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
+		tasklet_kill(&dev->wakeup_task);
+
+		rfcomm_dlc_lock(dev->dlc);
+		tty->driver_data = NULL;
+		dev->tty = NULL;
+		rfcomm_dlc_unlock(dev->dlc);
+	}
+
+	rfcomm_dev_put(dev);
+}
+
+static int rfcomm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
+{
+	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+	struct rfcomm_dlc *dlc = dev->dlc;
+	struct sk_buff *skb;
+	int err = 0, sent = 0, size;
+
+	BT_DBG("tty %p from_user %d count %d", tty, from_user, count);
+
+	while (count) {
+		size = min_t(uint, count, dlc->mtu);
+
+		if (from_user)
+			skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, GFP_KERNEL);
+		else
+			skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, GFP_ATOMIC);
+		
+		if (!skb)
+			break;
+
+		skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
+
+		if (from_user)
+			copy_from_user(skb_put(skb, size), buf + sent, size);
+		else
+			memcpy(skb_put(skb, size), buf + sent, size);
+
+		if ((err = rfcomm_dlc_send(dlc, skb)) < 0) {
+			kfree_skb(skb);
+			break;
+		}
+
+		sent  += size;
+		count -= size;
+	}
+
+	return sent ? sent : err;
+}
+
+static int rfcomm_tty_write_room(struct tty_struct *tty)
+{
+	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+	struct rfcomm_dlc *dlc = dev->dlc;
+
+	BT_DBG("tty %p", tty);
+
+	return dlc->mtu * (dlc->tx_credits ? : 10);
+}
+
+static int rfcomm_tty_set_modem_status(uint cmd, struct rfcomm_dlc *dlc, uint status)
+{
+	u8 v24_sig, mask;
+
+	BT_DBG("dlc %p cmd 0x%02x", dlc, cmd);
+
+	if (cmd == TIOCMSET)
+		v24_sig = 0;
+	else
+		rfcomm_dlc_get_modem_status(dlc, &v24_sig);
+
+	mask =  ((status & TIOCM_DSR) ? RFCOMM_V24_RTC : 0) |
+		((status & TIOCM_DTR) ? RFCOMM_V24_RTC : 0) |
+		((status & TIOCM_RTS) ? RFCOMM_V24_RTR : 0) |
+		((status & TIOCM_CTS) ? RFCOMM_V24_RTR : 0) |
+		((status & TIOCM_RI)  ? RFCOMM_V24_IC  : 0) |
+		((status & TIOCM_CD)  ? RFCOMM_V24_DV  : 0);
+
+	if (cmd == TIOCMBIC)
+		v24_sig &= ~mask;
+	else
+		v24_sig |= mask;
+
+	rfcomm_dlc_set_modem_status(dlc, v24_sig);
+	return 0;
+}
+
+static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+	struct rfcomm_dlc *dlc = dev->dlc;
+	uint status;
+	int err;
+
+	BT_DBG("tty %p cmd 0x%02x", tty, cmd);
+
+	switch (cmd) {
+	case TCGETS:
+		BT_DBG("TCGETS is not supported");
+		return -ENOIOCTLCMD;
+
+	case TCSETS:
+		BT_DBG("TCSETS is not supported");
+		return -ENOIOCTLCMD;
+
+	case TIOCMGET:
+		BT_DBG("TIOCMGET");
+
+		return put_user(dev->modem_status, (unsigned int *)arg);
+
+	case TIOCMSET: /* Turns on and off the lines as specified by the mask */
+	case TIOCMBIS: /* Turns on the lines as specified by the mask */
+	case TIOCMBIC: /* Turns off the lines as specified by the mask */
+		if ((err = get_user(status, (unsigned int *)arg)))
+			return err;
+		return rfcomm_tty_set_modem_status(cmd, dlc, status);
+
+	case TIOCMIWAIT:
+		BT_DBG("TIOCMIWAIT");
+		break;
+
+	case TIOCGICOUNT:
+		BT_DBG("TIOCGICOUNT");
+		break;
+
+	case TIOCGSERIAL:
+		BT_ERR("TIOCGSERIAL is not supported");
+		return -ENOIOCTLCMD;
+
+	case TIOCSSERIAL:
+		BT_ERR("TIOCSSERIAL is not supported");
+		return -ENOIOCTLCMD;
+
+	case TIOCSERGSTRUCT:
+		BT_ERR("TIOCSERGSTRUCT is not supported");
+		return -ENOIOCTLCMD;
+
+	case TIOCSERGETLSR:
+		BT_ERR("TIOCSERGETLSR is not supported");
+		return -ENOIOCTLCMD;
+
+	case TIOCSERCONFIG:
+		BT_ERR("TIOCSERCONFIG is not supported");
+		return -ENOIOCTLCMD;
+
+	default:
+		return -ENOIOCTLCMD;	/* ioctls which we must ignore */
+
+	}
+
+	return -ENOIOCTLCMD;
+}
+
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+static void rfcomm_tty_set_termios(struct tty_struct *tty, struct termios *old)
+{
+	BT_DBG("tty %p", tty);
+
+	if ((tty->termios->c_cflag == old->c_cflag) &&
+		(RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old->c_iflag)))
+		return;
+
+	/* handle turning off CRTSCTS */
+	if ((old->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {
+		BT_DBG("turning off CRTSCTS");
+	}
+}
+
+static void rfcomm_tty_throttle(struct tty_struct *tty)
+{
+	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+
+	BT_DBG("tty %p dev %p", tty, dev);
+	
+	rfcomm_dlc_throttle(dev->dlc);
+}
+
+static void rfcomm_tty_unthrottle(struct tty_struct *tty)
+{
+	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+
+	BT_DBG("tty %p dev %p", tty, dev);
+	
+	rfcomm_dlc_unthrottle(dev->dlc);
+}
+
+static int rfcomm_tty_chars_in_buffer(struct tty_struct *tty)
+{
+	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+	struct rfcomm_dlc *dlc = dev->dlc;
+
+	BT_DBG("tty %p dev %p", tty, dev);
+
+	if (skb_queue_len(&dlc->tx_queue))
+		return dlc->mtu;
+
+	return 0;
+}
+
+static void rfcomm_tty_flush_buffer(struct tty_struct *tty)
+{
+	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+	if (!dev)
+		return;
+
+	BT_DBG("tty %p dev %p", tty, dev);
+
+	skb_queue_purge(&dev->dlc->tx_queue);
+
+	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
+		tty->ldisc.write_wakeup(tty);
+}
+
+static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch)
+{
+	BT_DBG("tty %p ch %c", tty, ch);
+}
+
+static void rfcomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	BT_DBG("tty %p timeout %d", tty, timeout);
+}
+
+static void rfcomm_tty_hangup(struct tty_struct *tty)
+{
+	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+	if (!dev)
+		return;
+
+	BT_DBG("tty %p dev %p", tty, dev);
+
+	rfcomm_tty_flush_buffer(tty);
+
+	if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
+		rfcomm_dev_del(dev);
+}
+
+static int rfcomm_tty_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *unused)
+{
+	return 0;
+}
+
+/* ---- TTY structure ---- */
+static int    rfcomm_tty_refcount;       /* If we manage several devices */
+
+static struct tty_struct *rfcomm_tty_table[RFCOMM_TTY_PORTS];
+static struct termios *rfcomm_tty_termios[RFCOMM_TTY_PORTS];
+static struct termios *rfcomm_tty_termios_locked[RFCOMM_TTY_PORTS];
+
+static struct tty_driver rfcomm_tty_driver = {
+	magic:			TTY_DRIVER_MAGIC,
+	driver_name:		"rfcomm",
+#ifdef CONFIG_DEVFS_FS
+	name:			"bluetooth/rfcomm/%d",
+#else
+	name:			"rfcomm",
+#endif
+	major:			RFCOMM_TTY_MAJOR,
+	minor_start:		RFCOMM_TTY_MINOR,
+	num:			RFCOMM_TTY_PORTS,
+	type:			TTY_DRIVER_TYPE_SERIAL,
+	subtype:		SERIAL_TYPE_NORMAL,
+	flags:			TTY_DRIVER_REAL_RAW,
+
+	refcount:		&rfcomm_tty_refcount,
+	table:			rfcomm_tty_table,
+	termios:		rfcomm_tty_termios,
+	termios_locked:		rfcomm_tty_termios_locked,
+
+	open:			rfcomm_tty_open,
+	close:			rfcomm_tty_close,
+	write:			rfcomm_tty_write,
+	write_room:		rfcomm_tty_write_room,
+	chars_in_buffer:	rfcomm_tty_chars_in_buffer,
+	flush_buffer:		rfcomm_tty_flush_buffer,
+	ioctl:			rfcomm_tty_ioctl,
+	throttle:		rfcomm_tty_throttle,
+	unthrottle:		rfcomm_tty_unthrottle,
+	set_termios:		rfcomm_tty_set_termios,
+	send_xchar:		rfcomm_tty_send_xchar,
+	stop:			NULL,
+	start:			NULL,
+	hangup:			rfcomm_tty_hangup,
+	wait_until_sent:	rfcomm_tty_wait_until_sent,
+	read_proc:		rfcomm_tty_read_proc,
+};
+
+int rfcomm_init_ttys(void)
+{
+	int i;
+
+	/* Initalize our global data */
+	for (i = 0; i < RFCOMM_TTY_PORTS; i++)
+		rfcomm_tty_table[i] = NULL;
+
+	/* Register the TTY driver */
+	rfcomm_tty_driver.init_termios = tty_std_termios;
+	rfcomm_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	rfcomm_tty_driver.flags = TTY_DRIVER_REAL_RAW;
+
+	if (tty_register_driver(&rfcomm_tty_driver)) {
+		BT_ERR("Can't register RFCOMM TTY driver");
+		return -1;
+	}
+
+	return 0;
+}
+
+void rfcomm_cleanup_ttys(void)
+{
+	tty_unregister_driver(&rfcomm_tty_driver);
+	return;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/syms.c linux-2.4.21/net/bluetooth/syms.c
--- linux-2.4.20/net/bluetooth/syms.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21/net/bluetooth/syms.c	2002-12-18 18:58:01.000000000 +0000
@@ -44,6 +44,9 @@
 /* HCI Core */
 EXPORT_SYMBOL(hci_register_dev);
 EXPORT_SYMBOL(hci_unregister_dev);
+EXPORT_SYMBOL(hci_suspend_dev);
+EXPORT_SYMBOL(hci_resume_dev);
+
 EXPORT_SYMBOL(hci_register_proto);
 EXPORT_SYMBOL(hci_unregister_proto);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/core/wireless.c linux-2.4.21/net/core/wireless.c
--- linux-2.4.20/net/core/wireless.c	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/core/wireless.c	2002-12-18 18:58:04.000000000 +0000
@@ -33,8 +33,16 @@
  *	o Propagate events as rtnetlink IFLA_WIRELESS option
  *	o Generate event on selected SET requests
  *
- * v4 - 18.04.01 - Jean II
+ * v4 - 18.04.02 - Jean II
  *	o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
+ *
+ * v5 - 21.06.02 - Jean II
+ *	o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup)
+ *	o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
+ *	o Add IWEVCUSTOM for driver specific event/scanning token
+ *	o Turn on WE_STRICT_WRITE by default + kernel warning
+ *	o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num)
+ *	o Fix off-by-one in test (extra_size <= IFNAMSIZ)
  */
 
 /***************************** INCLUDES *****************************/
@@ -50,8 +58,9 @@
 
 /**************************** CONSTANTS ****************************/
 
-/* This will be turned on later on... */
-#undef WE_STRICT_WRITE		/* Check write buffer size */
+/* Enough lenience, let's make sure things are proper... */
+#define WE_STRICT_WRITE		/* Check write buffer size */
+/* I'll probably drop both the define and kernel message in the next version */
 
 /* Debuging stuff */
 #undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
@@ -106,7 +115,7 @@
 	/* SIOCSIWSPY */
 	{ IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0},
 	/* SIOCGIWSPY */
-	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0},
+	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_GET_SPY, 0},
 	/* -- hole -- */
 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
 	/* -- hole -- */
@@ -176,25 +185,41 @@
 	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
 	/* IWEVQUAL */
 	{ IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0},
+	/* IWEVCUSTOM */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_CUSTOM_MAX, 0},
+	/* IWEVREGISTERED */
+	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+	/* IWEVEXPIRED */
+	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
 };
 static const int standard_event_num = (sizeof(standard_event) /
 				       sizeof(struct iw_ioctl_description));
 
 /* Size (in bytes) of the various private data types */
-static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
+static const char priv_type_size[] = {
+	0,				/* IW_PRIV_TYPE_NONE */
+	1,				/* IW_PRIV_TYPE_BYTE */
+	1,				/* IW_PRIV_TYPE_CHAR */
+	0,				/* Not defined */
+	sizeof(__u32),			/* IW_PRIV_TYPE_INT */
+	sizeof(struct iw_freq),		/* IW_PRIV_TYPE_FLOAT */
+	sizeof(struct sockaddr),	/* IW_PRIV_TYPE_ADDR */
+	0,				/* Not defined */
+};
 
 /* Size (in bytes) of various events */
 static const int event_type_size[] = {
-	IW_EV_LCP_LEN,
+	IW_EV_LCP_LEN,			/* IW_HEADER_TYPE_NULL */
+	0,
+	IW_EV_CHAR_LEN,			/* IW_HEADER_TYPE_CHAR */
 	0,
-	IW_EV_CHAR_LEN,
+	IW_EV_UINT_LEN,			/* IW_HEADER_TYPE_UINT */
+	IW_EV_FREQ_LEN,			/* IW_HEADER_TYPE_FREQ */
+	IW_EV_ADDR_LEN,			/* IW_HEADER_TYPE_ADDR */
 	0,
-	IW_EV_UINT_LEN,
-	IW_EV_FREQ_LEN,
 	IW_EV_POINT_LEN,		/* Without variable payload */
-	IW_EV_PARAM_LEN,
-	IW_EV_ADDR_LEN,
-	IW_EV_QUAL_LEN,
+	IW_EV_PARAM_LEN,		/* IW_HEADER_TYPE_PARAM */
+	IW_EV_QUAL_LEN,			/* IW_HEADER_TYPE_QUAL */
 };
 
 /************************ COMMON SUBROUTINES ************************/
@@ -440,8 +465,10 @@
 		return -EFAULT;
 #ifdef WE_STRICT_WRITE
 	/* Check if there is enough buffer up there */
-	if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1))
+	if(iwr->u.data.length < dev->wireless_handlers->num_private_args) {
+		printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args);
 		return -E2BIG;
+	}
 #endif	/* WE_STRICT_WRITE */
 
 	/* Set the number of available ioctls. */
@@ -471,6 +498,7 @@
 	const struct iw_ioctl_description *	descr;
 	struct iw_request_info			info;
 	int					ret = -EINVAL;
+	int					user_size = 0;
 
 	/* Get the description of the IOCTL */
 	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
@@ -518,11 +546,8 @@
 			/* Check NULL pointer */
 			if(iwr->u.data.pointer == NULL)
 				return -EFAULT;
-#ifdef WE_STRICT_WRITE
-			/* Check if there is enough buffer up there */
-			if(iwr->u.data.length < descr->max_tokens)
-				return -E2BIG;
-#endif	/* WE_STRICT_WRITE */
+			/* Save user space buffer size for checking */
+			user_size = iwr->u.data.length;
 		}
 
 #ifdef WE_IOCTL_DEBUG
@@ -559,6 +584,15 @@
 
 		/* If we have something to return to the user */
 		if (!ret && IW_IS_GET(cmd)) {
+#ifdef WE_STRICT_WRITE
+			/* Check if there is enough buffer up there */
+			if(user_size < iwr->u.data.length) {
+				printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length);
+				kfree(extra);
+				return -E2BIG;
+			}
+#endif	/* WE_STRICT_WRITE */
+
 			err = copy_to_user(iwr->u.data.pointer, extra,
 					   iwr->u.data.length *
 					   descr->token_size);
@@ -646,12 +680,18 @@
 	/* Compute the size of the set/get arguments */
 	if(descr != NULL) {
 		if(IW_IS_SET(cmd)) {
+			int	offset = 0;	/* For sub-ioctls */
+			/* Check for sub-ioctl handler */
+			if(descr->name[0] == '\0')
+				/* Reserve one int for sub-ioctl index */
+				offset = sizeof(__u32);
+
 			/* Size of set arguments */
 			extra_size = get_priv_size(descr->set_args);
 
 			/* Does it fits in iwr ? */
 			if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
-			   (extra_size < IFNAMSIZ))
+			   ((extra_size + offset) <= IFNAMSIZ))
 				extra_size = 0;
 		} else {
 			/* Size of set arguments */
@@ -659,7 +699,7 @@
 
 			/* Does it fits in iwr ? */
 			if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
-			   (extra_size < IFNAMSIZ))
+			   (extra_size <= IFNAMSIZ))
 				extra_size = 0;
 		}
 	}
@@ -925,7 +965,7 @@
 		 * The best the driver could do is to log an error message.
 		 * We will do it ourselves instead...
 		 */
-	  	printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n",
+	  	printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
 		       dev->name, cmd);
 		return;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/netfilter/ip_tables.c linux-2.4.21/net/ipv4/netfilter/ip_tables.c
--- linux-2.4.20/net/ipv4/netfilter/ip_tables.c	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/ipv4/netfilter/ip_tables.c	2002-12-18 18:58:05.000000000 +0000
@@ -68,13 +68,12 @@
 #define inline
 #endif
 
-/* Locking is simple: we assume at worst case there will be one packet
-   in user context and one from bottom halves (or soft irq if Alexey's
-   softnet patch was applied).
-
+/*
    We keep a set of rules for each CPU, so we can avoid write-locking
-   them; doing a readlock_bh() stops packets coming through if we're
-   in user context.
+   them in the softirq when updating the counters and therefore
+   only need to read-lock in the softirq; doing a write_lock_bh() in user
+   context stops packets coming through and allows user context to read
+   the counters or update the rules.
 
    To be cache friendly on SMP, we arrange them like so:
    [ n-entries ]
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/ircomm/ircomm_core.c linux-2.4.21/net/irda/ircomm/ircomm_core.c
--- linux-2.4.20/net/irda/ircomm/ircomm_core.c	2002-02-25 19:38:14.000000000 +0000
+++ linux-2.4.21/net/irda/ircomm/ircomm_core.c	2002-12-18 18:58:01.000000000 +0000
@@ -498,7 +498,7 @@
 
 	self = (struct ircomm_cb *) hashbin_get_first(ircomm);
 	while (self != NULL) {
-		ASSERT(self->magic == IRCOMM_MAGIC, return len;);
+		ASSERT(self->magic == IRCOMM_MAGIC, break;);
 
 		if(self->line < 0x10)
 			len += sprintf(buf+len, "ircomm%d", self->line);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/ircomm/ircomm_tty.c linux-2.4.21/net/irda/ircomm/ircomm_tty.c
--- linux-2.4.20/net/irda/ircomm/ircomm_tty.c	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/irda/ircomm/ircomm_tty.c	2002-12-18 18:58:06.000000000 +0000
@@ -512,6 +512,9 @@
 	if (!tty)
 		return;
 
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
 	save_flags(flags); 
 	cli();
 
@@ -523,9 +526,6 @@
 		return;
 	}
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
 	if ((tty->count == 1) && (self->open_count != 1)) {
 		/*
 		 * Uh, oh.  tty->count is 1, which means that the tty
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/irda_device.c linux-2.4.21/net/irda/irda_device.c
--- linux-2.4.20/net/irda/irda_device.c	2002-02-25 19:38:14.000000000 +0000
+++ linux-2.4.21/net/irda/irda_device.c	2002-12-18 18:58:08.000000000 +0000
@@ -369,6 +369,12 @@
  *    time to complete. We do it this hairy way since we may have been
  *    called from interrupt context, so it's not possible to use
  *    schedule_timeout() 
+ * Two important notes :
+ *	o Make sure you irda_task_delete(task); in case you delete the
+ *	  calling instance.
+ *	o No real need to lock when calling this function, but you may
+ *	  want to lock within the task handler.
+ * Jean II
  */
 struct irda_task *irda_task_execute(void *instance, 
 				    IRDA_TASK_CALLBACK function, 
@@ -467,6 +473,9 @@
  * Function irda_device_init_dongle (self, type, qos)
  *
  *    Initialize attached dongle.
+ *
+ * Important : request_module require us to call this function with
+ * a process context and irq enabled. - Jean II
  */
 dongle_t *irda_device_dongle_init(struct net_device *dev, int type)
 {
@@ -478,6 +487,7 @@
 #ifdef CONFIG_KMOD
 	{
 	char modname[32];
+	ASSERT(!in_interrupt(), return NULL;);
 	/* Try to load the module needed */
 	sprintf(modname, "irda-dongle-%d", type);
 	request_module(modname);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/irlap.c linux-2.4.21/net/irda/irlap.c
--- linux-2.4.20/net/irda/irlap.c	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/irda/irlap.c	2002-12-18 18:58:07.000000000 +0000
@@ -1101,8 +1101,8 @@
 
 	self = (struct irlap_cb *) hashbin_get_first(irlap);
 	while (self != NULL) {
-		ASSERT(self != NULL, return -ENODEV;);
-		ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
+		ASSERT(self != NULL, break;);
+		ASSERT(self->magic == LAP_MAGIC, break;);
 
 		len += sprintf(buf+len, "irlap%d ", i++);
 		len += sprintf(buf+len, "state: %s\n", 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/irlmp.c linux-2.4.21/net/irda/irlmp.c
--- linux-2.4.20/net/irda/irlmp.c	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/irda/irlmp.c	2002-12-18 18:58:11.000000000 +0000
@@ -236,6 +236,16 @@
 	lap = self->lap;
 	if (lap) {
 		ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
+		/* We might close a LSAP before it has completed the
+		 * connection setup. In those case, higher layers won't
+		 * send a proper disconnect request. Harmless, except
+		 * that we will forget to close LAP... - Jean II */
+		if(self->lsap_state != LSAP_DISCONNECTED) {
+			self->lsap_state = LSAP_DISCONNECTED;
+			irlmp_do_lap_event(self->lap,
+					   LM_LAP_DISCONNECT_REQUEST, NULL);
+		}
+		/* Now, remove from the link */
 		lsap = hashbin_remove(lap->lsaps, (int) self, NULL);
 	}
 	self->lap = NULL;
@@ -1674,7 +1684,7 @@
 	len += sprintf( buf+len, "Unconnected LSAPs:\n");
 	self = (struct lsap_cb *) hashbin_get_first( irlmp->unconnected_lsaps);
 	while (self != NULL) {
-		ASSERT(self->magic == LMP_LSAP_MAGIC, return 0;);
+		ASSERT(self->magic == LMP_LSAP_MAGIC, break;);
 		len += sprintf(buf+len, "lsap state: %s, ", 
 			       irlsap_state[ self->lsap_state]);
 		len += sprintf(buf+len, 
@@ -1703,7 +1713,7 @@
 		len += sprintf(buf+len, "\n  Connected LSAPs:\n");
 		self = (struct lsap_cb *) hashbin_get_first(lap->lsaps);
 		while (self != NULL) {
-			ASSERT(self->magic == LMP_LSAP_MAGIC, return 0;);
+			ASSERT(self->magic == LMP_LSAP_MAGIC, break;);
 			len += sprintf(buf+len, "  lsap state: %s, ", 
 				       irlsap_state[ self->lsap_state]);
 			len += sprintf(buf+len, 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/irlmp_event.c linux-2.4.21/net/irda/irlmp_event.c
--- linux-2.4.20/net/irda/irlmp_event.c	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/irda/irlmp_event.c	2002-12-18 18:58:04.000000000 +0000
@@ -414,7 +414,7 @@
 
 			/* We don't want to change state just yet, because
 			 * we want to reflect accurately the real state of
-			 * the LAP, not the the state we whish it was in,
+			 * the LAP, not the state we wish it was in,
 			 * so that we don't loose LM_LAP_CONNECT_REQUEST.
 			 * In some cases, IrLAP won't close the LAP
 			 * immediately. For example, it might still be
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/irnet/irnet.h linux-2.4.21/net/irda/irnet/irnet.h
--- linux-2.4.20/net/irda/irnet/irnet.h	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/irda/irnet/irnet.h	2002-12-18 18:58:10.000000000 +0000
@@ -217,6 +217,11 @@
  *	  Better fix in irnet_disconnect_indication() :
  *	  - if connected, kill pppd via hangup.
  *	  - if not connected, reenable ppp Tx, which trigger IrNET retry.
+ *
+ * v12 - 10.4.02 - Jean II
+ *	o Fix race condition in irnet_connect_indication().
+ *	  If the socket was already trying to connect, drop old connection
+ *	  and use new one only if acting as primary. See comments.
  */
 
 /***************************** INCLUDES *****************************/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/irnet/irnet_irda.c linux-2.4.21/net/irda/irnet/irnet_irda.c
--- linux-2.4.20/net/irda/irnet/irnet_irda.c	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/irda/irnet/irnet_irda.c	2002-12-18 18:58:02.000000000 +0000
@@ -1340,46 +1340,80 @@
       return;
     }
 
-  /* Socket connecting ?
-   * Clear up flag : prevent irnet_disconnect_indication() to mess up tsap */
-  if(test_and_clear_bit(0, &new->ttp_connect))
-    {
-      /* The socket is trying to connect to the other end and may have sent
-       * a IrTTP connection request and is waiting for a connection response
-       * (that may never come).
-       * Now, the pain is that the socket may have opened a tsap and is
-       * waiting on it, while the other end is trying to connect to it on
-       * another tsap.
-       */
-      DERROR(IRDA_CB_ERROR, "Socket already connecting. Ouch !\n");
+  /* The following code is a bit tricky, so need comments ;-)
+   */
+  /* If ttp_connect is set, the socket is trying to connect to the other
+   * end and may have sent a IrTTP connection request and is waiting for
+   * a connection response (that may never come).
+   * Now, the pain is that the socket may have opened a tsap and is
+   * waiting on it, while the other end is trying to connect to it on
+   * another tsap.
+   * Because IrNET can be peer to peer, we need to workaround this.
+   * Furthermore, the way the irnetd script is implemented, the
+   * target will create a second IrNET connection back to the
+   * originator and expect the originator to bind this new connection
+   * to the original PPPD instance.
+   * And of course, if we don't use irnetd, we can have a race when
+   * both side try to connect simultaneously, which could leave both
+   * connections half closed (yuck).
+   * Conclusions :
+   *	1) The "originator" must accept the new connection and get rid
+   *	   of the old one so that irnetd works
+   *	2) One side must deny the new connection to avoid races,
+   *	   but both side must agree on which side it is...
+   * Most often, the originator is primary at the LAP layer.
+   * Jean II
+   */
+  /* Now, let's look at the way I wrote the test...
+   * We need to clear up the ttp_connect flag atomically to prevent
+   * irnet_disconnect_indication() to mess up the tsap we are going to close.
+   * We want to clear the ttp_connect flag only if we close the tsap,
+   * otherwise we will never close it, so we need to check for primary
+   * *before* doing the test on the flag.
+   * And of course, ALLOW_SIMULT_CONNECT can disable this entirely...
+   * Jean II
+   */
+
+  /* Socket already connecting ? On primary ? */
+  if(0
 #ifdef ALLOW_SIMULT_CONNECT
-      /* Cleanup the TSAP if necessary - IrIAP will be cleaned up later */
+     || ((irttp_is_primary(server->tsap) == 1)	/* primary */
+	 && (test_and_clear_bit(0, &new->ttp_connect)))
+#endif /* ALLOW_SIMULT_CONNECT */
+     )
+    {
+      DERROR(IRDA_CB_ERROR, "Socket already connecting, but going to reuse it !\n");
+
+      /* Cleanup the old TSAP if necessary - IrIAP will be cleaned up later */
       if(new->tsap != NULL)
 	{
-	  /* Close the connection the new socket was attempting.
-	   * This seems to be safe... */
+	  /* Close the old connection the new socket was attempting,
+	   * so that we can hook it up to the new connection.
+	   * It's now safe to do it... */
 	  irttp_close_tsap(new->tsap);
 	  new->tsap = NULL;
 	}
-      /* Note : no return, fall through... */
-#else /* ALLOW_SIMULT_CONNECT */
-      irnet_disconnect_server(server, skb);
-      return;
-#endif /* ALLOW_SIMULT_CONNECT */
     }
   else
-    /* If socket is not connecting or connected, tsap should be NULL */
-    if(new->tsap != NULL)
-      {
-	/* If we are here, we are also in irnet_disconnect_indication(),
-	 * and it's a nice race condition... On the other hand, we can't be
-	 * in irda_irnet_destroy() otherwise we would not have found the
-	 * socket in the hashbin. */
-	/* Better get out of here, otherwise we will mess up tsaps ! */
-	DERROR(IRDA_CB_ERROR, "Race condition detected, abort connect...\n");
-	irnet_disconnect_server(server, skb);
-	return;
-      }
+    {
+      /* Three options :
+       * 1) socket was not connecting or connected : ttp_connect should be 0.
+       * 2) we don't want to connect the socket because we are secondary or
+       * ALLOW_SIMULT_CONNECT is undefined. ttp_connect should be 1.
+       * 3) we are half way in irnet_disconnect_indication(), and it's a
+       * nice race condition... Fortunately, we can detect that by checking
+       * if tsap is still alive. On the other hand, we can't be in
+       * irda_irnet_destroy() otherwise we would not have found this
+       * socket in the hashbin.
+       * Jean II */
+      if((test_bit(0, &new->ttp_connect)) || (new->tsap != NULL))
+	{
+	  /* Don't mess this socket, somebody else in in charge... */
+	  DERROR(IRDA_CB_ERROR, "Race condition detected, socket in use, abort connect...\n");
+	  irnet_disconnect_server(server, skb);
+	  return;
+	}
+    }
 
   /* So : at this point, we have a socket, and it is idle. Good ! */
   irnet_connect_socket(server, new, qos, max_sdu_size, max_header_size);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/irttp.c linux-2.4.21/net/irda/irttp.c
--- linux-2.4.20/net/irda/irttp.c	2001-11-09 22:22:17.000000000 +0000
+++ linux-2.4.21/net/irda/irttp.c	2002-12-18 18:58:10.000000000 +0000
@@ -59,8 +59,8 @@
 
 static void irttp_flush_queues(struct tsap_cb *self);
 static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb);
-static void irttp_start_todo_timer(struct tsap_cb *self, int timeout);
 static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self);
+static void irttp_todo_expired(unsigned long data);
 static int irttp_param_max_sdu_size(void *instance, irda_param_t *param, 
 				    int get);
 
@@ -72,6 +72,8 @@
 static pi_major_info_t pi_major_call_table[] = {{ pi_minor_call_table, 2 }};
 static pi_param_info_t param_info = { pi_major_call_table, 1, 0x0f, 4 };
 
+/************************ GLOBAL PROCEDURES ************************/
+
 /*
  * Function irttp_init (void)
  *
@@ -126,6 +128,239 @@
 }
 #endif
 
+/*************************** SUBROUTINES ***************************/
+
+/*
+ * Function irttp_start_todo_timer (self, timeout)
+ *
+ *    Start todo timer. 
+ *
+ * Made it more effient and unsensitive to race conditions - Jean II
+ */
+static inline void irttp_start_todo_timer(struct tsap_cb *self, int timeout)
+{
+	/* Set new value for timer */
+	mod_timer(&self->todo_timer, jiffies + timeout);
+}
+
+/*
+ * Function irttp_todo_expired (data)
+ *
+ *    Todo timer has expired!
+ *
+ * One of the restriction of the timer is that it is run only on the timer
+ * interrupt which run every 10ms. This mean that even if you set the timer
+ * with a delay of 0, it may take up to 10ms before it's run.
+ * So, to minimise latency and keep cache fresh, we try to avoid using
+ * it as much as possible.
+ * Note : we can't use tasklets, because they can't be asynchronously
+ * killed (need user context), and we can't guarantee that here...
+ * Jean II
+ */
+static void irttp_todo_expired(unsigned long data)
+{
+	struct tsap_cb *self = (struct tsap_cb *) data;
+
+	/* Check that we still exist */
+	if (!self || self->magic != TTP_TSAP_MAGIC)
+		return;
+	
+	IRDA_DEBUG(4, __FUNCTION__ "(instance=%p)\n", self);
+
+	/* Try to make some progress, especially on Tx side - Jean II */
+	irttp_run_rx_queue(self);
+	irttp_run_tx_queue(self);
+
+	/* Check if time for disconnect */
+	if (test_bit(0, &self->disconnect_pend)) {
+		/* Check if it's possible to disconnect yet */
+		if (skb_queue_empty(&self->tx_queue)) {
+			/* Make sure disconnect is not pending anymore */
+			clear_bit(0, &self->disconnect_pend);	/* FALSE */
+
+			/* Note : self->disconnect_skb may be NULL */
+			irttp_disconnect_request(self, self->disconnect_skb,
+						 P_NORMAL);
+			self->disconnect_skb = NULL;
+		} else {
+			/* Try again later */
+			irttp_start_todo_timer(self, HZ/10);
+			
+			/* No reason to try and close now */
+			return;
+		}
+	}
+	
+	/* Check if it's closing time */
+	if (self->close_pend)
+		/* Finish cleanup */
+		irttp_close_tsap(self);
+}
+
+/*
+ * Function irttp_flush_queues (self)
+ *
+ *     Flushes (removes all frames) in transitt-buffer (tx_list)
+ */
+void irttp_flush_queues(struct tsap_cb *self)
+{
+	struct sk_buff* skb;
+	
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	
+	/* Deallocate frames waiting to be sent */
+	while ((skb = skb_dequeue(&self->tx_queue)) != NULL)
+		dev_kfree_skb(skb);
+	
+	/* Deallocate received frames */
+	while ((skb = skb_dequeue(&self->rx_queue)) != NULL)
+		dev_kfree_skb(skb);
+	
+	/* Deallocate received fragments */
+	while ((skb = skb_dequeue(&self->rx_fragments)) != NULL)
+		dev_kfree_skb(skb);
+}
+
+/*
+ * Function irttp_reassemble (self)
+ *
+ *    Makes a new (continuous) skb of all the fragments in the fragment
+ *    queue
+ *
+ */
+static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self)
+{
+	struct sk_buff *skb, *frag;
+	int n = 0;  /* Fragment index */
+	
+      	ASSERT(self != NULL, return NULL;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), self->rx_sdu_size=%d\n", 
+		   self->rx_sdu_size);
+
+	skb = dev_alloc_skb(TTP_HEADER + self->rx_sdu_size);
+	if (!skb)
+		return NULL;
+
+	/* 
+	 * Need to reserve space for TTP header in case this skb needs to 
+	 * be requeued in case delivery failes
+	 */
+	skb_reserve(skb, TTP_HEADER);
+	skb_put(skb, self->rx_sdu_size);
+
+	/*
+	 *  Copy all fragments to a new buffer
+	 */
+	while ((frag = skb_dequeue(&self->rx_fragments)) != NULL) {
+		memcpy(skb->data+n, frag->data, frag->len);
+		n += frag->len;
+		
+		dev_kfree_skb(frag);
+	}
+	IRDA_DEBUG(2, __FUNCTION__ "(), frame len=%d\n", n);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), rx_sdu_size=%d\n", self->rx_sdu_size);
+	ASSERT(n <= self->rx_sdu_size, return NULL;);
+
+	/* Set the new length */
+	skb_trim(skb, n);
+
+	self->rx_sdu_size = 0;
+
+	return skb;
+}
+
+/*
+ * Function irttp_fragment_skb (skb)
+ *
+ *    Fragments a frame and queues all the fragments for transmission
+ *
+ */
+static inline void irttp_fragment_skb(struct tsap_cb *self,
+				      struct sk_buff *skb)
+{
+	struct sk_buff *frag;
+	__u8 *frame;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	ASSERT(skb != NULL, return;);
+
+	/*
+	 *  Split frame into a number of segments
+	 */
+	while (skb->len > self->max_seg_size) {
+		IRDA_DEBUG(2, __FUNCTION__  "(), fragmenting ...\n");
+
+		/* Make new segment */
+		frag = dev_alloc_skb(self->max_seg_size+self->max_header_size);
+		if (!frag)
+			return;
+
+		skb_reserve(frag, self->max_header_size);
+
+		/* Copy data from the original skb into this fragment. */
+		memcpy(skb_put(frag, self->max_seg_size), skb->data, 
+		       self->max_seg_size);
+
+		/* Insert TTP header, with the more bit set */
+		frame = skb_push(frag, TTP_HEADER);
+		frame[0] = TTP_MORE;
+		
+		/* Hide the copied data from the original skb */
+		skb_pull(skb, self->max_seg_size);
+
+		/* Queue fragment */
+		skb_queue_tail(&self->tx_queue, frag);
+	}
+	/* Queue what is left of the original skb */
+	IRDA_DEBUG(2, __FUNCTION__  "(), queuing last segment\n");
+	
+	frame = skb_push(skb, TTP_HEADER);
+	frame[0] = 0x00; /* Clear more bit */
+
+	/* Queue fragment */
+	skb_queue_tail(&self->tx_queue, skb);
+}
+
+/*
+ * Function irttp_param_max_sdu_size (self, param)
+ *
+ *    Handle the MaxSduSize parameter in the connect frames, this function
+ *    will be called both when this parameter needs to be inserted into, and
+ *    extracted from the connect frames
+ */
+static int irttp_param_max_sdu_size(void *instance, irda_param_t *param, 
+				    int get)
+{
+	struct tsap_cb *self;
+
+	self = (struct tsap_cb *) instance;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
+
+	if (get)
+		param->pv.i = self->tx_max_sdu_size;
+	else
+		self->tx_max_sdu_size = param->pv.i;
+
+	IRDA_DEBUG(1, __FUNCTION__ "(), MaxSduSize=%d\n", param->pv.i);
+	
+	return 0;
+}
+
+/*************************** CLIENT CALLS ***************************/
+/************************** LMP CALLBACKS **************************/
+/* Everything is happily mixed up. Waiting for next clean up - Jean II */
+
 /*
  * Function irttp_open_tsap (stsap, notify)
  *
@@ -157,7 +392,10 @@
 	memset(self, 0, sizeof(struct tsap_cb));
 	spin_lock_init(&self->lock);
 
+	/* Initialise todo timer */
 	init_timer(&self->todo_timer);
+	self->todo_timer.data     = (unsigned long) self;
+	self->todo_timer.function = &irttp_todo_expired;
 
 	/* Initialize callbacks for IrLMP to use */
 	irda_notify_init(&ttp_notify);
@@ -166,6 +404,7 @@
 	ttp_notify.disconnect_indication = irttp_disconnect_indication;
 	ttp_notify.data_indication = irttp_data_indication;
 	ttp_notify.udata_indication = irttp_udata_indication;
+	ttp_notify.flow_indication = irttp_flow_indication;
 	if(notify->status_indication != NULL)
 		ttp_notify.status_indication = irttp_status_indication;
 	ttp_notify.instance = self;
@@ -199,8 +438,8 @@
 
 	hashbin_insert(irttp->tsaps, (irda_queue_t *) self, (int) self, NULL);
 
-	if (credit > TTP_MAX_QUEUE)
-		self->initial_credit = TTP_MAX_QUEUE;
+	if (credit > TTP_RX_MAX_CREDIT)
+		self->initial_credit = TTP_RX_MAX_CREDIT;
 	else
 		self->initial_credit = credit;
 
@@ -224,7 +463,7 @@
 
 	del_timer(&self->todo_timer);
 
-	/* This one won't be cleaned up if we are diconnect_pend + close_pend
+	/* This one won't be cleaned up if we are disconnect_pend + close_pend
 	 * and we receive a disconnect_indication */
 	if (self->disconnect_skb)
 		dev_kfree_skb(self->disconnect_skb);
@@ -262,7 +501,7 @@
 			irttp_disconnect_request(self, NULL, P_NORMAL);
 		}
 		self->close_pend = TRUE;
-		irttp_start_todo_timer(self, 1*HZ);
+		irttp_start_todo_timer(self, HZ/10);
 
 		return 0; /* Will be back! */
 	}
@@ -327,6 +566,9 @@
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
 	ASSERT(skb != NULL, return -1;);
 
+	IRDA_DEBUG(2, __FUNCTION__ " : queue len = %d\n",
+		   skb_queue_len(&self->tx_queue));
+
 	/* Check that nothing bad happens */
 	if ((skb->len == 0) || (!self->connected)) {
 		WARNING(__FUNCTION__ "(), No data, or not connected\n");
@@ -358,12 +600,14 @@
 	/* 
 	 *  Check if transmit queue is full
 	 */
-	if (skb_queue_len(&self->tx_queue) >= TTP_MAX_QUEUE) {
+	if (skb_queue_len(&self->tx_queue) >= TTP_TX_MAX_QUEUE) {
 		/*
 		 *  Give it a chance to empty itself
 		 */
 		irttp_run_tx_queue(self);
-		
+
+		/* Drop packet. This error code should trigger the caller
+		 * to requeue the packet in the client code - Jean II */
 		return -ENOBUFS;
 	}
        
@@ -387,20 +631,25 @@
 
 	/* Check if we can accept more data from client */
 	if ((!self->tx_sdu_busy) && 
-	    (skb_queue_len(&self->tx_queue) > TTP_HIGH_THRESHOLD)) {
-		
-		/* Tx queue filling up, so stop client */
-		self->tx_sdu_busy = TRUE;
-		
-	 	if (self->notify.flow_indication) {
+	    (skb_queue_len(&self->tx_queue) > TTP_TX_HIGH_THRESHOLD)) {
+		/* Tx queue filling up, so stop client. */
+		if (self->notify.flow_indication) {
  			self->notify.flow_indication(self->notify.instance, 
 						     self, FLOW_STOP);
 		}
- 	}
+		/* self->tx_sdu_busy is the state of the client.
+		 * Update state after notifying client to avoid
+		 * race condition with irttp_flow_indication().
+		 * If the queue empty itself after our test but before
+		 * we set the flag, we will fix ourselves below in
+		 * irttp_run_tx_queue().
+		 * Jean II */
+		self->tx_sdu_busy = TRUE;
+	}
 	
 	/* Try to make some progress */
 	irttp_run_tx_queue(self);
-	
+
 	return 0;
 }
 
@@ -416,28 +665,20 @@
 	unsigned long flags;
 	int n;
 
+	IRDA_DEBUG(2, __FUNCTION__ "() : send_credit = %d, queue_len = %d\n",
+		   self->send_credit, skb_queue_len(&self->tx_queue));
+
 	/* Get exclusive access to the tx queue, otherwise don't touch it */
 	if (irda_lock(&self->tx_queue_lock) == FALSE)
 		return;
 
-	/* Try to send out frames as long as we have credits */
+	/* Try to send out frames as long as we have credits
+	 * and as long as LAP is not full. If LAP is full, it will
+	 * poll us through irttp_flow_indication() - Jean II */
 	while ((self->send_credit > 0) &&
+	       (!irlmp_lap_tx_queue_full(self->lsap)) &&
 	       (skb = skb_dequeue(&self->tx_queue)))
 	{
-		/* 
-		 * Make sure we don't flood IrLAP with frames just because
-		 * the remote device has given us a lot of credits
-		 */
-		if (irlmp_get_lap_tx_queue_len(self->lsap) > LAP_MAX_QUEUE) {
-			/* Re-queue packet */
-			skb_queue_head(&self->tx_queue, skb);
-
-			/* Try later. Would be better if IrLAP could notify us */
-			irttp_start_todo_timer(self, MSECS_TO_JIFFIES(10));
-			
-			break;
-		}
-
 		/*
 		 *  Since we can transmit and receive frames concurrently, 
 		 *  the code below is a critical region and we must assure that
@@ -484,32 +725,35 @@
 		 * Jean II */
 		if (skb->sk != NULL) {
 			/* IrSOCK application, IrOBEX, ... */
-			IRDA_DEBUG(4, __FUNCTION__ "() : Detaching SKB from socket.\n");
-
-			/* That's the right way to do it - Jean II */
 			skb_orphan(skb);
-		} else {
-			/* IrCOMM over IrTTP, IrLAN, ... */
-			IRDA_DEBUG(4, __FUNCTION__ "() : Got SKB not attached to a socket.\n");
 		}
+			/* IrCOMM over IrTTP, IrLAN, ... */
 
 		/* Pass the skb to IrLMP - done */
 		irlmp_data_request(self->lsap, skb);
 		self->stats.tx_packets++;
+	}
 
-		/* Check if we can accept more frames from client */
-		if ((self->tx_sdu_busy) && 
-		    (skb_queue_len(&self->tx_queue) < TTP_LOW_THRESHOLD)) 
-		{
-			self->tx_sdu_busy = FALSE;
-			
-			if (self->notify.flow_indication)
-				self->notify.flow_indication(
-					self->notify.instance, self,
-					FLOW_START);
-		}
+	/* Check if we can accept more frames from client.
+	 * We don't want to wait until the todo timer to do that, and we
+	 * can't use tasklets (grr...), so we are obliged to give control
+	 * to client. That's ok, this test will be true not too often
+	 * (max once per LAP window) and we are called from places
+	 * where we can spend a bit of time doing stuff. - Jean II */
+	if ((self->tx_sdu_busy) && 
+	    (skb_queue_len(&self->tx_queue) < TTP_TX_LOW_THRESHOLD) &&
+	    (!self->close_pend))
+	{
+		if (self->notify.flow_indication)
+			self->notify.flow_indication(self->notify.instance,
+						     self, FLOW_START);
+
+		/* self->tx_sdu_busy is the state of the client.
+		 * We don't really have a race here, but it's always safer
+		 * to update our state after the client - Jean II */
+		self->tx_sdu_busy = FALSE;
 	}
-	
+
 	/* Reset lock */
 	self->tx_queue_lock = 0;
 }
@@ -520,7 +764,7 @@
  *    Send a dataless flowdata TTP-PDU and give available credit to peer
  *    TSAP
  */
-void irttp_give_credit(struct tsap_cb *self) 
+static inline void irttp_give_credit(struct tsap_cb *self) 
 {
 	struct sk_buff *tx_skb = NULL;
 	unsigned long flags;
@@ -531,7 +775,7 @@
 
 	IRDA_DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", 
 		   self->send_credit, self->avail_credit, self->remote_credit);
-	
+
 	/* Give credit to peer */
 	tx_skb = dev_alloc_skb(64);
 	if (!tx_skb)
@@ -606,6 +850,7 @@
 				 struct sk_buff *skb)
 {
 	struct tsap_cb *self;
+	unsigned long flags;
 	int n;
 
 	self = (struct tsap_cb *) instance;
@@ -614,47 +859,66 @@
 
 	self->stats.rx_packets++;
 
+	/*  Deal with inbound credit
+	 *  Since we can transmit and receive frames concurrently, 
+	 *  the code below is a critical region and we must assure that
+	 *  nobody messes with the credits while we update them.
+	 */
+	spin_lock_irqsave(&self->lock, flags);
+	self->send_credit += n;
+	if (skb->len > 1)
+		self->remote_credit--;
+	spin_unlock_irqrestore(&self->lock, flags);
+
 	/* 
 	 *  Data or dataless packet? Dataless frames contains only the 
 	 *  TTP_HEADER. 
 	 */
 	if (skb->len > 1) {
-		/* Deal with inbound credit */
-		self->send_credit += n;
-		self->remote_credit--;
-		
 		/* 
 		 *  We don't remove the TTP header, since we must preserve the
 		 *  more bit, so the defragment routing knows what to do
 		 */
 		skb_queue_tail(&self->rx_queue, skb);
 	} else {
-		self->send_credit += n;	/* Dataless flowdata TTP-PDU */
+		/* Dataless flowdata TTP-PDU */
 		dev_kfree_skb(skb);
 	}
 
+
+	/* Push data to the higher layer.
+	 * We do it synchronously because running the todo timer for each
+	 * receive packet would be too much overhead and latency.
+	 * By passing control to the higher layer, we run the risk that
+	 * it may take time or grab a lock. Most often, the higher layer
+	 * will only put packet in a queue.
+	 * Anyway, packets are only dripping through the IrDA, so we can
+	 * have time before the next packet.
+	 * Further, we are run from NET_BH, so the worse that can happen is
+	 * us missing the optimal time to send back the PF bit in LAP.
+	 * Jean II */
 	irttp_run_rx_queue(self);
 
-	/* 
-	 *  Give avay some credits to peer? 
-	 */
-	if ((skb_queue_empty(&self->tx_queue)) && 
-	    (self->remote_credit < TTP_LOW_THRESHOLD) && 
-	    (self->avail_credit > 0)) 
-	{
-		/* Schedule to start immediately after this thread */
-		irttp_start_todo_timer(self, 0);
-		/*irttp_give_credit(self);*/
-	}
-	
+	/* We now give credits to peer in irttp_run_rx_queue().
+	 * We need to send credit *NOW*, otherwise we are going
+	 * to miss the next Tx window. The todo timer may take
+	 * a while before it's run... - Jean II */
+
 	/* 
 	 * If the peer device has given us some credits and we didn't have
-         * anyone from before, the we need to shedule the tx queue?  
+         * anyone from before, then we need to shedule the tx queue.
+	 * We need to do that because our Tx have stopped (so we may not
+	 * get any LAP flow indication) and the user may be stopped as
+	 * well. - Jean II
 	 */
 	if (self->send_credit == n) {
-		/*irttp_run_tx_queue(self);*/
-		irttp_start_todo_timer(self, 0);
+		/* Restart pushing stuff to LAP */
+		irttp_run_tx_queue(self);
+		/* Note : we don't want to schedule the todo timer
+		 * because it has horrible latency. No tasklets
+		 * because the tasklet API is broken. - Jean II */
 	}
+
 	return 0;
 }
 
@@ -687,6 +951,50 @@
 }
 
 /*
+ * Function irttp_flow_indication (self, reason)
+ *
+ *    Flow_indication : IrLAP tells us to send more data.
+ *
+ */
+void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
+{
+	struct tsap_cb *self;
+
+	self = (struct tsap_cb *) instance;
+	
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	
+	IRDA_DEBUG(4, __FUNCTION__ "(instance=%p)\n", self);
+
+	/* We are "polled" directly from LAP, and the LAP want to fill
+	 * its Tx window. We want to do our best to send it data, so that
+	 * we maximise the window. On the other hand, we want to limit the
+	 * amount of work here so that LAP doesn't hang forever waiting
+	 * for packets. - Jean II */
+
+	/* Try to send some packets. Currently, LAP calls us every time
+	 * there is one free slot, so we will send only one packet.
+	 * This allow the scheduler to do its round robin - Jean II */
+	irttp_run_tx_queue(self);
+
+	/* Note regarding the interraction with higher layer.
+	 * irttp_run_tx_queue() may call the client when its queue
+	 * start to empty, via notify.flow_indication(). Initially.
+	 * I wanted this to happen in a tasklet, to avoid client
+	 * grabbing the CPU, but we can't use tasklets safely. And timer
+	 * is definitely too slow.
+	 * This will happen only once per LAP window, and usually at
+	 * the third packet (unless window is smaller). LAP is still
+	 * doing mtt and sending first packet so it's sort of OK
+	 * to do that. Jean II */
+
+	/* If we need to send disconnect. try to do it now */
+	if(self->disconnect_pend)
+		irttp_start_todo_timer(self, 0);
+}
+
+/*
  * Function irttp_flow_request (self, command)
  *
  *    This funtion could be used by the upper layers to tell IrTTP to stop
@@ -709,7 +1017,10 @@
 		IRDA_DEBUG(1, __FUNCTION__ "(), flow start\n");
 		self->rx_sdu_busy = FALSE;
 		
+		/* Client say he can accept more data, try to free our
+		 * queues ASAP - Jean II */
 		irttp_run_rx_queue(self);
+
 		break;
 	default:
 		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown flow command!\n");
@@ -1147,10 +1458,15 @@
 
 			irttp_run_tx_queue(self);
 
-			irttp_start_todo_timer(self, MSECS_TO_JIFFIES(1000));
+			irttp_start_todo_timer(self, HZ/10);
 			return -1;
 		}
 	}
+	/* Note : we don't need to check if self->rx_queue is full and the
+	 * state of self->rx_sdu_busy because the disconnect response will
+	 * be sent at the LMP level (so even if the peer has its Tx queue
+	 * full of data). - Jean II */
+
 	IRDA_DEBUG(1, __FUNCTION__ "(), Disconnecting ...\n");
 	self->connected = FALSE;
 
@@ -1281,8 +1597,7 @@
 	 *  Reassemble all frames in receive queue and deliver them
 	 */
 	while (!self->rx_sdu_busy && (skb = skb_dequeue(&self->rx_queue))) {
-		self->avail_credit++;
-
+		/* This bit will tell us if it's the last fragment or not */
 		more = skb->data[0] & 0x80;
 
 		/* Remove TTP header */
@@ -1293,7 +1608,7 @@
 
 		/*  
 		 * If SAR is disabled, or user has requested no reassembly
-		 * of received fragements then we just deliver them
+		 * of received fragments then we just deliver them
 		 * immediately. This can be requested by clients that
 		 * implements byte streams without any message boundaries
 		 */
@@ -1353,236 +1668,46 @@
 		}
 		self->rx_sdu_size = 0;
 	}
-	/* Reset lock */
-	self->rx_queue_lock = 0;
-}
-
-/*
- * Function irttp_flush_queues (self)
- *
- *     Flushes (removes all frames) in transitt-buffer (tx_list)
- */
-void irttp_flush_queues(struct tsap_cb *self)
-{
-	struct sk_buff* skb;
-	
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-	
-	/* Deallocate frames waiting to be sent */
-	while ((skb = skb_dequeue(&self->tx_queue)) != NULL)
-		dev_kfree_skb(skb);
-	
-	/* Deallocate received frames */
-	while ((skb = skb_dequeue(&self->rx_queue)) != NULL)
-		dev_kfree_skb(skb);
-	
-	/* Deallocate received fragments */
-	while ((skb = skb_dequeue(&self->rx_fragments)) != NULL)
-		dev_kfree_skb(skb);
-}
-
-/*
- * Function irttp_reasseble (self)
- *
- *    Makes a new (continuous) skb of all the fragments in the fragment
- *    queue
- *
- */
-static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self)
-{
-	struct sk_buff *skb, *frag;
-	int n = 0;  /* Fragment index */
-	
-      	ASSERT(self != NULL, return NULL;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;);
-
-	IRDA_DEBUG(2, __FUNCTION__ "(), self->rx_sdu_size=%d\n", 
-		   self->rx_sdu_size);
-
-	skb = dev_alloc_skb(TTP_HEADER + self->rx_sdu_size);
-	if (!skb)
-		return NULL;
-
-	/* 
-	 * Need to reserve space for TTP header in case this skb needs to 
-	 * be requeued in case delivery failes
-	 */
-	skb_reserve(skb, TTP_HEADER);
-	skb_put(skb, self->rx_sdu_size);
-
-	/*
-	 *  Copy all fragments to a new buffer
-	 */
-	while ((frag = skb_dequeue(&self->rx_fragments)) != NULL) {
-		memcpy(skb->data+n, frag->data, frag->len);
-		n += frag->len;
-		
-		dev_kfree_skb(frag);
-	}
-	IRDA_DEBUG(2, __FUNCTION__ "(), frame len=%d\n", n);
-
-	IRDA_DEBUG(2, __FUNCTION__ "(), rx_sdu_size=%d\n", self->rx_sdu_size);
-	ASSERT(n <= self->rx_sdu_size, return NULL;);
-
-	/* Set the new length */
-	skb_trim(skb, n);
-
-	self->rx_sdu_size = 0;
-
-	return skb;
-}
-
-/*
- * Function irttp_fragment_skb (skb)
- *
- *    Fragments a frame and queues all the fragments for transmission
- *
- */
-static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb)
-{
-	struct sk_buff *frag;
-	__u8 *frame;
-
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
-
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
 
 	/*
-	 *  Split frame into a number of segments
+	 * It's not trivial to keep track of how many credits are available
+	 * by incrementing at each packet, because delivery may fail 
+	 * (irttp_do_data_indication() may requeue the frame) and because
+	 * we need to take care of fragmentation.
+	 * We want the other side to send up to initial_credit packets.
+	 * We have some frames in our queues, and we have already allowed it
+	 * to send remote_credit.
+	 * No need to spinlock, write is atomic and self correcting...
+	 * Jean II
 	 */
-	while (skb->len > self->max_seg_size) {
-		IRDA_DEBUG(2, __FUNCTION__  "(), fragmenting ...\n");
-
-		/* Make new segment */
-		frag = dev_alloc_skb(self->max_seg_size+self->max_header_size);
-		if (!frag)
-			return;
-
-		skb_reserve(frag, self->max_header_size);
-
-		/* Copy data from the original skb into this fragment. */
-		memcpy(skb_put(frag, self->max_seg_size), skb->data, 
-		       self->max_seg_size);
-
-		/* Insert TTP header, with the more bit set */
-		frame = skb_push(frag, TTP_HEADER);
-		frame[0] = TTP_MORE;
-		
-		/* Hide the copied data from the original skb */
-		skb_pull(skb, self->max_seg_size);
-
-		/* Queue fragment */
-		skb_queue_tail(&self->tx_queue, frag);
-	}
-	/* Queue what is left of the original skb */
-	IRDA_DEBUG(2, __FUNCTION__  "(), queuing last segment\n");
-	
-	frame = skb_push(skb, TTP_HEADER);
-	frame[0] = 0x00; /* Clear more bit */
-
-	/* Queue fragment */
-	skb_queue_tail(&self->tx_queue, skb);
-}
-
-/*
- * Function irttp_param_max_sdu_size (self, param)
- *
- *    Handle the MaxSduSize parameter in the connect frames, this function
- *    will be called both when this parameter needs to be inserted into, and
- *    extracted from the connect frames
- */
-static int irttp_param_max_sdu_size(void *instance, irda_param_t *param, 
-				    int get)
-{
-	struct tsap_cb *self;
-
-	self = (struct tsap_cb *) instance;
-
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
-
-	if (get)
-		param->pv.i = self->tx_max_sdu_size;
-	else
-		self->tx_max_sdu_size = param->pv.i;
-
-	IRDA_DEBUG(1, __FUNCTION__ "(), MaxSduSize=%d\n", param->pv.i);
-	
-	return 0;
-}
-
-/*
- * Function irttp_todo_expired (data)
- *
- *    Todo timer has expired!
- *
- */
-static void irttp_todo_expired(unsigned long data)
-{
-	struct tsap_cb *self = (struct tsap_cb *) data;
-
-	/* Check that we still exist */
-	if (!self || self->magic != TTP_TSAP_MAGIC)
-		return;
-	
-	irttp_run_rx_queue(self);
-	irttp_run_tx_queue(self);
-		
-	/*  Give avay some credits to peer?  */
-	if ((self->remote_credit < TTP_LOW_THRESHOLD) && 
-	    (self->avail_credit > 0) && (skb_queue_empty(&self->tx_queue)))
-	{
+	self->avail_credit = (self->initial_credit -
+			      (self->remote_credit +
+			       skb_queue_len(&self->rx_queue) +
+			       skb_queue_len(&self->rx_fragments)));
+
+	/* Do we have too much credits to send to peer ? */
+	if ((self->remote_credit <= TTP_RX_MIN_CREDIT) &&
+	    (self->avail_credit > 0)) {
+		/* Send explicit credit frame */
 		irttp_give_credit(self);
+		/* Note : do *NOT* check if tx_queue is non-empty, that
+		 * will produce deadlocks. I repeat : send a credit frame
+		 * even if we have something to send in our Tx queue.
+		 * If we have credits, it means that our Tx queue is blocked.
+		 *
+		 * Let's suppose the peer can't keep up with our Tx. He will
+		 * flow control us by not sending us any credits, and we
+		 * will stop Tx and start accumulating credits here.
+		 * Up to the point where the peer will stop its Tx queue,
+		 * for lack of credits.
+		 * Let's assume the peer application is single threaded.
+		 * It will block on Tx and never consume any Rx buffer.
+		 * Deadlock. Guaranteed. - Jean II
+		 */
 	}
 
-	/* Check if time for disconnect */
-	if (test_bit(0, &self->disconnect_pend)) {
-		/* Check if it's possible to disconnect yet */
-		if (skb_queue_empty(&self->tx_queue)) {
-			/* Make sure disconnect is not pending anymore */
-			clear_bit(0, &self->disconnect_pend);	/* FALSE */
-
-			/* Note : self->disconnect_skb may be NULL */
-			irttp_disconnect_request(self, self->disconnect_skb,
-						 P_NORMAL);
-			self->disconnect_skb = NULL;
-		} else {
-			/* Try again later */
-			irttp_start_todo_timer(self, 1*HZ);
-			
-			/* No reason to try and close now */
-			return;
-		}
-	}
-	
-	/* Check if it's closing time */
-	if (self->close_pend)
-		irttp_close_tsap(self);
-}
-
-/*
- * Function irttp_start_todo_timer (self, timeout)
- *
- *    Start todo timer. 
- *
- */
-static void irttp_start_todo_timer(struct tsap_cb *self, int timeout)
-{
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-
-	del_timer(&self->todo_timer);
-	
-	self->todo_timer.data     = (unsigned long) self;
-	self->todo_timer.function = &irttp_todo_expired;
-	self->todo_timer.expires  = jiffies + timeout;
-
-	add_timer(&self->todo_timer);
+	/* Reset lock */
+	self->rx_queue_lock = 0;
 }
 
 #ifdef CONFIG_PROC_FS
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/parameters.c linux-2.4.21/net/irda/parameters.c
--- linux-2.4.20/net/irda/parameters.c	2001-11-09 22:22:17.000000000 +0000
+++ linux-2.4.21/net/irda/parameters.c	2002-12-18 18:58:03.000000000 +0000
@@ -28,6 +28,7 @@
  *     
  ********************************************************************/
 
+#include <linux/types.h>
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/socket.c linux-2.4.21/net/socket.c
--- linux-2.4.20/net/socket.c	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/socket.c	2002-12-18 18:58:06.000000000 +0000
@@ -436,11 +436,11 @@
 	struct inode * inode;
 	struct socket * sock;
 
-	inode = get_empty_inode();
+	inode = new_inode(sock_mnt->mnt_sb);
 	if (!inode)
 		return NULL;
 
-	inode->i_sb = sock_mnt->mnt_sb;
+	inode->i_dev = NODEV;
 	sock = socki_lookup(inode);
 
 	inode->i_mode = S_IFSOCK|S_IRWXUGO;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/sunrpc/clnt.c linux-2.4.21/net/sunrpc/clnt.c
--- linux-2.4.20/net/sunrpc/clnt.c	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/sunrpc/clnt.c	2002-12-18 18:58:07.000000000 +0000
@@ -43,6 +43,7 @@
 static DECLARE_WAIT_QUEUE_HEAD(destroy_wait);
 
 
+static void	call_start(struct rpc_task *task);
 static void	call_reserve(struct rpc_task *task);
 static void	call_reserveresult(struct rpc_task *task);
 static void	call_allocate(struct rpc_task *task);
@@ -326,13 +327,9 @@
 		rpcauth_bindcred(task);
 
 	if (task->tk_status == 0)
-		task->tk_action = call_reserve;
+		task->tk_action = call_start;
 	else
 		task->tk_action = NULL;
-
-	/* Increment call count */
-	if (task->tk_msg.rpc_proc < task->tk_client->cl_maxproc)
-		rpcproc_count(task->tk_client, task->tk_msg.rpc_proc)++;
 }
 
 void
@@ -359,26 +356,48 @@
 	if (RPC_ASSASSINATED(task))
 		return;
 
-	task->tk_action = call_reserve;
-	rpcproc_count(task->tk_client, task->tk_msg.rpc_proc)++;
+	task->tk_action = call_start;
 }
 
 /*
- * 1.	Reserve an RPC call slot
+ * 0.  Initial state
+ *
+ *     Other FSM states can be visited zero or more times, but
+ *     this state is visited exactly once for each RPC.
  */
 static void
-call_reserve(struct rpc_task *task)
+call_start(struct rpc_task *task)
 {
 	struct rpc_clnt	*clnt = task->tk_client;
 
 	if (task->tk_msg.rpc_proc > clnt->cl_maxproc) {
-		printk(KERN_WARNING "%s (vers %d): bad procedure number %d\n",
-			clnt->cl_protname, clnt->cl_vers, task->tk_msg.rpc_proc);
+		printk(KERN_ERR "%s (vers %d): bad procedure number %d\n",
+				clnt->cl_protname, clnt->cl_vers,
+				task->tk_msg.rpc_proc);
 		rpc_exit(task, -EIO);
 		return;
 	}
 
+	dprintk("RPC: %4d call_start %s%d proc %d (%s)\n", task->tk_pid,
+		clnt->cl_protname, clnt->cl_vers, task->tk_msg.rpc_proc,
+		(RPC_IS_ASYNC(task) ? "async" : "sync"));
+
+	/* Increment call count */
+	rpcproc_count(clnt, task->tk_msg.rpc_proc)++;
+	clnt->cl_stats->rpccnt++;
+	task->tk_action = call_reserve;
+}
+
+/*
+ * 1.	Reserve an RPC call slot
+ */
+static void
+call_reserve(struct rpc_task *task)
+{
+	struct rpc_clnt	*clnt = task->tk_client;
+
 	dprintk("RPC: %4d call_reserve\n", task->tk_pid);
+
 	if (!rpcauth_uptodatecred(task)) {
 		task->tk_action = call_refresh;
 		return;
@@ -387,7 +406,6 @@
 	task->tk_status  = 0;
 	task->tk_action  = call_reserveresult;
 	task->tk_timeout = clnt->cl_timeout.to_resrvval;
-	clnt->cl_stats->rpccnt++;
 	xprt_reserve(task);
 }
 
@@ -645,7 +663,6 @@
 	case -ENOMEM:
 	case -EAGAIN:
 		task->tk_action = call_transmit;
-		clnt->cl_stats->rpcretrans++;
 		break;
 	default:
 		if (clnt->cl_chatty)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/sunrpc/svc.c linux-2.4.21/net/sunrpc/svc.c
--- linux-2.4.20/net/sunrpc/svc.c	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/sunrpc/svc.c	2002-12-18 18:58:11.000000000 +0000
@@ -333,8 +333,12 @@
 		}
 	} else {
 		dprintk("svc: calling dispatcher\n");
-		if (!versp->vs_dispatch(rqstp, statp))
+		if (!versp->vs_dispatch(rqstp, statp)) {
+			/* Release reply info */
+			if (procp->pc_release)
+				procp->pc_release(rqstp, NULL, rqstp->rq_resp);
 			goto dropit;
+		}
 	}
 
 	/* Check RPC status result */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/sunrpc/xprt.c linux-2.4.21/net/sunrpc/xprt.c
--- linux-2.4.20/net/sunrpc/xprt.c	2002-12-18 18:27:10.000000000 +0000
+++ linux-2.4.21/net/sunrpc/xprt.c	2002-12-18 18:58:03.000000000 +0000
@@ -1416,6 +1416,8 @@
 		sk->no_check = UDP_CSUM_NORCV;
 		xprt_set_connected(xprt);
 	} else {
+		struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+		tp->nonagle = 1;	/* disable Nagle's algorithm */
 		sk->data_ready = tcp_data_ready;
 		sk->state_change = tcp_state_change;
 		xprt_clear_connected(xprt);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/scripts/Configure linux-2.4.21/scripts/Configure
--- linux-2.4.20/scripts/Configure	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.21/scripts/Configure	2002-12-18 18:58:04.000000000 +0000
@@ -343,24 +343,14 @@
 #
 # int processes an integer argument with optional limits
 #
-#	int question define default [min max]
+#	int question define default
 #
 function int () {
 	old=$(eval echo "\${$2}")
 	def=${old:-$3}
-	if [ $# -gt 3 ]; then
-	  min=$4
-	else
-	  min=-10000000    # !!
-	fi
-	if [ $# -gt 4 ]; then
-	  max=$5
-	else
-	  max=10000000     # !!
-	fi
 	while :; do
 	  readln "$1 ($2) [$def] " "$def" "$old"
-	  if expr \( \( $ans + 0 \) \>= $min \) \& \( $ans \<= $max \) >/dev/null 2>&1 ; then
+	  if expr "$ans" : '[0-9]*$' > /dev/null; then
             define_int "$2" "$ans"
 	    break
           else
